Skip to content

Commit

Permalink
refactor(time): apply useModalAction & useModalState hook at TimeTabl…
Browse files Browse the repository at this point in the history
…e components (#97)
  • Loading branch information
SWARVY committed Aug 9, 2024
1 parent 37c18b1 commit 76245d8
Show file tree
Hide file tree
Showing 5 changed files with 185 additions and 144 deletions.
112 changes: 61 additions & 51 deletions apps/time/src/widgets/time-table/ui/TimeTable.tsx
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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 (
<>
<table className="w-full table-auto border-collapse bg-white">
<thead className="w-full">
<tr>
<TimeTableItem rowHeader>교시</TimeTableItem>
{DAY_VALUE_ARRAY.map((day) => (
<TimeTableItem key={day} rowHeader>
{day}
<table className="w-full table-auto border-collapse bg-white">
<thead className="w-full">
<tr>
<TimeTableItem rowHeader>교시</TimeTableItem>
{DAY_VALUE_ARRAY.map((day) => (
<TimeTableItem key={day} rowHeader>
{day}
</TimeTableItem>
))}
</tr>
</thead>
<tbody>
{selectedSchedule.map(([period, time]) => {
return (
<tr key={period} className="text-center">
<TimeTableItem columnHeader>
<p>{period}교시</p>
<p className="hidden sm:block">
{getFormattedTime({
hour: time.start.hour,
minute: time.start.minute,
})}
~
{getFormattedTime({
hour: time.end.hour,
minute: time.end.minute,
})}
</p>
</TimeTableItem>
))}
</tr>
</thead>
<tbody>
{selectedSchedule.map(([period, time]) => {
return (
<tr key={period} className="text-center">
<TimeTableItem columnHeader>
<p>{period}교시</p>
<p className="hidden sm:block">
{getFormattedTime({
hour: time.start.hour,
minute: time.start.minute,
})}
~
{getFormattedTime({
hour: time.end.hour,
minute: time.end.minute,
})}
</p>
{Array.from({ length: 5 }, (_, idx) => (
<TimeTableItem key={`${period}-${idx + 1}`}>
<button
type="button"
className="size-full"
onClick={() => {
buttonClickAction({
period: period as DayPeriod | NightPeriod,
idx,
});
open();
}}
/>
</TimeTableItem>
{Array.from({ length: 5 }, (_, idx) => (
<TimeTableItem key={`${period}-${idx + 1}`}>
<button
type="button"
className="size-full"
onClick={() => action.buttonClickAction({ period, idx })}
/>
</TimeTableItem>
))}
</tr>
);
})}
</tbody>
</table>
</>
))}
</tr>
);
})}
</tbody>
</table>
);
}

export default memo(TimeTable);

TimeTable.displayName = 'TimeTable';
TimeTableItem.displayName = 'TimeTableItem';
23 changes: 15 additions & 8 deletions apps/time/src/widgets/time-table/ui/TimeTableFilter.tsx
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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 (
<div className="flex gap-4 rounded-full border border-gray-300 bg-white p-1">
<TimeTableFilterItem
selected={state.dayStatus === 'day'}
selected={dayStatus === 'day'}
onClick={() => onClickHandler('day')}
>
{DAY_STATUS.day}
</TimeTableFilterItem>
<TimeTableFilterItem
selected={state.dayStatus === 'night'}
selected={dayStatus === 'night'}
onClick={() => onClickHandler('night')}
>
{DAY_STATUS.night}
Expand Down
6 changes: 1 addition & 5 deletions apps/time/src/widgets/time-table/ui/TimeTableHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
import { memo } from 'react';

import { TimeTableFilter } from '@/widgets/time-table';

function TimeTableHeader() {
export default function TimeTableHeader() {
return (
<div className="flex">
<TimeTableFilter />
</div>
);
}

export default memo(TimeTableHeader);

TimeTableHeader.displayName = 'TimeTableHeader';
111 changes: 64 additions & 47 deletions apps/time/src/widgets/time-table/ui/TimeTableLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,85 +1,102 @@
'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,
useTimeTableParams,
} 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<TimeTableContextType>({
state: { dayStatus: 'day', period: '', day: '', modalVisible: false },
action: {
export const TimeTableStateContext = createContext<TimeTableStateContextType>({
dayStatus: 'day',
period: '' as DayPeriod | NightPeriod,
day: '',
});

export const TimeTableActionContext = createContext<TimeTableActionContextType>(
{
searchParamsAction: {} as SearchParamsActionType,
buttonClickAction: () => {},
modalCloseAction: () => {},
},
});
);

export default function TimeTableLayout() {
const { dayStatus, searchParamsAction } = useTimeTableParams();
const [visible, setVisible] = useState<boolean>(false);
const [selectedDay, setSelectedDay] = useState<DayKor>();
const [selectedPeriod, setSelectedPeriod] = useState<string>();
const [selectedPeriod, setSelectedPeriod] = useState<
DayPeriod | NightPeriod
>();
const [defaultStateContextValue, setDefaultStateContextValue] =
useState<TimeTableStateContextType>({
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 (
<div className="flex flex-col items-center justify-center gap-y-8 p-4">
<TimeTableContext.Provider value={defaultContextValue}>
<TimeTableHeader />
<TimeTable />
{visible && <TimeTableModal />}
</TimeTableContext.Provider>
<TimeTableStateContext.Provider value={defaultStateContextValue}>
<TimeTableActionContext.Provider value={defaultActionContextValue}>
<TimeTableHeader />
<TimeTable />
<TimeTableModal />
</TimeTableActionContext.Provider>
</TimeTableStateContext.Provider>
</div>
);
}
Loading

0 comments on commit 76245d8

Please sign in to comment.