From 4e46fcaa340b0a248528381efcbd41c2342e7167 Mon Sep 17 00:00:00 2001 From: eunbeann Date: Sat, 31 Aug 2024 12:19:00 +0900 Subject: [PATCH 1/2] feat: DueDate --- .../[id]/components/DueDateDropDown.tsx | 112 +++++++++++++++ src/app/(sidebar)/my-recruit/[id]/page.tsx | 133 +++++++++--------- 2 files changed, 182 insertions(+), 63 deletions(-) create mode 100644 src/app/(sidebar)/my-recruit/[id]/components/DueDateDropDown.tsx diff --git a/src/app/(sidebar)/my-recruit/[id]/components/DueDateDropDown.tsx b/src/app/(sidebar)/my-recruit/[id]/components/DueDateDropDown.tsx new file mode 100644 index 0000000..4b83942 --- /dev/null +++ b/src/app/(sidebar)/my-recruit/[id]/components/DueDateDropDown.tsx @@ -0,0 +1,112 @@ +import { recruitScheduleStageList } from '@/app/(sidebar)/my-recruit/constant'; +import { TouchButton } from '@/components/TouchButton'; +import { Icon } from '@/system/components'; +import { color } from '@/system/token/color'; +import { Spacing } from '@/system/utils/Spacing'; +import { cn } from '@/utils'; +import { immer } from '@/utils/immer'; +import clsx from 'clsx'; +import { format } from 'date-fns/format'; +import { useState } from 'react'; +import { usePostRecruitSchedule } from '../../api/usePostRecruitSchedule'; +import { AddIcon } from '../../containers/components/DueDateDialog/AddIcon'; +import { Form } from '../../containers/components/DueDateDialog/Form'; + +interface DueDateDropDownProps { + id: number; + title?: string; + close: () => void; +} + +const DEFAULT_FORM = { + recruitScheduleStage: recruitScheduleStageList[0], + deadLine: undefined, +}; + +export function DueDateDropDown({ id, title, close }: DueDateDropDownProps) { + const { mutate: postRecruitSchedule } = usePostRecruitSchedule(); + const [scheduleList, setScheduleList] = useState< + Array<{ + recruitScheduleStage: string; + deadLine?: Date; + }> + >([DEFAULT_FORM]); + + const handleDelete = (index: number) => { + const newList = [...scheduleList]; + newList.splice(index, 1); + setScheduleList(newList); + }; + + const save = () => { + scheduleList.forEach((schedule) => { + if (schedule.deadLine == null) { + return; + } + postRecruitSchedule({ + id, + recruitScheduleStage: schedule.recruitScheduleStage, + deadLine: format(schedule.deadLine, 'yyyy-MM-dd'), + }); + }); + close(); + }; + + return ( +
+
+ {title && ( + <> + + + + )} + + {title ? `${title}의 공고 일정 등록하기` : '공고 일정 등록하기'} + +
+ + + 일정을 등록하면 잊지 않도록 알려드릴게요! + + + {/* 마감일 입력 */} +
+ {scheduleList.map((schedule, index) => ( +
{ + const newSchedule = immer(scheduleList); + newSchedule[index].recruitScheduleStage = stage; + setScheduleList([...newSchedule]); + }} + onDeadLineClick={(date) => { + const newSchedule = immer(scheduleList); + newSchedule[index].deadLine = date; + setScheduleList([...newSchedule]); + }} + onDeleteClick={() => handleDelete(index)} + /> + ))} +
+ + setScheduleList([...scheduleList, DEFAULT_FORM])} + className="hover:bg-neutral-3 w-full h-46 gap-[4px] rounded-[6px] py-[13px] flex items-center justify-center"> + + 일정 추가 + + + + 저장하기 + +
+ ); +} diff --git a/src/app/(sidebar)/my-recruit/[id]/page.tsx b/src/app/(sidebar)/my-recruit/[id]/page.tsx index 87180c6..b8368dc 100644 --- a/src/app/(sidebar)/my-recruit/[id]/page.tsx +++ b/src/app/(sidebar)/my-recruit/[id]/page.tsx @@ -10,20 +10,25 @@ import { cn } from '@/utils'; import { DragEndEvent } from '@dnd-kit/core'; import { AnimatePresence, motion } from 'framer-motion'; import { useRouter } from 'next/navigation'; -import { Suspense, useState } from 'react'; +import { useState } from 'react'; import { useDeleteRecruit } from '../api/useDeleteRecruit'; import { usePostCardToRecruit } from '../api/usePostCardToRecruit'; import { RightSidebar } from '../containers/RightSidebar/RightSidebar'; -import { DueDateDialog } from '../containers/components/DueDateDialog/DueDateDialog'; import { DetailContent } from './components/DetailContent'; import DetailHeader from './components/DetailHeader'; +import { DueDateDropDown } from './components/DueDateDropDown'; export default function CompanyDetail({ params: { id: recruitId } }: { params: { id: string } }) { const router = useRouter(); const [sidebarOpened, setSidebarOpened] = useState(false); + const [dueDateDialogOpened, setDueDateDialogOpened] = useState(false); const { mutate: deleteRecruit } = useDeleteRecruit(); const { mutate: mutatePostCardToRecruit } = usePostCardToRecruit(); + const handleCloseDueDateDialog = () => { + setDueDateDialogOpened(!dueDateDialogOpened); + }; + const handleDeleteRecruit = () => { deleteRecruit(parseInt(recruitId, 10)); router.push('/my-recruit'); @@ -44,75 +49,77 @@ export default function CompanyDetail({ params: { id: recruitId } }: { params: {
-
- + +
- -
- - - - - - - 공고 일정 등록 - - - - - - }> - - - - +
+ + handleCloseDueDateDialog()}> + + + + + 공고 일정 등록 + + + + + {dueDateDialogOpened && ( + + }> + + + + )} + - setSidebarOpened(!sidebarOpened)} - className="relative p-[12px] rounded-[6px] hover:bg-neutral-3 border border-neutral-10 bg-white max-h-[42px]" - aria-label="copy button"> - - - - 내 정보 가져오기 - - - + setSidebarOpened(!sidebarOpened)} + className="relative p-[12px] rounded-[6px] hover:bg-neutral-3 border border-neutral-10 bg-white max-h-[42px]" + aria-label="copy button"> + + + + 내 정보 가져오기 + + + - - -
- -
-
- - -
- -
삭제하기
+ + +
+
- - -
+ + + +
+ +
삭제하기
+
+
+
+ +
-
+ - + - +
{sidebarOpened ? setSidebarOpened(false)} /> : null} From 8fa0be4b60683f6a0e8b255ae9b869b93c8bfdc0 Mon Sep 17 00:00:00 2001 From: eunbeann Date: Sat, 31 Aug 2024 14:14:12 +0900 Subject: [PATCH 2/2] feat: changed --- src/types/info.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/info.ts b/src/types/info.ts index 23b3cc6..55edc8c 100644 --- a/src/types/info.ts +++ b/src/types/info.ts @@ -14,7 +14,7 @@ export interface TagType { export const INFO_TYPES = ['경험_정리', '자기소개서', '면접_질문'] as const; export type InfoType = (typeof INFO_TYPES)[number]; -export const ANNOUNCEMENT_TYPES = ['서류_준비', '과제_준비', '인터뷰_준비', '내_정보_복사'] as const; +export const ANNOUNCEMENT_TYPES = ['서류_준비', '과제_준비', '면접_준비', '내_정보_복사'] as const; export const TYPE_LIST = [...INFO_TYPES, ...ANNOUNCEMENT_TYPES] as const; export type TypeTag = (typeof TYPE_LIST)[number];