diff --git a/src/app/(sidebar)/my-recruit/containers/AllRecruitment.tsx b/src/app/(sidebar)/my-recruit/containers/AllRecruitment.tsx
index 7f456cfc..e6959e93 100644
--- a/src/app/(sidebar)/my-recruit/containers/AllRecruitment.tsx
+++ b/src/app/(sidebar)/my-recruit/containers/AllRecruitment.tsx
@@ -12,6 +12,8 @@ import {
import { motion } from 'framer-motion';
import { color } from '@/system/token/color';
import { Dialog } from '@/system/components/Dialog/ShadcnDialog';
+import { cardList } from '../mock';
+import { RowCard } from './components/Card/RowCard';
export function AllRecruitment() {
return (
@@ -43,6 +45,12 @@ export function AllRecruitment() {
등록된 공고가 없어요
+
+
+ {cardList.map((cardInfo) => (
+
+ ))}
+
>
);
}
diff --git a/src/app/(sidebar)/my-recruit/containers/ProgressingRecruitment.tsx b/src/app/(sidebar)/my-recruit/containers/ProgressingRecruitment.tsx
index 9098eb5b..3d31fd3d 100644
--- a/src/app/(sidebar)/my-recruit/containers/ProgressingRecruitment.tsx
+++ b/src/app/(sidebar)/my-recruit/containers/ProgressingRecruitment.tsx
@@ -3,6 +3,9 @@ import { ShoeIcon } from './components/ShoeIcon';
import { Dialog } from '@/system/components/Dialog/ShadcnDialog';
import { motion } from 'framer-motion';
import { color } from '@/system/token/color';
+import { cardList } from '../mock';
+import { BoxCard } from './components/Card/BoxCard';
+import { TouchButton } from '@/components/TouchButton';
export function ProgressingRecruitment() {
return (
@@ -21,6 +24,22 @@ export function ProgressingRecruitment() {
진행중인 공고가 없어요
+
+
+ {cardList.map((cardInfo) => (
+
+ ))}
+
+
+
+
+
+ 더보기
+
+
+ 간략히 보기
+
+
>
);
}
diff --git a/src/app/(sidebar)/my-recruit/containers/components/Card/BoxCard.tsx b/src/app/(sidebar)/my-recruit/containers/components/Card/BoxCard.tsx
new file mode 100644
index 00000000..b3924ead
--- /dev/null
+++ b/src/app/(sidebar)/my-recruit/containers/components/Card/BoxCard.tsx
@@ -0,0 +1,68 @@
+import { Spacing } from '@/components/Spacing';
+import { Icon } from '@/system/components';
+import { color } from '@/system/token/color';
+import { dday } from '@/utils/date';
+import { MoreButton } from '@/app/(sidebar)/my-recruit/containers/components/Card/common/MoreButton';
+import { StatusButton } from '@/app/(sidebar)/my-recruit/containers/components/Card/common/StatusButton';
+import { Dialog } from '@/system/components/Dialog/ShadcnDialog';
+import { DueDateDialog } from '../DueDateDialog';
+
+export type ProgressingCardType = {
+ type: '서류 마감' | '1차 면접' | '2차 면접';
+ status: '지원 완료' | '서류 통과' | '서류 탈락';
+ dueDate: Date | null;
+ period: string;
+ title: string;
+};
+
+export function BoxCard({ type, title, status, dueDate, period }: ProgressingCardType) {
+ return (
+
+
+ {dueDate == null ? (
+
+ ) : (
+ <>
+
+
+
+ {type} D-{dday(dueDate)}
+
+
+
+ >
+ )}
+
+
+
+ );
+}
+
+const statusList = [
+ { variant: 'text', text: '지원 준비' },
+ { variant: 'text', text: '지원 완료' },
+ { variant: 'border' },
+ { variant: 'text', text: '서류 통과' },
+ { variant: 'text', text: '서류 탈락' },
+ { variant: 'border' },
+ { variant: 'text', text: '면접 통과' },
+ { variant: 'text', text: '면접 탈락' },
+ { variant: 'border' },
+ { variant: 'text', text: '최종 합격' },
+ { variant: 'text', text: '최종 탈락' },
+] as const;
diff --git a/src/app/(sidebar)/my-recruit/containers/components/Card/RowCard.tsx b/src/app/(sidebar)/my-recruit/containers/components/Card/RowCard.tsx
new file mode 100644
index 00000000..1e9cc852
--- /dev/null
+++ b/src/app/(sidebar)/my-recruit/containers/components/Card/RowCard.tsx
@@ -0,0 +1,44 @@
+import { If } from '@/components/If';
+import { Spacing } from '@/components/Spacing';
+import { Icon } from '@/system/components';
+import { color } from '@/system/token/color';
+import { dday } from '@/utils/date';
+import { MoreButton } from '@/app/(sidebar)/my-recruit/containers/components/Card/common/MoreButton';
+import { StatusButton } from './common/StatusButton';
+
+interface RowCardProps {
+ type: '서류 마감' | '1차 면접' | '2차 면접';
+ status: '지원 완료' | '서류 통과' | '서류 탈락';
+ dueDate: Date | null;
+ period: string;
+ title: string;
+}
+
+export function RowCard({ type, title, status, dueDate, period }: RowCardProps) {
+ return (
+
+
+
+
+
{period}
+
+
+
+
+
+ {type} D-{dday(dueDate!)}
+
+
+
+
+
{title}
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/app/(sidebar)/my-recruit/containers/components/Card/common/MoreButton.tsx b/src/app/(sidebar)/my-recruit/containers/components/Card/common/MoreButton.tsx
new file mode 100644
index 00000000..c81693de
--- /dev/null
+++ b/src/app/(sidebar)/my-recruit/containers/components/Card/common/MoreButton.tsx
@@ -0,0 +1,24 @@
+import { Icon } from '@/system/components';
+import {
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuTrigger,
+} from '@/system/components/DropdownMenu/DropdownMenu';
+import { color } from '@/system/token/color';
+
+export function MoreButton() {
+ return (
+
+
+
+
+
+
+
+ 삭제하기
+
+
+
+ );
+}
diff --git a/src/app/(sidebar)/my-recruit/containers/components/Card/common/StatusButton.tsx b/src/app/(sidebar)/my-recruit/containers/components/Card/common/StatusButton.tsx
new file mode 100644
index 00000000..e643f4cd
--- /dev/null
+++ b/src/app/(sidebar)/my-recruit/containers/components/Card/common/StatusButton.tsx
@@ -0,0 +1,58 @@
+import { SwitchCase } from '@/components/SwitchCase';
+import { Icon } from '@/system/components';
+import {
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuTrigger,
+ DropdownMenuSeparator,
+} from '@/system/components/DropdownMenu/DropdownMenu';
+import { color } from '@/system/token/color';
+import { cn } from '@/utils';
+
+interface Props {
+ currentStatus: string;
+}
+
+export function StatusButton({ currentStatus }: Props) {
+ return (
+
+
+
+ {currentStatus}
+
+
+
+
+ {statusList.map((item) => (
+
+ {item.text}
+
+ ) : null,
+ border: ,
+ }}
+ />
+ ))}
+
+
+ );
+}
+
+const statusList = [
+ { variant: 'text', text: '지원 준비' },
+ { variant: 'text', text: '지원 완료' },
+ { variant: 'border' },
+ { variant: 'text', text: '서류 통과' },
+ { variant: 'text', text: '서류 탈락' },
+ { variant: 'border' },
+ { variant: 'text', text: '면접 통과' },
+ { variant: 'text', text: '면접 탈락' },
+ { variant: 'border' },
+ { variant: 'text', text: '최종 합격' },
+ { variant: 'text', text: '최종 탈락' },
+] as const;
diff --git a/src/app/(sidebar)/my-recruit/containers/components/DueDateDialog.tsx b/src/app/(sidebar)/my-recruit/containers/components/DueDateDialog.tsx
new file mode 100644
index 00000000..50b110a4
--- /dev/null
+++ b/src/app/(sidebar)/my-recruit/containers/components/DueDateDialog.tsx
@@ -0,0 +1,64 @@
+import { Spacing } from '@/components/Spacing';
+import { Button, Icon } from '@/system/components';
+import { color } from '@/system/token/color';
+import clsx from 'clsx';
+import { motion } from 'framer-motion';
+import { Popover, PopoverContent, PopoverTrigger } from '@/system/components/Popover/Popover';
+import { Calendar } from '@/system/components/Calendar/Calendar';
+import { format } from 'date-fns/format';
+import { useState } from 'react';
+
+interface DueDateDialogProps {
+ title: string;
+}
+
+export function DueDateDialog({ title }: DueDateDialogProps) {
+ const [selectedDate, setSelectedDate] = useState();
+
+ const isDateSelected = selectedDate != null;
+
+ return (
+
+
+
+
+ {title}
+ 의 공고 일정 등록하기
+
+
+
일정을 등록하면 잊지 않도록 알려드릴게요!
+
+ {/* 마감일 입력 */}
+
+
서류마감
+
+
+
+
+
+ {isDateSelected ? format(selectedDate, 'yyyy.mm.dd') : '마감일을 선택해주세요'}
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/app/(sidebar)/my-recruit/mock.ts b/src/app/(sidebar)/my-recruit/mock.ts
new file mode 100644
index 00000000..e08cfed9
--- /dev/null
+++ b/src/app/(sidebar)/my-recruit/mock.ts
@@ -0,0 +1,18 @@
+import { ProgressingCardType } from './containers/components/Card/BoxCard';
+
+export const cardList: ProgressingCardType[] = [
+ {
+ type: '1차 면접',
+ status: '서류 통과',
+ dueDate: null,
+ period: '2024 상반기',
+ title: '디프만 15기 디자이너 직군',
+ },
+ {
+ type: '2차 면접',
+ status: '지원 완료',
+ dueDate: new Date('2024-08-20'),
+ period: '2024 하반기',
+ title: '2024 네이버 프로덕트 디자이너 신입공채 지원서 제출',
+ },
+];
diff --git a/src/components/SwitchCase.tsx b/src/components/SwitchCase.tsx
new file mode 100644
index 00000000..58aec27c
--- /dev/null
+++ b/src/components/SwitchCase.tsx
@@ -0,0 +1,17 @@
+interface Props {
+ caseBy: Partial>;
+ value: Case;
+ defaultComponent?: JSX.Element | null;
+}
+
+export function SwitchCase({
+ value,
+ caseBy,
+ defaultComponent: defaultComponent = null,
+}: Props) {
+ if (value == null) {
+ return defaultComponent;
+ }
+
+ return caseBy[value] ?? defaultComponent;
+}
diff --git a/src/system/components/Icon/Icon.tsx b/src/system/components/Icon/Icon.tsx
index bff5a2b5..69c4f423 100644
--- a/src/system/components/Icon/Icon.tsx
+++ b/src/system/components/Icon/Icon.tsx
@@ -23,6 +23,9 @@ import { Link } from './SVG/Link';
import { Unlink } from './SVG/Unlink';
import { Calendar } from './SVG/Calendar';
import { CalendarFill } from './SVG/CalendarFill';
+import { Clover } from './SVG/Clover';
+import { DownChevron } from './SVG/DownChevron';
+import { FolderFill } from './SVG/FolderFill';
const iconMap = {
bell: Bell,
@@ -30,11 +33,13 @@ const iconMap = {
check: Check,
division: Division,
folder: Folder,
+ folderFill: FolderFill,
logout: Logout,
memo: Memo,
profile: Profile,
profileFill: ProfileFill,
rightChevron: RightChevron,
+ downChevron: DownChevron,
search: Search,
setting: Setting,
down: Down,
@@ -49,6 +54,7 @@ const iconMap = {
unlink: Unlink,
calendar: Calendar,
calendarFill: CalendarFill,
+ clover: Clover,
} as const;
export interface IconProps extends IconBaseType {
diff --git a/src/system/components/Icon/SVG/Clover.tsx b/src/system/components/Icon/SVG/Clover.tsx
new file mode 100644
index 00000000..788e93e2
--- /dev/null
+++ b/src/system/components/Icon/SVG/Clover.tsx
@@ -0,0 +1,14 @@
+import { IconBaseType } from '@/system/components/Icon/SVG/type';
+
+export function Clover({ size, color }: IconBaseType) {
+ return (
+
+ );
+}
diff --git a/src/system/components/Icon/SVG/DownChevron.tsx b/src/system/components/Icon/SVG/DownChevron.tsx
new file mode 100644
index 00000000..47033995
--- /dev/null
+++ b/src/system/components/Icon/SVG/DownChevron.tsx
@@ -0,0 +1,9 @@
+import { IconBaseType } from '@/system/components/Icon/SVG/type';
+
+export function DownChevron({ color, size }: IconBaseType) {
+ return (
+
+ );
+}
diff --git a/src/system/components/Icon/SVG/FolderFill.tsx b/src/system/components/Icon/SVG/FolderFill.tsx
new file mode 100644
index 00000000..3cb4d33a
--- /dev/null
+++ b/src/system/components/Icon/SVG/FolderFill.tsx
@@ -0,0 +1,14 @@
+import { IconBaseType } from '@/system/components/Icon/SVG/type';
+
+export function FolderFill({ size, color }: IconBaseType) {
+ return (
+
+ );
+}
diff --git a/src/utils/date.ts b/src/utils/date.ts
index 7b5785b3..130b1166 100644
--- a/src/utils/date.ts
+++ b/src/utils/date.ts
@@ -1,3 +1,5 @@
+import { differenceInDays } from 'date-fns/differenceInDays';
+
interface Option {
separator?: string;
}
@@ -11,3 +13,9 @@ export const formatToYYMMDD = (dateString: string, { separator = '' }: Option =
return [yy, mm, dd].join(separator);
};
+
+export const dday = (target: Date) => {
+ const today = new Date();
+
+ return differenceInDays(target, today);
+};