diff --git a/apps/time/src/widgets/time-table/ui/TimeTableModal.tsx b/apps/time/src/widgets/time-table/ui/TimeTableModal.tsx index 6330c873..0aab54e8 100644 --- a/apps/time/src/widgets/time-table/ui/TimeTableModal.tsx +++ b/apps/time/src/widgets/time-table/ui/TimeTableModal.tsx @@ -2,49 +2,91 @@ import { Dispatch, + HTMLAttributes, SetStateAction, + memo, useCallback, useEffect, useState, } from 'react'; +import { Input } from '@clab/design-system'; import { CloseOutline } from '@clab/icon'; import { DAY_VALUE_ARRAY, MODAL_KEY } from '@/shared/constants'; import { useModalAction, useModalState } from '@/shared/hooks'; import type { DayKor } from '@/shared/types'; import { Modal } from '@/shared/ui'; +import { + DayPeriod, + DayStatus, + Grade, + LectureKey, + NightPeriod, + Region, + SPECIAL_PERIOD, + SpecialPeriod, +} from '@/widgets/time-table'; import { DAY_PERIOD_ARRAY, - DAY_STATUS, - type DayPeriod, - type DayStatus, GRADE, - type Grade, + LECTURE, + LECTURE_ARRAY, NIGHT_PERIOD_ARRAY, - type NightPeriod, + REGION, + REGION_VALUE_ARRAY, } from '@/widgets/time-table'; interface TimeTableModalFilterProps { title: string; list: T[]; - origin: T; + origin: T[]; handleFilterItem: (listVal: T) => void; parseFunc?: () => boolean; } -interface TimeTableModalPeriodDropdownProps { +interface TimeTableModalPeriodDropdownProps { dayStatus: DayStatus; - selectedPeriod: DayPeriod[]; - dropdownItemHandler: (period: DayPeriod) => void; + selectedPeriod: T[]; + handlePeriodDropdownItem: (period: T) => void; +} + +interface TimeTableModalLectureTypeDropdownProps { + selectedLectureType: LectureKey[]; + handleLectureTypeDropdownItem: (lecture: LectureKey) => void; +} + +interface TimeTableModalDropdownButtonProps + extends HTMLAttributes { + onClick: (event: React.MouseEvent) => void; + value: string; } -interface TimeTableModalProps { +interface TimeTableLectureTableProps { + lectureList: unknown[]; +} + +interface TimeTableModalProps { dayStatus: DayStatus; day: DayKor; - period: DayPeriod | NightPeriod; + period: T; } +const LECTURE_TABLE_ROW_HEADER = [ + '과목코드', + '캠퍼스', + '카테고리', + '학점', + '학년', + '전공', + '수업명', + '담당교수', + '학기', + '시간', + '수업구분', + '초과여부', +] as const; + function TimeTableModalFilter({ title, list, @@ -52,12 +94,14 @@ function TimeTableModalFilter({ handleFilterItem, parseFunc, }: TimeTableModalFilterProps) { + const originSet = new Set(origin); + return ( {list.map((listVal) => ( handleFilterItem(listVal)} > {listVal} @@ -67,70 +111,201 @@ function TimeTableModalFilter({ ); } -function TimeTableModalPeriodDropdown({ +const TimeTableModalPeriodDropdown = memo(function TimeTableModalPeriodDropdown< + T extends DayPeriod | NightPeriod, +>({ dayStatus, selectedPeriod, - dropdownItemHandler, -}: TimeTableModalPeriodDropdownProps) { + handlePeriodDropdownItem, +}: TimeTableModalPeriodDropdownProps) { const periodList = dayStatus === 'day' ? DAY_PERIOD_ARRAY : NIGHT_PERIOD_ARRAY; const selectedValue = ( -
- {selectedPeriod.map((period) => ( - - ))} -
+ <> + {selectedPeriod.length ? ( +
+ {selectedPeriod.map((period) => ( + { + event.stopPropagation(); + handlePeriodDropdownItem(period); + }} + value={period} + /> + ))} +
+ ) : ( +

시간을 선택하세요

+ )} + ); return ( - + {periodList.map(([period, obj]) => ( dropdownItemHandler(period as DayPeriod | NightPeriod)} + key={`dropdown-${period}`} + selected={selectedPeriod.includes(period as T)} + onClick={() => handlePeriodDropdownItem(period as T)} >{`${period} (${obj.string})`} ))} + {SPECIAL_PERIOD.map((period) => ( + handlePeriodDropdownItem(period as T)} + > + {period} + + ))} ); -} +}); -export default function TimeTableModal({ - dayStatus, - day, - period, -}: TimeTableModalProps) { +const TimeTableModalLectureTypeDropdown = memo( + function TimeTableModalLectureTypeDropdown({ + selectedLectureType, + handleLectureTypeDropdownItem, + }: TimeTableModalLectureTypeDropdownProps) { + const selectedValue = ( + <> + {selectedLectureType.length ? ( +
+ {selectedLectureType.map((lectureType) => ( + { + event.stopPropagation(); + handleLectureTypeDropdownItem(lectureType); + }} + value={LECTURE[lectureType]} + /> + ))} +
+ ) : ( +

강의 구분을 선택하세요

+ )} + + ); + + return ( + + {LECTURE_ARRAY.map(([lectureKey, lectureValue]) => ( + handleLectureTypeDropdownItem(lectureKey)} + > + {lectureValue} + + ))} + + ); + }, +); + +const TimeTableModalDropdownButton = memo( + function TimeTableModalDropdownButton({ + onClick, + value, + }: TimeTableModalDropdownButtonProps) { + return ( + + ); + }, +); + +const TimeTableModalInput = memo(function TimeTableModalInput() { + return ( + + + + ); +}); + +const TimeTableLectureTable = memo(function TimeTableLectureTable({ + lectureList, +}: TimeTableLectureTableProps) { + return ( +
+ + + + {LECTURE_TABLE_ROW_HEADER.map((header) => ( + + ))} + + + + + + + +
+ {header} +
+ {lectureList.length ? ( +

검색 결과가 없습니다.

+ ) : ( +

검색 결과가 없습니다.

+ )} +
+
+ ); +}); + +export default function TimeTableModal< + T extends DayPeriod | NightPeriod | SpecialPeriod, +>({ dayStatus, day, period }: TimeTableModalProps) { const { close } = useModalAction({ key: MODAL_KEY.timeTable }); const visible = useModalState({ key: MODAL_KEY.timeTable }).visible; - const [selectedGrade, setSelectedGrade] = useState(''); - const [selectedDay, setSelectedDay] = useState(day); + const [selectedRegion, setSelectedRegion] = useState([ + REGION.campus1, + REGION.campus2, + ]); + const [selectedGrade, setSelectedGrade] = useState([]); + const [selectedDay, setSelectedDay] = useState([day]); const [selectedPeriod, setSelectedPeriod] = useState< DayPeriod[] | NightPeriod[] >([period]); + const [selectedLectureType, setSelectedLectureType] = useState( + [], + ); useEffect(() => { - setSelectedGrade(''); - setSelectedDay(day as DayKor); + setSelectedGrade([]); + setSelectedRegion([REGION.campus1, REGION.campus2]); + setSelectedDay([day]); setSelectedPeriod([period]); + setSelectedLectureType([]); }, [day, period]); const handleFilterItem = useCallback( - (targetValue: T, targetAction: Dispatch>) => { - targetAction(targetValue); + ( + targetValue: T, + targetList: T[], + targetAction: Dispatch>, + ) => { + const targetSet = new Set(targetList); + + if (targetSet.has(targetValue)) { + targetSet.delete(targetValue); + } else { + targetSet.add(targetValue); + } + + targetAction(() => Array.from(targetSet)); }, [], ); @@ -157,26 +332,47 @@ export default function TimeTableModal({ {visible && ( - + str)} + origin={selectedRegion} + handleFilterItem={(region: Region) => + handleFilterItem(region, selectedRegion, setSelectedRegion) + } + /> - handleFilterItem(grade, setSelectedGrade) + handleFilterItem={(grade: Grade) => + handleFilterItem(grade, selectedGrade, setSelectedGrade) } /> handleFilterItem(day, setSelectedDay)} + handleFilterItem={(day) => + handleFilterItem(day, selectedDay, setSelectedDay) + } /> + + handleFilterItem( + lecture, + selectedLectureType, + setSelectedLectureType, + ) + } /> + + )}