Refactor: workspace-browse page 리팩토링

This commit is contained in:
정현조 2024-09-18 17:01:09 +09:00
parent 331a110df1
commit cf35ca5b67
3 changed files with 105 additions and 112 deletions

View File

@ -3,9 +3,10 @@ import ProjectCreateForm, { ProjectCreateFormValues } from './ProjectCreateForm'
import { Dialog, DialogContent, DialogHeader, DialogTrigger } from '../ui/dialogCustom'; import { Dialog, DialogContent, DialogHeader, DialogTrigger } from '../ui/dialogCustom';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Plus } from 'lucide-react'; import { Plus } from 'lucide-react';
import { ProjectRequest } from '@/types';
interface ProjectCreateModalProps { interface ProjectCreateModalProps {
onSubmit: (data: { title: string; labelType: 'classification' | 'detection' | 'segmentation' }) => void; onSubmit: (data: ProjectRequest) => void;
buttonClass?: string; buttonClass?: string;
} }
@ -17,7 +18,7 @@ export default function ProjectCreateModal({ onSubmit, buttonClass = '' }: Proje
const formatLabelType = ( const formatLabelType = (
labelType: 'Classification' | 'Detection' | 'Segmentation' labelType: 'Classification' | 'Detection' | 'Segmentation'
): 'classification' | 'detection' | 'segmentation' => { ): ProjectRequest['projectType'] => {
switch (labelType) { switch (labelType) {
case 'Classification': case 'Classification':
return 'classification'; return 'classification';
@ -47,9 +48,9 @@ export default function ProjectCreateModal({ onSubmit, buttonClass = '' }: Proje
<DialogHeader title="새 프로젝트" /> <DialogHeader title="새 프로젝트" />
<ProjectCreateForm <ProjectCreateForm
onSubmit={(data: ProjectCreateFormValues) => { onSubmit={(data: ProjectCreateFormValues) => {
const formattedData = { const formattedData: ProjectRequest = {
title: data.projectName, title: data.projectName,
labelType: formatLabelType(data.labelType), projectType: formatLabelType(data.labelType),
}; };
onSubmit(formattedData); onSubmit(formattedData);
handleClose(); handleClose();

View File

@ -1,10 +1,11 @@
import { Suspense, useEffect } from 'react'; import { useEffect, Suspense } from 'react';
import { NavLink, Outlet, useNavigate } from 'react-router-dom'; import { NavLink, Outlet, useNavigate } from 'react-router-dom';
import Header from '../Header'; import Header from '../Header';
import useAuthStore from '@/stores/useAuthStore'; import useAuthStore from '@/stores/useAuthStore';
import WorkSpaceCreateModal from '../WorkSpaceCreateModal'; import WorkSpaceCreateModal from '../WorkSpaceCreateModal';
import { WorkspaceRequest, WorkspaceResponse } from '@/types'; import { WorkspaceRequest, WorkspaceResponse } from '@/types';
import useWorkspaceListQuery from '@/queries/useWorkspaceListQuery'; import useWorkspaceListQuery from '@/queries/useWorkspaceListQuery';
import { useCreateWorkspace } from '@/hooks/useWorkspaceHooks';
export default function WorkspaceBrowseLayout() { export default function WorkspaceBrowseLayout() {
const { profile, isLoggedIn } = useAuthStore(); const { profile, isLoggedIn } = useAuthStore();
@ -12,42 +13,22 @@ export default function WorkspaceBrowseLayout() {
const navigate = useNavigate(); const navigate = useNavigate();
useEffect(() => { useEffect(() => {
if (!isLoggedIn || !memberId) { if (!isLoggedIn || memberId == 0) {
console.error('로그인되지 않았거나 유효한 멤버 ID가 없습니다.');
navigate('/'); navigate('/');
} }
}, [isLoggedIn, memberId, navigate]); }, [isLoggedIn, memberId, navigate]);
const { data: workspacesResponse, isLoading, isError } = useWorkspaceListQuery(memberId ?? 0); const { data: workspacesResponse } = useWorkspaceListQuery(memberId ?? 0);
const createWorkspace = useCreateWorkspace();
const workspaces = workspacesResponse?.workspaceResponses ?? [];
// const createWorkspace = useCreateWorkspace();
const handleCreateWorkspace = (data: WorkspaceRequest) => { const handleCreateWorkspace = (data: WorkspaceRequest) => {
if (!memberId) return; createWorkspace.mutate({
console.log(data); memberId,
// createWorkspace.mutate( data,
// { memberId, data }, });
// {
// onSuccess: () => {
// console.log('워크스페이스가 성공적으로 생성되었습니다.');
// queryClient.invalidateQueries({ queryKey: ['workspaces'] });
// },
// onError: (error: AxiosError<CustomError>) => {
// console.error('워크스페이스 생성 실패:', error.message);
// },
// }
// );
}; };
if (isLoading) { const workspaces = workspacesResponse?.workspaceResponses ?? [];
return <p>Loading workspaces...</p>;
}
if (isError) {
return <p>Error loading workspaces. Please try again later.</p>;
}
return ( return (
<> <>

View File

@ -3,8 +3,10 @@ import ProjectCard from '@/components/ProjectCard';
import { Smile } from 'lucide-react'; import { Smile } from 'lucide-react';
import ProjectCreateModal from '../components/ProjectCreateModal'; import ProjectCreateModal from '../components/ProjectCreateModal';
import useAuthStore from '@/stores/useAuthStore'; import useAuthStore from '@/stores/useAuthStore';
import { ProjectResponse } from '@/types'; import { ProjectResponse, ProjectRequest } from '@/types';
import useProjectListQuery from '@/queries/useProjectListQuery'; import useProjectListQuery from '@/queries/useProjectListQuery';
import useWorkspaceQuery from '@/queries/useWorkspaceQuery';
import { useCreateProject } from '@/hooks/useProjectHooks';
import { webPath } from '@/router'; import { webPath } from '@/router';
export default function WorkspaceBrowseDetail() { export default function WorkspaceBrowseDetail() {
@ -13,50 +15,63 @@ export default function WorkspaceBrowseDetail() {
const { profile } = useAuthStore(); const { profile } = useAuthStore();
const memberId = profile?.id ?? 0; const memberId = profile?.id ?? 0;
const navigate = useNavigate(); const navigate = useNavigate();
// const createProject = useCreateProject();
const { data: workspaceData } = useWorkspaceQuery(workspaceId, memberId);
const { data: projectsResponse, isError } = useProjectListQuery(workspaceId, memberId); const { data: projectsResponse, isError } = useProjectListQuery(workspaceId, memberId);
const createProject = useCreateProject();
const handleCreateProject = (data: { title: string; labelType: 'classification' | 'detection' | 'segmentation' }) => { const handleCreateProject = (data: ProjectRequest) => {
console.log(data); createProject.mutate({
// createProject.mutate( workspaceId,
// { memberId,
// workspaceId: workspaceId, data,
// memberId, });
// data: { title: data.title, projectType: data.labelType },
// },
// {
// onSuccess: () => {
// console.log('프로젝트가 성공적으로 생성되었습니다.');
// refetch();
// },
// onError: (error) => {
// console.error('프로젝트 생성 실패:', error);
// const errorMessage = error?.response?.data?.message || error.message || '알 수 없는 오류';
// console.error('프로젝트 생성 실패:', errorMessage);
// },
// }
// );
}; };
// TODO: 반환 형식 반영 projectsResponse?.workspaceResponses => projectResponse
const projects: ProjectResponse[] = projectsResponse?.workspaceResponses ?? []; const projects: ProjectResponse[] = projectsResponse?.workspaceResponses ?? [];
if (isNaN(workspaceId)) {
return ( return (
<div className="flex h-full w-full flex-col items-center justify-center"> <div className="flex h-full w-full flex-col gap-8 px-6 py-4">
<div className="flex flex-col items-center"> <HeaderSection
<Smile workspaceName={workspaceData?.title ?? `Workspace-${workspaceId}`}
size={48} onCreateProject={handleCreateProject}
className="mb-2 text-gray-300"
/> />
<div className="body text-gray-400"> </div> {isNaN(workspaceId) || isError || !workspaceId ? (
<EmptyStateMessage workspaceId={workspaceId} />
) : (
<ProjectList
projects={projects}
workspaceId={workspaceId}
navigate={navigate}
/>
)}
</div>
);
}
function HeaderSection({
workspaceName,
onCreateProject,
}: {
workspaceName: string;
onCreateProject: (data: ProjectRequest) => void;
}) {
return (
<div className="flex items-center justify-center">
<h1 className="small-title flex grow">{workspaceName}</h1>
<div className="flex flex-col">
<div className="flex gap-3">
<ProjectCreateModal
buttonClass="mt-4 flex items-center gap-2"
onSubmit={onCreateProject}
/>
</div>
</div> </div>
</div> </div>
); );
} }
if (isError || !workspaceId) { function EmptyStateMessage({ workspaceId }: { workspaceId: number }) {
return ( return (
<div className="flex h-full w-full flex-col items-center justify-center"> <div className="flex h-full w-full flex-col items-center justify-center">
<div className="flex flex-col items-center"> <div className="flex flex-col items-center">
@ -72,20 +87,28 @@ export default function WorkspaceBrowseDetail() {
); );
} }
function ProjectList({
projects,
workspaceId,
navigate,
}: {
projects: ProjectResponse[];
workspaceId: number;
navigate: ReturnType<typeof useNavigate>;
}) {
if (projects.length === 0) {
return ( return (
<div className="flex h-full w-full flex-col gap-8 px-6 py-4"> <div className="flex h-full w-full flex-col items-center justify-center">
<div className="flex items-center justify-center"> <Smile
<h1 className="small-title flex grow">{`Workspace-${workspaceId}`}</h1> size={48}
<div className="flex flex-col"> className="mb-2 text-gray-300"
<div className="flex gap-3">
<ProjectCreateModal
buttonClass="mt-4 flex items-center gap-2"
onSubmit={handleCreateProject}
/> />
<div className="body text-gray-400"> .</div>
</div> </div>
</div> );
</div> }
{projects.length > 0 ? (
return (
<div className="flex flex-wrap gap-6"> <div className="flex flex-wrap gap-6">
{projects.map((project: ProjectResponse) => ( {projects.map((project: ProjectResponse) => (
<ProjectCard <ProjectCard
@ -98,17 +121,5 @@ export default function WorkspaceBrowseDetail() {
/> />
))} ))}
</div> </div>
) : (
<div className="flex h-full w-full flex-col items-center justify-center">
<div className="flex flex-col items-center">
<Smile
size={48}
className="mb-2 text-gray-300"
/>
<div className="body text-gray-400"> .</div>
</div>
</div>
)}
</div>
); );
} }