Skip to content

Commit

Permalink
feat-fe: posts 라우트 List컴포넌트 빌드 (#349)
Browse files Browse the repository at this point in the history
Co-authored-by: Jeongwoo Park <[email protected]>
  • Loading branch information
github-actions[bot] and lurgi authored Aug 8, 2024
1 parent 4f9b2fb commit d8f824b
Show file tree
Hide file tree
Showing 15 changed files with 288 additions and 21 deletions.
24 changes: 24 additions & 0 deletions frontend/src/api/dashboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,30 @@ import { convertParamsToQueryString } from './utils';
import ApiError from './ApiError';

const dashboardApis = {
get: async ({ dashboardId }: { dashboardId: string }) => {
const queryParams = {
clubId: dashboardId,
};

const response = await fetch(`${DASHBOARDS}?${convertParamsToQueryString(queryParams)}`, {
headers: {
Accept: 'application/json',
},
});

if (!response.ok) {
throw new ApiError({
method: 'GET',
statusCode: response.status,
message: '공고 리스트의 정보를 불러오지 못했습니다.',
});
}

const data = await response.json();

return data;
},

create: async ({ clubId, dashboardFormInfo }: { clubId: number; dashboardFormInfo: DashboardFormInfo }) => {
const queryParams = {
clubId: String(clubId),
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/api/process.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { createParams } from './utils';
import ApiError from './ApiError';

const processApis = {
get: async ({ id }: { id: number }) => {
const response = await fetch(`${PROCESSES}?${createParams({ dashboard_id: String(id) })}`, {
get: async ({ id }: { id: string }) => {
const response = await fetch(`${PROCESSES}?${createParams({ dashboard_id: id })}`, {
headers: {
Accept: 'application/json',
},
Expand Down
5 changes: 4 additions & 1 deletion frontend/src/components/appModal/ApplicantBaseInfo/index.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { useParams } from 'react-router-dom';

import Dropdown from '@components/common/Dropdown';
import Button from '@components/common/Button';
import useProcess from '@hooks/useProcess';
Expand All @@ -14,7 +16,8 @@ interface ApplicantBaseInfoProps {
export default function ApplicantBaseInfo({ applicantId }: ApplicantBaseInfoProps) {
const { data: applicantBaseDetail } = specificApplicant.useGetBaseInfo({ applicantId });
const { mutate: rejectMutate } = specificApplicant.useRejectApplicant();
const { processList } = useProcess();
const { dashboardId, postId } = useParams() as { dashboardId: string; postId: string };
const { processList } = useProcess({ dashboardId, postId });
const { moveApplicantProcess } = useApplicant({ applicantId });
const { close } = useModal();

Expand Down
5 changes: 4 additions & 1 deletion frontend/src/components/dashboard/ProcessColumn/index.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { useParams } from 'react-router-dom';

import { useSpecificApplicantId } from '@contexts/SpecificApplicnatIdContext';
import { Process } from '@customTypes/process';
import useProcess from '@hooks/useProcess';
Expand All @@ -12,7 +14,8 @@ interface ProcessColumnProps {
}

export default function ProcessColumn({ process }: ProcessColumnProps) {
const { processList } = useProcess();
const { dashboardId, postId } = useParams() as { dashboardId: string; postId: string };
const { processList } = useProcess({ dashboardId, postId });
const { moveApplicantProcess } = useApplicant({});
const { setApplicantId } = useSpecificApplicantId();
const { open } = useModal();
Expand Down
17 changes: 17 additions & 0 deletions frontend/src/hooks/useGetDashboards/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import dashboardApis from '@api/dashboard';
import type { Club } from '@customTypes/dashboard';
import QUERY_KEYS from '@hooks/queryKeys';
import { useQuery } from '@tanstack/react-query';

interface UseGetDashboardsProps {
dashboardId: string;
}

export default function useGetDashboards({ dashboardId }: UseGetDashboardsProps) {
const { data, error, isLoading } = useQuery<Club>({
queryKey: [QUERY_KEYS.DASHBOARD, dashboardId],
queryFn: () => dashboardApis.get({ dashboardId }),
});

return { data, error, isLoading };
}
12 changes: 8 additions & 4 deletions frontend/src/hooks/useProcess/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,29 @@ import { useQuery } from '@tanstack/react-query';
import type { Process } from '@customTypes/process';

import processApis from '@api/process';
import { DASHBOARD_ID } from '@constants/constants';
import QUERY_KEYS from '@hooks/queryKeys';

interface SimpleProcess {
processName: string;
processId: number;
}

interface UseProcessProps {
dashboardId: string;
postId: string;
}

interface UseProcessReturn {
processes: Process[];
processList: SimpleProcess[];
error: Error | null;
isLoading: boolean;
}

export default function useProcess(): UseProcessReturn {
export default function useProcess({ dashboardId, postId }: UseProcessProps): UseProcessReturn {
const { data, error, isLoading } = useQuery<{ processes: Process[] }>({
queryKey: [QUERY_KEYS.DASHBOARD, DASHBOARD_ID],
queryFn: () => processApis.get({ id: DASHBOARD_ID }),
queryKey: [QUERY_KEYS.DASHBOARD, dashboardId, postId],
queryFn: () => processApis.get({ id: postId }),
});

const processes = data?.processes || [];
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/hooks/useProcess/useProcess.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const wrapper = ({ children }: PropsWithChildren) => (

describe('useProcess', () => {
it('should return processes and processNameList when data is loaded', async () => {
const { result } = renderHook(() => useProcess(), { wrapper });
const { result } = renderHook(() => useProcess({ dashboardId: '1', postId: '1' }), { wrapper });

await waitFor(() => expect(result.current.isLoading).toBe(false));

Expand Down
44 changes: 44 additions & 0 deletions frontend/src/mocks/dashboardList.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"clubName": "크루루",
"dashboards": [
{
"dashboardId": "1",
"title": "프론트엔드 7기 모집",
"stats": {
"accept": 3,
"fail": 3,
"inProgress": 9,
"total": 15
},
"postUrl": "https://www.cruru.kr/123543920/recruit",
"startDate": "1900-01-21T00:00:00",
"endDate": "2024-07-24T18:00:00"
},
{
"dashboardId": "2",
"title": "백엔드 7기 모집",
"stats": {
"accept": 3,
"fail": 3,
"inProgress": 9,
"total": 15
},
"postUrl": "https://www.cruru.kr/98765101/recruit",
"startDate": "1900-01-21T00:00:00",
"endDate": "2024-07-24T20:30:00"
},
{
"dashboardId": "3",
"title": "안드로이드 7기 모집",
"stats": {
"accept": 3,
"fail": 3,
"inProgress": 9,
"total": 15
},
"postUrl": "https://www.cruru.kr/7777890/recruit",
"startDate": "1900-01-21T00:00:00",
"endDate": "2024-07-24T21:00:00"
}
]
}
17 changes: 16 additions & 1 deletion frontend/src/mocks/handlers/dashboardHandlers.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { http } from 'msw';
import { http, HttpResponse } from 'msw';

import { DASHBOARDS } from '@api/endPoint';
import { DashboardFormInfo } from '@customTypes/dashboard';
import DASHBOARD_LIST from '../dashboardList.json';

const dashboardHandlers = [
http.post(DASHBOARDS, async ({ request }) => {
Expand All @@ -21,6 +22,20 @@ const dashboardHandlers = [
statusText: 'Created',
});
}),

http.get(DASHBOARDS, ({ request }) => {
const url = new URL(request.url);
const clubId = url.searchParams.get('clubId');

if (!clubId) {
return new Response(null, {
status: 400,
statusText: 'The request Param is missing required information.',
});
}

return HttpResponse.json(DASHBOARD_LIST);
}),
];

export default dashboardHandlers;
36 changes: 36 additions & 0 deletions frontend/src/pages/DashBoardList/DashboardList.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { reactRouterParameters } from 'storybook-addon-remix-react-router';
import type { Meta, StoryObj } from '@storybook/react';
import DashboardList from '.';

const meta: Meta<typeof DashboardList> = {
title: 'Components/DashboardList',
component: DashboardList,
parameters: {
layout: 'centered',
docs: {
description: {
component: 'DashboardList 컴포넌트는 여러 대시보드를 리스트 형태로 보여줍니다.',
},
},
reactRouter: reactRouterParameters({
location: {
pathParams: { dashboardId: '1' },
},
routing: { path: '/dashboardId/:dashboardId' },
}),
},
tags: ['autodocs'],
};

export default meta;
type Story = StoryObj<typeof DashboardList>;

export const Default: Story = {
decorators: [
(Child) => (
<div style={{ width: '900px', border: '1px solid gray' }}>
<Child />
</div>
),
],
};
40 changes: 34 additions & 6 deletions frontend/src/pages/DashBoardList/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,38 @@
import RecruitmentCard from '@components/recruitment/RecruitmentCard';
import { useNavigate, useParams } from 'react-router-dom';
import useGetDashboards from '@hooks/useGetDashboards';
import S from './style';

export default function DashboardList() {
const { dashboardId } = useParams() as { dashboardId: string };
const { data } = useGetDashboards({ dashboardId });
const navigate = useNavigate();

const handleCardClick = (postId: number) => {
navigate(`/dashboard/${dashboardId}/${postId}`);
};

return (
<div>
List
{/*
TODO: 여기에 PostList를 넣어주세요!!!!!!
*/}
</div>
<S.Container>
<S.Title>{data?.clubName}</S.Title>
<S.CardGrid>
{data?.dashboards.map((dashboard) => (
<RecruitmentCard
key={dashboard.dashboardId}
// TODO: dashboardId -> postId로 변경
dashboardId={Number(dashboard.dashboardId)}
title={dashboard.title}
postStats={dashboard.stats}
startDate={dashboard.startDate}
endDate={dashboard.endDate}
onClick={handleCardClick}
/>
))}
<S.AddCard onClick={() => navigate(`/dashboard/${dashboardId}/create`)}>
<div>+</div>
<span>새 공고 추가</span>
</S.AddCard>
</S.CardGrid>
</S.Container>
);
}
58 changes: 58 additions & 0 deletions frontend/src/pages/DashBoardList/style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import styled from '@emotion/styled';

const Container = styled.div`
display: flex;
flex-direction: column;
padding: 3.8rem 2.4rem;
gap: 2.4rem;
`;

const Title = styled.h1`
${({ theme }) => theme.typography.heading[700]}
padding-bottom: 2.4rem;
border-bottom: 1px solid ${({ theme }) => theme.baseColors.grayscale[300]};
`;

const CardGrid = styled.div`
display: grid;
grid-template-columns: repeat(auto-fill, 37.8rem);
gap: 2.4rem;
`;

const AddCard = styled.div`
display: flex;
height: 20rem;
flex-direction: column;
align-items: center;
justify-content: center;
border: 0.2rem dashed ${({ theme }) => theme.baseColors.grayscale[600]};
border-radius: 0.5rem;
padding: 2rem;
cursor: pointer;
text-align: center;
&:hover {
background-color: ${({ theme }) => theme.baseColors.grayscale[200]};
}
div {
font-size: 6rem;
color: ${({ theme }) => theme.colors.brand.primary};
}
span {
${({ theme }) => theme.typography.common.large}
color: ${({ theme }) => theme.baseColors.grayscale[800]};
}
`;

const S = {
Container,
Title,
CardGrid,
AddCard,
};

export default S;
7 changes: 5 additions & 2 deletions frontend/src/pages/Dashboard/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { useParams } from 'react-router-dom';

import ProcessManageBoard from '@components/processManagement/ProcessManageBoard';
import Tab from '@components/common/Tab';
import KanbanBoard from '@components/dashboard/KanbanBoard';
import ProcessManageBoard from '@components/processManagement/ProcessManageBoard';

import useTab from '@components/common/Tab/useTab';
import useProcess from '@hooks/useProcess';
Expand All @@ -13,7 +15,8 @@ import S from './style';
export type DashboardTabItems = '지원자 관리' | '모집 과정 관리';

export default function Dashboard() {
const { processes } = useProcess();
const { dashboardId, postId } = useParams() as { dashboardId: string; postId: string };
const { processes } = useProcess({ dashboardId, postId });

const { currentMenu, moveTab } = useTab<DashboardTabItems>({ defaultValue: '지원자 관리' });

Expand Down
Loading

0 comments on commit d8f824b

Please sign in to comment.