Merge branch 'fe/refactor/improve-design' into 'fe/develop'

Refactor: 리뷰 탭 분리

See merge request s11-s-project/S11P21S002!269
This commit is contained in:
정현조 2024-10-02 20:20:06 +09:00
commit b82000562a
15 changed files with 122 additions and 71 deletions

View File

@ -6,10 +6,6 @@ export default function AdminMenuSidebar() {
const { workspaceId, projectId } = useParams<{ workspaceId: string; projectId?: string }>();
const menuItems = [
{
label: '리뷰',
path: projectId ? `/admin/${workspaceId}/reviews/${projectId}` : `/admin/${workspaceId}/reviews`,
},
{
label: '멤버 관리',
path: projectId ? `/admin/${workspaceId}/members/${projectId}` : `/admin/${workspaceId}/members`,

View File

@ -2,11 +2,8 @@ import { ResizablePanel, ResizableHandle } from '../ui/resizable';
import { Link, useLocation, useParams } from 'react-router-dom';
import { SquarePen } from 'lucide-react';
import useProjectListQuery from '@/queries/projects/useProjectListQuery';
import useCreateProjectQuery from '@/queries/projects/useCreateProjectQuery';
import useWorkspaceQuery from '@/queries/workspaces/useWorkspaceQuery';
import { ProjectRequest } from '@/types';
import useAuthStore from '@/stores/useAuthStore';
import ProjectCreateModal from '../ProjectCreateModal';
import { cn } from '@/lib/utils';
export default function AdminProjectSidebar(): JSX.Element {
@ -20,20 +17,7 @@ export default function AdminProjectSidebar(): JSX.Element {
const { data: projects } = useProjectListQuery(Number(workspaceId), memberId);
const createProject = useCreateProjectQuery();
const handleCreateProject = (data: ProjectRequest) => {
createProject.mutate({
workspaceId: Number(workspaceId),
memberId,
data,
});
};
const getNewPath = (newProjectId: string) => {
if (location.pathname.includes('reviews')) {
return `/admin/${workspaceId}/reviews/${newProjectId}`;
}
if (location.pathname.includes('members')) {
return `/admin/${workspaceId}/members/${newProjectId}`;
}
@ -64,10 +48,6 @@ export default function AdminProjectSidebar(): JSX.Element {
<button className="p-2">
<SquarePen size={16} />
</button>
<ProjectCreateModal
buttonClass="caption"
onSubmit={handleCreateProject}
/>
</header>
<div className="flex flex-col gap-2 p-4">
{projects.map((project) => {

View File

@ -1,9 +1,15 @@
import { cn } from '@/lib/utils';
import { Link, useParams } from 'react-router-dom';
import { Link, useLocation, useParams } from 'react-router-dom';
import useAuthStore from '@/stores/useAuthStore';
import useWorkspaceListQuery from '@/queries/workspaces/useWorkspaceListQuery';
export default function WorkspaceNavigation() {
const location = useLocation();
const isBrowsePage = location.pathname.startsWith('/browse');
const isWorkspacePage = location.pathname.startsWith('/workspace');
const isReviewPage = location.pathname.startsWith('/review');
const isAdminPage = location.pathname.startsWith('/admin');
const { workspaceId } = useParams<{ workspaceId: string }>();
const profile = useAuthStore((state) => state.profile);
const memberId = profile?.id;
@ -21,7 +27,7 @@ export default function WorkspaceNavigation() {
<nav className="hidden items-center gap-5 md:flex">
<Link
to={activeWorkspaceId ? `/browse/${activeWorkspaceId}` : '/browse'}
className={cn('text-color-text-default-default', 'font-body-strong', 'text-sm sm:text-base md:text-lg')}
className={cn('', isBrowsePage ? 'body-strong' : 'body')}
>
workspace
</Link>
@ -29,13 +35,19 @@ export default function WorkspaceNavigation() {
<>
<Link
to={`/workspace/${activeWorkspaceId}`}
className={cn('text-color-text-default-default', 'font-body', 'text-sm sm:text-base md:text-lg')}
className={cn('', isWorkspacePage ? 'body-strong' : 'body')}
>
labeling
</Link>
<Link
to={`/review/${activeWorkspaceId}`}
className={cn('', isReviewPage ? 'body-strong' : 'body')}
>
review
</Link>
<Link
to={`/admin/${activeWorkspaceId}`}
className={cn('text-color-text-default-default', 'font-body', 'text-sm sm:text-base md:text-lg')}
className={cn('', isAdminPage ? 'body-strong' : 'body')}
>
admin
</Link>

View File

@ -2,7 +2,6 @@ import React from 'react';
import MemberAddForm, { MemberAddFormValues } from './MemberAddForm';
import { Dialog, DialogContent, DialogHeader, DialogTrigger } from '../ui/dialogCustom';
import { Button } from '@/components/ui/button';
import { Plus } from 'lucide-react';
import useAddProjectMemberQuery from '@/queries/projects/useAddProjectMemberQuery';
import { ProjectMemberRequest } from '@/types';
@ -42,12 +41,11 @@ export default function MemberAddModal({ projectId, buttonClass = '' }: MemberAd
className={`${buttonClass}`}
onClick={handleOpen}
>
<Plus size={16} />
<span> </span>
<span> </span>
</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader title="새 멤버 초대" />
<DialogHeader title="프로젝트에 새 멤버 초대" />
<MemberAddForm onSubmit={handleMemberAdd} />
</DialogContent>
</Dialog>

View File

@ -0,0 +1,57 @@
import { Link, Outlet, useParams } from 'react-router-dom';
import Header from '../Header';
import useAuthStore from '@/stores/useAuthStore';
import useWorkspaceQuery from '@/queries/workspaces/useWorkspaceQuery';
import useProjectListQuery from '@/queries/projects/useProjectListQuery';
import { cn } from '@/lib/utils';
import { ProjectResponse } from '@/types';
export default function ReviewLayout() {
const { workspaceId, projectId } = useParams<{ workspaceId: string; projectId?: string }>();
const profile = useAuthStore((state) => state.profile);
const memberId = profile?.id || 0;
const { data: workspaceData } = useWorkspaceQuery(Number(workspaceId), memberId);
const workspaceTitle = workspaceData?.title || `Workspace-${workspaceId}`;
const { data: projects } = useProjectListQuery(Number(workspaceId), memberId);
return (
<>
<Header className="fixed left-0 top-0 w-full" />
<div className="flex min-h-screen flex-col justify-between">
<div className="mt-16 flex flex-1">
<div className="flex w-[280px] flex-col border-r border-gray-200 bg-gray-100 p-2">
<div className="flex items-center justify-center gap-5 p-2">
<Link
to={`/review/${workspaceId}`}
className="heading w-full overflow-hidden text-ellipsis whitespace-nowrap"
>
{workspaceTitle}
</Link>
</div>
{projects.map((project: ProjectResponse) => (
<Link
key={project.id}
to={`/review/${workspaceId}/${project.id}`}
className={cn(
'cursor-pointer rounded-lg p-3 hover:bg-gray-200',
projectId === String(project.id) ? 'body-strong bg-gray-300' : 'body'
)}
>
{project.title}
</Link>
))}
</div>
<div className="flex w-[calc(100%-280px)] flex-col gap-24">
<main className="h-full grow overflow-y-auto">
<Outlet />
</main>
</div>
</div>
</div>
</>
);
}

View File

@ -42,7 +42,7 @@ export default function ReviewItem({
return (
<Link
to={`/admin/${workspaceId}/reviews/${projectId}/${reviewId}`}
to={`/review/${workspaceId}/${projectId}/${reviewId}`}
className="block hover:bg-gray-100"
>
<div className="flex h-[100px] w-full items-center justify-between border-b-[0.67px] border-[#ececef] bg-[#fbfafd] p-4">

View File

@ -6,6 +6,7 @@ import WorkSpaceCreateModal from '../WorkSpaceCreateModal';
import { WorkspaceRequest, WorkspaceResponse } from '@/types';
import useWorkspaceListQuery from '@/queries/workspaces/useWorkspaceListQuery';
import useCreateWorkspaceQuery from '@/queries/workspaces/useCreateWorkspaceQuery';
import { cn } from '@/lib/utils';
export default function WorkspaceBrowseLayout() {
const { profile } = useAuthStore();
@ -33,19 +34,22 @@ export default function WorkspaceBrowseLayout() {
return (
<>
<Header className="fixed left-0 top-0 w-full" />
<div className="flex min-h-screen flex-col justify-between">
<div className="mt-16 flex flex-1">
<div className="flex w-[280px] flex-col gap-4 border-r border-gray-200 bg-gray-100 px-6 py-4">
<div className="flex items-center justify-center gap-5">
<h1 className="heading mr-2.5 w-full"> </h1>
<div className="flex w-[280px] flex-col border-r border-gray-200 bg-gray-100 p-2">
<div className="flex items-center justify-center gap-5 p-2">
<h1 className="heading mr-2.5 w-full overflow-hidden text-ellipsis whitespace-nowrap"> </h1>
<WorkSpaceCreateModal onSubmit={handleCreateWorkspace} />
</div>
{workspaces.length > 0 ? (
workspaces.map((workspace: WorkspaceResponse) => (
<NavLink
to={`/browse/${workspace.id}`}
key={workspace.id}
className={({ isActive }) => (isActive ? 'body-strong' : 'body') + ' cursor-pointer'}
to={`/browse/${workspace.id}`}
className={({ isActive }) =>
cn('cursor-pointer rounded-lg p-3 hover:bg-gray-200', isActive ? 'body-strong bg-gray-300' : 'body')
}
>
{workspace.title}
</NavLink>

View File

@ -2,7 +2,6 @@ import React from 'react';
import MemberAddForm, { MemberAddFormValues } from './MemberAddForm';
import { Dialog, DialogContent, DialogHeader, DialogTrigger } from '../ui/dialogCustom';
import { Button } from '@/components/ui/button';
import { Plus } from 'lucide-react';
import useAddWorkspaceMemberQuery from '@/queries/workspaces/useAddWorkspaceMemberQuery';
interface WorkspaceMemberAddModalProps {
@ -42,12 +41,11 @@ export default function WorkspaceMemberAddModal({
className={`${buttonClass}`}
onClick={handleOpen}
>
<Plus size={16} />
<span> </span>
<span> </span>
</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader title="워크스페이스 멤버 초대" />
<DialogHeader title="워크스페이스에 새 멤버 초대" />
<MemberAddForm onSubmit={handleSubmit} />
</DialogContent>
</Dialog>

View File

@ -39,7 +39,7 @@ export default function useReviewRequest() {
},
{
onSuccess: () => {
navigate(`/admin/${workspaceId}/reviews`);
navigate(`/review/${workspaceId}`);
},
}
);

View File

@ -7,7 +7,7 @@ export default function AdminIndex() {
useEffect(() => {
if (workspaceId) {
navigate(`/admin/${workspaceId}/reviews`);
navigate(`/admin/${workspaceId}/members`);
}
}, [navigate, workspaceId]);

View File

@ -63,12 +63,13 @@ export default function ProjectReviewList() {
<header className="sticky top-0 z-10 flex h-[57px] items-center gap-1 border-b bg-white px-4">
<h1 className="text-xl font-semibold"> </h1>
<Link
to={`/admin/${workspaceId}/reviews/request`}
to={`/review/${workspaceId}/request`}
className="ml-auto"
>
<Button variant="blue"> </Button>
</Link>
</header>
<ReviewList
key={`${sortValue}-${activeTab}`}
reviews={projectReviews}

View File

@ -153,7 +153,7 @@ export default function ReviewDetail(): JSX.Element {
</div>
<div className="mt-6 flex justify-end gap-2">
<Link to={`/admin/${workspaceId}/reviews`}>
<Link to={`/review/${workspaceId}`}>
<Button variant="black"> </Button>
</Link>
{isAdminOrManager && reviewDetail.reviewStatus !== 'APPROVED' && reviewDetail.reviewStatus !== 'REJECTED' && (

View File

@ -28,7 +28,7 @@ export default function ReviewRequest(): JSX.Element {
reviewData,
},
{
onSuccess: () => navigate(`/admin/${workspaceId}/reviews`),
onSuccess: () => navigate(`/review/${workspaceId}`),
}
);
};

View File

@ -63,7 +63,7 @@ export default function WorkspaceReviewList() {
<header className="sticky top-0 z-10 flex h-[57px] items-center gap-1 border-b bg-white px-4">
<h1 className="text-xl font-semibold"> </h1>
<Link
to={`/admin/${workspaceId}/reviews/request`}
to={`/review/${workspaceId}/request`}
className="ml-auto"
>
<Button variant="blue"> </Button>
@ -80,9 +80,7 @@ export default function WorkspaceReviewList() {
setSortValue={setSortValue}
workspaceId={Number(workspaceId)}
/>
{isFetchingNextPage}
<div
ref={loadMoreRef}
className="h-1"

View File

@ -20,11 +20,13 @@ import NotFound from '@/pages/NotFound';
import ReviewRequest from '@/pages/ReviewRequest';
import ModelIndex from '@/pages/ModelIndex';
import ModelDetail from '@/pages/ModelDetail';
import ReviewLayout from '@/components/ReviewLayout';
export const webPath = {
home: () => '/',
browse: () => '/browse',
workspace: () => '/workspace',
review: () => '/review',
admin: () => `/admin`,
oauthCallback: () => '/redirect/oauth2',
};
@ -80,6 +82,32 @@ const router = createBrowserRouter([
},
],
},
{
path: `${webPath.review()}/:workspaceId`,
element: (
<Suspense fallback={<div></div>}>
<ReviewLayout />
</Suspense>
),
children: [
{
index: true,
element: <WorkspaceReviewList />,
},
{
path: 'request',
element: <ReviewRequest />,
},
{
path: ':projectId',
element: <ProjectReviewList />,
},
{
path: ':projectId/:reviewId',
element: <ReviewDetail />,
},
],
},
{
path: `${webPath.admin()}/:workspaceId`,
element: (
@ -92,27 +120,6 @@ const router = createBrowserRouter([
index: true,
element: <AdminIndex />,
},
{
path: 'reviews',
children: [
{
index: true,
element: <WorkspaceReviewList />,
},
{
path: 'request',
element: <ReviewRequest />,
},
{
path: ':projectId',
element: <ProjectReviewList />,
},
{
path: ':projectId/:reviewId',
element: <ReviewDetail />,
},
],
},
{
path: 'members',
children: [