Skip to content

Commit

Permalink
feat-fe: 공고 대시보드 제목 영역에 모집일자 및 상태 정보 추가 (#802)
Browse files Browse the repository at this point in the history
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Seongjin Hong <[email protected]>
Co-authored-by: Kim Da Eun <[email protected]>
  • Loading branch information
3 people authored Oct 15, 2024
1 parent 0c2585d commit 590cdc8
Show file tree
Hide file tree
Showing 13 changed files with 250 additions and 51 deletions.
8 changes: 1 addition & 7 deletions frontend/src/components/_common/atoms/OpenInNewTab/style.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
import styled from '@emotion/styled';

const Container = styled.div`
width: 100%;
display: flex;
align-items: center;
gap: 0.8rem;
padding: 0.8rem;
border-bottom: 1px solid ${({ theme }) => theme.baseColors.grayscale[500]};
gap: 0.4rem;
& > svg {
color: ${({ theme }) => theme.baseColors.purplescale[800]};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import type { Meta, StoryObj } from '@storybook/react';
import { withRouter } from 'storybook-addon-remix-react-router';
import DashboardHeader from '.';

const meta = {
title: 'Organisms/Dashboard/DashboardHeader',
component: DashboardHeader,
parameters: {
layout: 'centered',
docs: {
description: {
component: '현재 공고의 대시보드 헤더를 표시하는 컴포넌트입니다.',
},
},
},
tags: ['autodocs'],
argTypes: {
title: { control: 'text' },
postUrl: { control: 'text' },
startDate: { control: 'date' },
endDate: { control: 'date' },
},
decorators: [
withRouter,
(Story) => (
<div style={{ width: '720px' }}>
<Story />
</div>
),
],
} satisfies Meta<typeof DashboardHeader>;

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

export const DashboardHeaderDefault: Story = {
args: {
title: '우아한테크코스 7기 프론트엔드 모집',
postUrl: 'https://www.cruru.kr',
startDate: '2024-07-15T09:00:00Z',
endDate: '2024-12-15T09:00:00Z',
},
};
40 changes: 40 additions & 0 deletions frontend/src/components/dashboard/DashboardHeader/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import formatDate from '@utils/formatDate';
import { HiOutlineCalendar } from 'react-icons/hi';

import OpenInNewTab from '@components/_common/atoms/OpenInNewTab';
import RecruitmentStatusFlag from '@components/recruitment/RecruitmentStatusFlag';

import S from './style';

interface DashboardHeaderProps {
title: string;
postUrl: string;
startDate: string;
endDate: string;
}

export default function DashboardHeader({ title, postUrl, startDate, endDate }: DashboardHeaderProps) {
return (
<S.Wrapper>
<S.TitleContainer>
<S.Title>
{title}
<OpenInNewTab
url={postUrl}
title="공고로 이동"
/>
</S.Title>
<S.RecruitmentStatusContainer>
<S.RecruitmentPeriod>
<HiOutlineCalendar style={{ strokeWidth: '0.25rem' }} />
{`${formatDate(startDate)} ~ ${formatDate(endDate)}`}
</S.RecruitmentPeriod>
<RecruitmentStatusFlag
startDate={startDate}
endDate={endDate}
/>
</S.RecruitmentStatusContainer>
</S.TitleContainer>
</S.Wrapper>
);
}
57 changes: 57 additions & 0 deletions frontend/src/components/dashboard/DashboardHeader/style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import styled from '@emotion/styled';

const Wrapper = styled.div`
display: flex;
flex-direction: row;
justify-content: space-between;
padding-bottom: 1.2rem;
`;

const TitleContainer = styled.div`
display: flex;
flex-direction: column;
gap: 0.8rem;
`;

const Title = styled.div`
${({ theme }) => theme.typography.heading[700]}
display: flex;
align-items: baseline;
gap: 1.2rem;
`;

const RecruitmentStatusContainer = styled.div`
display: flex;
flex-direction: row;
align-items: center;
gap: 1.6rem;
`;

const RecruitmentPeriod = styled.div`
display: flex;
flex-direction: row;
align-items: center;
gap: 0.6rem;
${({ theme }) => theme.typography.heading[400]};
color: ${({ theme }) => theme.baseColors.grayscale[600]};
`;

const PostLinkContainer = styled.div`
display: flex;
gap: 0.8rem;
min-width: 30rem;
height: fit-content;
`;

const S = {
Wrapper,
TitleContainer,
Title,
RecruitmentStatusContainer,
RecruitmentPeriod,
PostLinkContainer,
};

export default S;
16 changes: 5 additions & 11 deletions frontend/src/components/recruitment/RecruitmentCard/index.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { HiOutlineClock } from 'react-icons/hi';
import { RecruitmentStatusType } from '@customTypes/recruitment';
import formatDate from '@utils/formatDate';
import { getTimeStatus } from '@utils/compareTime';

import RecruitmentCardStat from '../RecruitmentCardStat';
import RecruitmentStatusFlag from '../RecruitmentStatusFlag';
import S from './style';

interface RecruitmentStats {
Expand All @@ -29,12 +28,6 @@ const POST_STATS_KEY: Record<string, string> = {
total: '전체',
} as const;

const RECRUITMENT_STATUS: Record<RecruitmentStatusType, string> = {
Pending: '모집 예정',
Ongoing: '모집 진행 중',
Closed: '모집 마감',
};

export default function RecruitmentCard({
dashboardId,
title,
Expand All @@ -43,8 +36,6 @@ export default function RecruitmentCard({
endDate,
onClick,
}: RecruitmentCardProps) {
const { status } = getTimeStatus({ startDate, endDate });

const postStatsMap: [string, number][] = [
[POST_STATS_KEY.total, postStats.total],
[POST_STATS_KEY.inProgress, postStats.inProgress],
Expand All @@ -56,7 +47,10 @@ export default function RecruitmentCard({
<S.CardWrapper onClick={onClick}>
<S.RecruitmentInfoContainer>
<S.RecruitmentTitle>{title}</S.RecruitmentTitle>
<S.RecruitmentStatusFlag status={status}>{RECRUITMENT_STATUS[status]}</S.RecruitmentStatusFlag>
<RecruitmentStatusFlag
startDate={startDate}
endDate={endDate}
/>
<S.EndDateContainer>
<HiOutlineClock size="1.6rem" />
<span>{formatDate(endDate)}</span>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import type { Meta, StoryObj } from '@storybook/react';
import RecruitmentStatusFlag from '.';

const meta = {
title: 'Organisms/Recruitment/RecruitmentStatusFlag',
component: RecruitmentStatusFlag,
parameters: {
layout: 'centered',
docs: {
description: {
component: '현재 공고의 모집 진행 상태를 표시하는 플래그 컴포넌트입니다.',
},
},
},
tags: ['autodocs'],
argTypes: {
startDate: { control: 'date' },
endDate: { control: 'date' },
},
} satisfies Meta<typeof RecruitmentStatusFlag>;

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

export const RecruitmentStatusFlagDefault: Story = {
args: {
startDate: '2024-07-15T09:00:00Z',
endDate: '2024-12-15T09:00:00Z',
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { RecruitmentStatusType } from '@customTypes/recruitment';
import { getTimeStatus } from '@utils/compareTime';
import S from './style';

interface RecruitmentStatusFlagProps {
startDate: string;
endDate: string;
}

const RECRUITMENT_STATUS: Record<RecruitmentStatusType, string> = {
Pending: '모집 예정',
Ongoing: '모집 진행 중',
Closed: '모집 마감',
};

export default function RecruitmentStatusFlag({ startDate, endDate }: RecruitmentStatusFlagProps) {
const { status } = getTimeStatus({ startDate, endDate });

return <S.FlagContainer status={status}>{RECRUITMENT_STATUS[status]}</S.FlagContainer>;
}
38 changes: 38 additions & 0 deletions frontend/src/components/recruitment/RecruitmentStatusFlag/style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import styled from '@emotion/styled';
import { css } from '@emotion/react';
import { RecruitmentStatusType } from '@customTypes/recruitment';

const FlagContainer = styled.div<{ status: RecruitmentStatusType }>`
width: fit-content;
border-radius: 0.4rem;
padding: 0.5rem 0.8rem;
${({ theme }) => theme.typography.common.small};
${({ theme, status }) => {
if (status === 'Pending') {
return css`
border: 1px solid ${theme.baseColors.bluescale[100]};
background: ${theme.baseColors.bluescale[50]};
color: ${theme.baseColors.bluescale[500]};
`;
}
if (status === 'Ongoing') {
return css`
border: 1px solid ${theme.baseColors.purplescale[100]};
background: ${theme.baseColors.purplescale[50]};
color: ${theme.baseColors.purplescale[500]};
`;
}
return css`
border: 1px solid ${theme.baseColors.grayscale[300]};
background: ${theme.baseColors.grayscale[200]};
color: ${theme.baseColors.grayscale[700]};
`;
}}
`;

const S = {
FlagContainer,
};

export default S;
4 changes: 4 additions & 0 deletions frontend/src/hooks/useProcess/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ interface UseProcessReturn {
error: Error | null;
isLoading: boolean;
postUrl: string;
startDate: string;
endDate: string;
}

export default function useProcess({ dashboardId, applyFormId }: UseProcessProps): UseProcessReturn {
Expand All @@ -42,5 +44,7 @@ export default function useProcess({ dashboardId, applyFormId }: UseProcessProps
processList,
error,
isLoading,
startDate: data?.startDate ?? '0',
endDate: data?.endDate ?? '0',
};
}
2 changes: 2 additions & 0 deletions frontend/src/mocks/processMockData.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
{
"title": "우아한테크코스 프론트엔드 크루 모집",
"applyFormId": "1",
"startDate": "2024-09-21T00:00:00",
"endDate": "2024-12-24T00:00:00",
"processes": [
{
"processId": 1,
Expand Down
22 changes: 8 additions & 14 deletions frontend/src/pages/Dashboard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ import ProcessBoard from '@components/dashboard/ProcessBoard';
import ApplyManagement from '@components/applyManagement';
import ProcessManageBoard from '@components/processManagement/ProcessManageBoard';
import PostManageBoard from '@components/postManagement/PostManageBoard';
import OpenInNewTab from '@components/_common/atoms/OpenInNewTab';
import CopyToClipboard from '@components/_common/atoms/CopyToClipboard';
import DashboardHeader from '@components/dashboard/DashboardHeader';

import useTab from '@components/_common/molecules/Tab/useTab';
import useProcess from '@hooks/useProcess';
Expand All @@ -24,23 +23,18 @@ export type DashboardTabItems = '지원자 관리' | '모집 과정 관리' | '

export default function Dashboard() {
const { dashboardId, applyFormId } = useParams() as { dashboardId: string; applyFormId: string };
const { processes, title, postUrl } = useProcess({ dashboardId, applyFormId });
const { processes, title, postUrl, startDate, endDate } = useProcess({ dashboardId, applyFormId });

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

return (
<S.AppContainer>
<S.Header>
<S.Title>{title}</S.Title>

<S.CopyWrapper>
<OpenInNewTab
url={postUrl}
title="공고로 이동"
/>
<CopyToClipboard url={postUrl} />
</S.CopyWrapper>
</S.Header>
<DashboardHeader
title={title}
postUrl={postUrl}
startDate={startDate}
endDate={endDate}
/>

<Tab>
{Object.values(DASHBOARD_TAB_MENUS).map((label) => (
Expand Down
19 changes: 0 additions & 19 deletions frontend/src/pages/Dashboard/style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,6 @@ const AppContainer = styled.div`
height: 100%;
`;

const Header = styled.div`
display: flex;
justify-content: space-between;
`;

const Title = styled.div`
${({ theme }) => theme.typography.heading[700]}
`;

const CopyWrapper = styled.div`
display: flex;
gap: 0.8rem;
min-width: 30rem;
`;

const DashboardPanel = styled.div<{ isVisible: boolean }>`
width: 100%;
height: 80%;
Expand All @@ -38,10 +22,7 @@ const DashboardPanel = styled.div<{ isVisible: boolean }>`

const S = {
AppContainer,
Header,
Title,
DashboardPanel,
CopyWrapper,
};

export default S;
Loading

0 comments on commit 590cdc8

Please sign in to comment.