diff --git a/apps/time/src/widgets/time-table/ui/TimeTable.tsx b/apps/time/src/widgets/time-table/ui/TimeTable.tsx index 9471a8ec..fc89f307 100644 --- a/apps/time/src/widgets/time-table/ui/TimeTable.tsx +++ b/apps/time/src/widgets/time-table/ui/TimeTable.tsx @@ -1,16 +1,22 @@ 'use client'; -import { ReactNode, memo, useContext } from 'react'; +import { ReactNode, useContext } from 'react'; import { cn } from '@clab/utils'; -import { DAY_VALUE_ARRAY } from '@/shared/constants'; +import { DAY_VALUE_ARRAY, MODAL_KEY } from '@/shared/constants'; +import { useModalAction } from '@/shared/hooks'; import { DAY_PERIOD_ARRAY, + DayPeriod, NIGHT_PERIOD_ARRAY, + NightPeriod, getFormattedTime, } from '@/widgets/time-table'; -import { TimeTableContext } from '@/widgets/time-table/ui/TimeTableLayout'; +import { + TimeTableActionContext, + TimeTableStateContext, +} from '@/widgets/time-table/ui/TimeTableLayout'; interface TimeTableItemProps { rowHeader?: boolean; @@ -39,61 +45,65 @@ function TimeTableItem({ ); } -function TimeTable() { - const { state, action } = useContext(TimeTableContext); +export default function TimeTable() { + const { dayStatus } = useContext(TimeTableStateContext); + const { buttonClickAction } = useContext(TimeTableActionContext); const selectedSchedule = - state.dayStatus === 'day' ? DAY_PERIOD_ARRAY : NIGHT_PERIOD_ARRAY; + dayStatus === 'day' ? DAY_PERIOD_ARRAY : NIGHT_PERIOD_ARRAY; + const { open } = useModalAction({ key: MODAL_KEY.timeTable }); return ( - <> - - - - 교시 - {DAY_VALUE_ARRAY.map((day) => ( - - {day} +
+ + + 교시 + {DAY_VALUE_ARRAY.map((day) => ( + + {day} + + ))} + + + + {selectedSchedule.map(([period, time]) => { + return ( + + +

{period}교시

+

+ {getFormattedTime({ + hour: time.start.hour, + minute: time.start.minute, + })} + ~ + {getFormattedTime({ + hour: time.end.hour, + minute: time.end.minute, + })} +

- ))} - - - - {selectedSchedule.map(([period, time]) => { - return ( - - -

{period}교시

-

- {getFormattedTime({ - hour: time.start.hour, - minute: time.start.minute, - })} - ~ - {getFormattedTime({ - hour: time.end.hour, - minute: time.end.minute, - })} -

+ {Array.from({ length: 5 }, (_, idx) => ( + +
- ); - })} - -
- + ))} + + ); + })} + + ); } -export default memo(TimeTable); - TimeTable.displayName = 'TimeTable'; TimeTableItem.displayName = 'TimeTableItem'; diff --git a/apps/time/src/widgets/time-table/ui/TimeTableFilter.tsx b/apps/time/src/widgets/time-table/ui/TimeTableFilter.tsx index 59477b8b..ae6c971a 100644 --- a/apps/time/src/widgets/time-table/ui/TimeTableFilter.tsx +++ b/apps/time/src/widgets/time-table/ui/TimeTableFilter.tsx @@ -1,11 +1,14 @@ 'use client'; -import { ReactNode, useContext } from 'react'; +import { ReactNode, useCallback, useContext } from 'react'; import { cn } from '@clab/utils'; import { DAY_STATUS, DayStatus } from '@/widgets/time-table'; -import { TimeTableContext } from '@/widgets/time-table/ui/TimeTableLayout'; +import { + TimeTableActionContext, + TimeTableStateContext, +} from '@/widgets/time-table/ui/TimeTableLayout'; interface TimeTableFilterItemProps { children: ReactNode; @@ -33,22 +36,26 @@ function TimeTableFilterItem({ } export default function TimeTableFilter() { - const { state, action } = useContext(TimeTableContext); + const { dayStatus } = useContext(TimeTableStateContext); + const { searchParamsAction } = useContext(TimeTableActionContext); - const onClickHandler = (dayStatus: DayStatus) => { - action.searchParamsAction.set('classType', dayStatus); - }; + const onClickHandler = useCallback( + (status: DayStatus) => { + searchParamsAction.set('classType', status); + }, + [searchParamsAction], + ); return (
onClickHandler('day')} > {DAY_STATUS.day} onClickHandler('night')} > {DAY_STATUS.night} diff --git a/apps/time/src/widgets/time-table/ui/TimeTableHeader.tsx b/apps/time/src/widgets/time-table/ui/TimeTableHeader.tsx index 5412cc26..505783e6 100644 --- a/apps/time/src/widgets/time-table/ui/TimeTableHeader.tsx +++ b/apps/time/src/widgets/time-table/ui/TimeTableHeader.tsx @@ -1,8 +1,6 @@ -import { memo } from 'react'; - import { TimeTableFilter } from '@/widgets/time-table'; -function TimeTableHeader() { +export default function TimeTableHeader() { return (
@@ -10,6 +8,4 @@ function TimeTableHeader() { ); } -export default memo(TimeTableHeader); - TimeTableHeader.displayName = 'TimeTableHeader'; diff --git a/apps/time/src/widgets/time-table/ui/TimeTableLayout.tsx b/apps/time/src/widgets/time-table/ui/TimeTableLayout.tsx index a90eefcb..738ed7e0 100644 --- a/apps/time/src/widgets/time-table/ui/TimeTableLayout.tsx +++ b/apps/time/src/widgets/time-table/ui/TimeTableLayout.tsx @@ -1,11 +1,19 @@ 'use client'; -import { createContext, useCallback, useState } from 'react'; +import { + createContext, + useCallback, + useEffect, + useMemo, + useState, +} from 'react'; import { DAY_VALUE_ARRAY } from '@/shared/constants'; import { DayKor } from '@/shared/types'; import { + DayPeriod, DayStatus, + NightPeriod, TimeTable, TimeTableHeader, TimeTableModal, @@ -13,73 +21,82 @@ import { } from '@/widgets/time-table'; import { SearchParamsActionType } from '@/widgets/time-table/model/hooks/useTimeTableParams'; -interface TimeTableContextType { - state: { - dayStatus: DayStatus; - period: string; - day: DayKor | ''; - modalVisible: boolean; - }; - action: { - searchParamsAction: SearchParamsActionType; - buttonClickAction: ({ - period, - idx, - }: { - period: string; - idx: number; - }) => void; - modalCloseAction: () => void; - }; +interface TimeTableStateContextType { + dayStatus: DayStatus; + period: DayPeriod | NightPeriod; + day: DayKor | ''; +} + +interface TimeTableActionContextType { + searchParamsAction: SearchParamsActionType; + buttonClickAction: ({ + period, + idx, + }: { + period: DayPeriod | NightPeriod; + idx: number; + }) => void; } -export const TimeTableContext = createContext({ - state: { dayStatus: 'day', period: '', day: '', modalVisible: false }, - action: { +export const TimeTableStateContext = createContext({ + dayStatus: 'day', + period: '' as DayPeriod | NightPeriod, + day: '', +}); + +export const TimeTableActionContext = createContext( + { searchParamsAction: {} as SearchParamsActionType, buttonClickAction: () => {}, - modalCloseAction: () => {}, }, -}); +); export default function TimeTableLayout() { const { dayStatus, searchParamsAction } = useTimeTableParams(); - const [visible, setVisible] = useState(false); const [selectedDay, setSelectedDay] = useState(); - const [selectedPeriod, setSelectedPeriod] = useState(); + const [selectedPeriod, setSelectedPeriod] = useState< + DayPeriod | NightPeriod + >(); + const [defaultStateContextValue, setDefaultStateContextValue] = + useState({ + dayStatus, + period: '' as DayPeriod | NightPeriod, + day: '', + }); const buttonClickAction = useCallback( - ({ period, idx }: { period: string; idx: number }) => { + ({ period, idx }: { period: DayPeriod | NightPeriod; idx: number }) => { setSelectedDay(DAY_VALUE_ARRAY[idx]); setSelectedPeriod(period); - setVisible(true); }, - [setSelectedDay, setSelectedPeriod, setVisible], + [], ); - const modalCloseAction = useCallback(() => { - setSelectedDay(undefined); - setSelectedPeriod(undefined); - setVisible(false); - }, [setVisible]); - - const defaultContextValue: TimeTableContextType = { - state: { + useEffect(() => { + setDefaultStateContextValue({ dayStatus, - period: selectedPeriod ?? '', + period: selectedPeriod!, day: selectedDay ?? '', - modalVisible: visible, - }, - action: { searchParamsAction, buttonClickAction, modalCloseAction }, - }; + }); + }, [dayStatus, selectedPeriod, selectedDay]); + + const defaultActionContextValue: TimeTableActionContextType = useMemo( + () => ({ + searchParamsAction, + buttonClickAction, + }), + [searchParamsAction, buttonClickAction], + ); return (
- - - - {visible && } - + + + + + + +
); } diff --git a/apps/time/src/widgets/time-table/ui/TimeTableModal.tsx b/apps/time/src/widgets/time-table/ui/TimeTableModal.tsx index e093dd58..53644af3 100644 --- a/apps/time/src/widgets/time-table/ui/TimeTableModal.tsx +++ b/apps/time/src/widgets/time-table/ui/TimeTableModal.tsx @@ -5,12 +5,14 @@ import { SetStateAction, useCallback, useContext, + useEffect, useState, } from 'react'; import { CloseOutline } from '@clab/icon'; -import { DAY_VALUE_ARRAY } from '@/shared/constants'; +import { DAY_VALUE_ARRAY, MODAL_KEY } from '@/shared/constants'; +import { useModalAction, useModalState } from '@/shared/hooks'; import { DayKor } from '@/shared/types'; import { Modal } from '@/shared/ui'; import { @@ -23,7 +25,7 @@ import { NIGHT_PERIOD_ARRAY, NightPeriod, } from '@/widgets/time-table'; -import { TimeTableContext } from '@/widgets/time-table/ui/TimeTableLayout'; +import { TimeTableStateContext } from '@/widgets/time-table/ui/TimeTableLayout'; interface TimeTableModalFilterProps { title: string; @@ -104,12 +106,19 @@ function TimeTableModalPeriodDropdown({ } export default function TimeTableModal() { - const { state, action } = useContext(TimeTableContext); + const { dayStatus, day, period } = useContext(TimeTableStateContext); + const { close } = useModalAction({ key: MODAL_KEY.timeTable }); + const visible = useModalState({ key: MODAL_KEY.timeTable }); const [selectedGrade, setSelectedGrade] = useState(''); - const [selectedDay, setSelectedDay] = useState(state.day as DayKor); + const [selectedDay, setSelectedDay] = useState(day as DayKor); const [selectedPeriod, setSelectedPeriod] = useState< DayPeriod[] | NightPeriod[] - >([state.period] as DayPeriod[] | NightPeriod[]); + >([period]); + + useEffect(() => { + setSelectedDay(day as DayKor); + setSelectedPeriod([period]); + }, [day, period]); const filterItemHandler = useCallback( (targetValue: T, targetAction: Dispatch>) => { @@ -136,33 +145,35 @@ export default function TimeTableModal() { ); return ( - - - - - filterItemHandler(grade, setSelectedGrade) - } - /> - filterItemHandler(day, setSelectedDay)} - /> - - - + <> + {visible && ( + + + + + filterItemHandler(grade, setSelectedGrade) + } + /> + + filterItemHandler(day, setSelectedDay) + } + /> + + + + )} + ); }