Refactor: workspace-browse page 리팩토링
This commit is contained in:
parent
331a110df1
commit
cf35ca5b67
@ -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();
|
||||||
|
@ -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 (
|
||||||
<>
|
<>
|
||||||
|
@ -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,102 +15,111 @@ 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 gap-8 px-6 py-4">
|
||||||
<div className="flex h-full w-full flex-col items-center justify-center">
|
<HeaderSection
|
||||||
<div className="flex flex-col items-center">
|
workspaceName={workspaceData?.title ?? `Workspace-${workspaceId}`}
|
||||||
<Smile
|
onCreateProject={handleCreateProject}
|
||||||
size={48}
|
/>
|
||||||
className="mb-2 text-gray-300"
|
{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>
|
</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 (
|
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">
|
<Smile
|
||||||
<Smile
|
size={48}
|
||||||
size={48}
|
className="mb-2 text-gray-300"
|
||||||
className="mb-2 text-gray-300"
|
/>
|
||||||
/>
|
<div className="body text-gray-400">작업할 프로젝트가 없습니다.</div>
|
||||||
<div className="body text-gray-400">
|
|
||||||
{!workspaceId ? '작업할 워크스페이스를 선택하세요.' : '작업할 프로젝트가 없습니다.'}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full w-full flex-col gap-8 px-6 py-4">
|
<div className="flex flex-wrap gap-6">
|
||||||
<div className="flex items-center justify-center">
|
{projects.map((project: ProjectResponse) => (
|
||||||
<h1 className="small-title flex grow">{`Workspace-${workspaceId}`}</h1>
|
<ProjectCard
|
||||||
<div className="flex flex-col">
|
key={project.id}
|
||||||
<div className="flex gap-3">
|
title={project.title}
|
||||||
<ProjectCreateModal
|
description={project.projectType}
|
||||||
buttonClass="mt-4 flex items-center gap-2"
|
onClick={() => {
|
||||||
onSubmit={handleCreateProject}
|
navigate(`${webPath.workspace()}/${workspaceId}/project/${project.id}`);
|
||||||
/>
|
}}
|
||||||
</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>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user