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 { Button } from '@/components/ui/button';
import { Plus } from 'lucide-react';
import { ProjectRequest } from '@/types';
interface ProjectCreateModalProps {
onSubmit: (data: { title: string; labelType: 'classification' | 'detection' | 'segmentation' }) => void;
onSubmit: (data: ProjectRequest) => void;
buttonClass?: string;
}
@ -17,7 +18,7 @@ export default function ProjectCreateModal({ onSubmit, buttonClass = '' }: Proje
const formatLabelType = (
labelType: 'Classification' | 'Detection' | 'Segmentation'
): 'classification' | 'detection' | 'segmentation' => {
): ProjectRequest['projectType'] => {
switch (labelType) {
case 'Classification':
return 'classification';
@ -47,9 +48,9 @@ export default function ProjectCreateModal({ onSubmit, buttonClass = '' }: Proje
<DialogHeader title="새 프로젝트" />
<ProjectCreateForm
onSubmit={(data: ProjectCreateFormValues) => {
const formattedData = {
const formattedData: ProjectRequest = {
title: data.projectName,
labelType: formatLabelType(data.labelType),
projectType: formatLabelType(data.labelType),
};
onSubmit(formattedData);
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 Header from '../Header';
import useAuthStore from '@/stores/useAuthStore';
import WorkSpaceCreateModal from '../WorkSpaceCreateModal';
import { WorkspaceRequest, WorkspaceResponse } from '@/types';
import useWorkspaceListQuery from '@/queries/useWorkspaceListQuery';
import { useCreateWorkspace } from '@/hooks/useWorkspaceHooks';
export default function WorkspaceBrowseLayout() {
const { profile, isLoggedIn } = useAuthStore();
@ -12,42 +13,22 @@ export default function WorkspaceBrowseLayout() {
const navigate = useNavigate();
useEffect(() => {
if (!isLoggedIn || !memberId) {
console.error('로그인되지 않았거나 유효한 멤버 ID가 없습니다.');
if (!isLoggedIn || memberId == 0) {
navigate('/');
}
}, [isLoggedIn, memberId, navigate]);
const { data: workspacesResponse, isLoading, isError } = useWorkspaceListQuery(memberId ?? 0);
const workspaces = workspacesResponse?.workspaceResponses ?? [];
// const createWorkspace = useCreateWorkspace();
const { data: workspacesResponse } = useWorkspaceListQuery(memberId ?? 0);
const createWorkspace = useCreateWorkspace();
const handleCreateWorkspace = (data: WorkspaceRequest) => {
if (!memberId) return;
console.log(data);
// createWorkspace.mutate(
// { memberId, data },
// {
// onSuccess: () => {
// console.log('워크스페이스가 성공적으로 생성되었습니다.');
// queryClient.invalidateQueries({ queryKey: ['workspaces'] });
// },
// onError: (error: AxiosError<CustomError>) => {
// console.error('워크스페이스 생성 실패:', error.message);
// },
// }
// );
createWorkspace.mutate({
memberId,
data,
});
};
if (isLoading) {
return <p>Loading workspaces...</p>;
}
if (isError) {
return <p>Error loading workspaces. Please try again later.</p>;
}
const workspaces = workspacesResponse?.workspaceResponses ?? [];
return (
<>

View File

@ -3,8 +3,10 @@ import ProjectCard from '@/components/ProjectCard';
import { Smile } from 'lucide-react';
import ProjectCreateModal from '../components/ProjectCreateModal';
import useAuthStore from '@/stores/useAuthStore';
import { ProjectResponse } from '@/types';
import { ProjectResponse, ProjectRequest } from '@/types';
import useProjectListQuery from '@/queries/useProjectListQuery';
import useWorkspaceQuery from '@/queries/useWorkspaceQuery';
import { useCreateProject } from '@/hooks/useProjectHooks';
import { webPath } from '@/router';
export default function WorkspaceBrowseDetail() {
@ -13,102 +15,111 @@ export default function WorkspaceBrowseDetail() {
const { profile } = useAuthStore();
const memberId = profile?.id ?? 0;
const navigate = useNavigate();
// const createProject = useCreateProject();
const { data: workspaceData } = useWorkspaceQuery(workspaceId, memberId);
const { data: projectsResponse, isError } = useProjectListQuery(workspaceId, memberId);
const createProject = useCreateProject();
const handleCreateProject = (data: { title: string; labelType: 'classification' | 'detection' | 'segmentation' }) => {
console.log(data);
// createProject.mutate(
// {
// workspaceId: workspaceId,
// 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);
// },
// }
// );
const handleCreateProject = (data: ProjectRequest) => {
createProject.mutate({
workspaceId,
memberId,
data,
});
};
// TODO: 반환 형식 반영 projectsResponse?.workspaceResponses => projectResponse
const projects: ProjectResponse[] = projectsResponse?.workspaceResponses ?? [];
if (isNaN(workspaceId)) {
return (
<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"
return (
<div className="flex h-full w-full flex-col gap-8 px-6 py-4">
<HeaderSection
workspaceName={workspaceData?.title ?? `Workspace-${workspaceId}`}
onCreateProject={handleCreateProject}
/>
{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 className="body text-gray-400"> </div>
</div>
</div>
);
}
</div>
);
}
if (isError || !workspaceId) {
function EmptyStateMessage({ workspaceId }: { workspaceId: number }) {
return (
<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">
{!workspaceId ? '작업할 워크스페이스를 선택하세요.' : '작업할 프로젝트가 없습니다.'}
</div>
</div>
</div>
);
}
function ProjectList({
projects,
workspaceId,
navigate,
}: {
projects: ProjectResponse[];
workspaceId: number;
navigate: ReturnType<typeof useNavigate>;
}) {
if (projects.length === 0) {
return (
<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">
{!workspaceId ? '작업할 워크스페이스를 선택하세요.' : '작업할 프로젝트가 없습니다.'}
</div>
</div>
<Smile
size={48}
className="mb-2 text-gray-300"
/>
<div className="body text-gray-400"> .</div>
</div>
);
}
return (
<div className="flex h-full w-full flex-col gap-8 px-6 py-4">
<div className="flex items-center justify-center">
<h1 className="small-title flex grow">{`Workspace-${workspaceId}`}</h1>
<div className="flex flex-col">
<div className="flex gap-3">
<ProjectCreateModal
buttonClass="mt-4 flex items-center gap-2"
onSubmit={handleCreateProject}
/>
</div>
</div>
</div>
{projects.length > 0 ? (
<div className="flex flex-wrap gap-6">
{projects.map((project: ProjectResponse) => (
<ProjectCard
key={project.id}
title={project.title}
description={project.projectType}
onClick={() => {
navigate(`${webPath.workspace()}/${workspaceId}/project/${project.id}`);
}}
/>
))}
</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 className="flex flex-wrap gap-6">
{projects.map((project: ProjectResponse) => (
<ProjectCard
key={project.id}
title={project.title}
description={project.projectType}
onClick={() => {
navigate(`${webPath.workspace()}/${workspaceId}/project/${project.id}`);
}}
/>
))}
</div>
);
}