Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat-fe: 공고 대시보드 제목 영역에 모집일자 및 상태 정보 추가 #802

Merged
merged 11 commits into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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}
/>
Comment on lines +50 to +53
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

깔끔해졌네용👍

<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
Loading