Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions frontend/src/components/Calendar/Core/SelectedWeek.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { weekStyle } from './index.css';
import { WeekCell } from './WeekCell';

export const SelectedWeek = () => {
const { selected, dates, handleChangeWeek } = useCalendarContext();
const { selected, dates } = useCalendarContext();
const today = new Date();

return (
Expand All @@ -22,7 +22,6 @@ export const SelectedWeek = () => {
day={day}
isToday={isSameDate(dates[i], today)}
key={day}
onClickHandler={() => handleChangeWeek(dates[i])}
selected={isSameDate(dates[i], selected)}
/>)}
</div>
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/Calendar/Core/TimeControlButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export const TimeControlButton = ({ type }: { type: 'prev' | 'next' | 'today' })
className={timeControlButtonStyle({ order: 'first' })}
onClick={handleClickPrevWeek}
>
<ChevronLeft fill={vars.color.Ref.Netural[600]} />
<ChevronLeft clickable fill={vars.color.Ref.Netural[600]} />
</button>
);
case 'next':
Expand All @@ -25,7 +25,7 @@ export const TimeControlButton = ({ type }: { type: 'prev' | 'next' | 'today' })
className={timeControlButtonStyle({ order: 'last' })}
onClick={handleClickNextWeek}
>
<ChevronRight fill={vars.color.Ref.Netural[600]} />
<ChevronRight clickable fill={vars.color.Ref.Netural[600]} />
</button>
);
case 'today':
Expand Down
7 changes: 2 additions & 5 deletions frontend/src/components/Calendar/Core/WeekCell.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import type { MouseEvent } from 'react';

import type { WEEKDAY } from '@/constants/date';

import { Text } from '../../Text';
Expand All @@ -10,10 +8,9 @@ interface WeekCellProps {
date: Date;
isToday: boolean;
selected: boolean;
onClickHandler: (event: MouseEvent<HTMLDivElement>) => void;
}

export const WeekCell = ({ day, date, isToday, selected, onClickHandler }: WeekCellProps) => {
export const WeekCell = ({ day, date, isToday, selected }: WeekCellProps) => {
const dayStyleName = (day: WEEKDAY) => {
switch (day) {
case 'SUN':
Expand All @@ -31,7 +28,7 @@ export const WeekCell = ({ day, date, isToday, selected, onClickHandler }: WeekC
day: dayStyleName(day),
state: selected ? 'selected' : 'default',
})}
onClick={onClickHandler}
key={selected ? Date.now() : ''}
>
<Text typo='b3M'>{day}</Text>
<div className={weekCellBoxStyle({ day: isToday ? 'today' : dayStyleName(day) })}>
Expand Down
5 changes: 3 additions & 2 deletions frontend/src/components/Calendar/Core/index.css.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { style } from '@vanilla-extract/css';
import { recipe } from '@vanilla-extract/recipes';

import { fadeHighlightProps } from '@/theme/animation.css';

import { vars } from '../../../theme/index.css';

export const containerStyle = style({
Expand Down Expand Up @@ -64,8 +66,6 @@ export const weekCellStyle = recipe({
justifyContent: 'center',
alignItems: 'center',
gap: vars.spacing[100],

cursor: 'pointer',
},
variants: {
day: {
Expand All @@ -82,6 +82,7 @@ export const weekCellStyle = recipe({
state: {
selected: {
backgroundColor: vars.color.Ref.Primary[50],
...fadeHighlightProps,
},
default: {
backgroundColor: vars.color.Ref.Netural.White,
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/Calendar/Header/CalendarHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isSameDate, isWeekend } from '@/utils/date';
import { isSameDate } from '@/utils/date';

import { useCalendarContext } from '../context/CalendarContext';
import { CalendarCell } from '../Table/CalendarCell';
Expand All @@ -13,7 +13,7 @@ export const CalendarHeader = () => {
<SideCell time='all' />
{dates.map((date) =>
<CalendarCell
holiday={isWeekend(date)}
date={date}
key={date.getTime()}
selected={isSameDate(selected, date)}
time='all'
Expand Down
22 changes: 18 additions & 4 deletions frontend/src/components/Calendar/Table/CalendarCell.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@

import type { Time } from '../../../constants/date';
import { Flex } from '@/components/Flex';
import { MINUTES, type Time } from '@/constants/date';
import { isWeekend } from '@/utils/date';

import { CalendarDetailCell } from './CalendarDetailCell';
import { cellStyle } from './index.css';

interface CalendarCellProps {
holiday?: boolean;
date: Date;
time: Time;
selected: boolean;
}

export const CalendarCell = ({ holiday = false, time, selected }: CalendarCellProps) => {
export const CalendarCell = ({ date, time, selected }: CalendarCellProps) => {
const formatTimeToStyle = (time: Time) => {
if (time === 'empty') return 'empty';
if (time === 'all') return 'all';
Expand All @@ -19,13 +23,23 @@ export const CalendarCell = ({ holiday = false, time, selected }: CalendarCellPr
<div
aria-selected={selected}
className={cellStyle({
day: holiday ? 'holiday' : 'default',
day: isWeekend(date) ? 'holiday' : 'default',
time: formatTimeToStyle(time),
state: selected ? 'selected' : 'default',
})}
role='gridcell'
tabIndex={0}
>
{(time === 'empty' || time === 'all') ? null : (
<Flex direction='column' height='100%'>
{MINUTES.map((minute) => {
const newDate = new Date(date);
newDate.setHours(time);
newDate.setMinutes(minute);
return <CalendarDetailCell date={newDate} key={newDate.getTime()} />;
})}
</Flex>
)}
</div>
);
};
15 changes: 8 additions & 7 deletions frontend/src/components/Calendar/Table/CalendarDay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,30 @@ import { CalendarCell } from './CalendarCell';
import { dayStyle } from './index.css';

interface CalendarDayProps {
holiday?: boolean;
date: Date;
selected: boolean;
}

export const CalendarDay = memo(({ holiday = false, selected }: CalendarDayProps) => (
export const CalendarDay = memo(({ date, selected }: CalendarDayProps) => (
<div className={dayStyle}>
<CalendarCell
holiday={holiday}
date={date}
selected={selected}
time='all'
/>
<CalendarCell
holiday={holiday}
date={date}
selected={selected}
time='empty'
/>
{TIMES.map((time) =>
{TIMES.map((time) => (
<CalendarCell
holiday={holiday}
date={date}
key={time}
selected={selected}
time={time}
/>,
/>
),
)}
</div>
));
36 changes: 36 additions & 0 deletions frontend/src/components/Calendar/Table/CalendarDetailCell.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { isDateInRange } from '@/utils/date';

import { useTimeTableContext } from '../context/TimeTableContext';
import { cellDetailStyle } from './index.css';

export const CalendarDetailCell = ({ date }: { date: Date }) => {
const {
selectedStartTime,
selectedEndTime,
doneStartTime,
doneEndTime,
handleMouseDown,
handleMouseEnter,
handleMouseUp,
handleClick,
} = useTimeTableContext();
const selected = isDateInRange(date, selectedStartTime, selectedEndTime);
const done = isDateInRange(date, doneStartTime, doneEndTime);

const stateStyle = (() => {
if (done) return 'done';
if (selected) return 'selected';
return 'default';
})();

return (
<div
className={cellDetailStyle({ state: stateStyle })}
key={date.getTime()}
onClick={()=>handleClick(date)}
onMouseDown={()=>handleMouseDown(date)}
onMouseEnter={()=>handleMouseEnter(date)}
onMouseUp={handleMouseUp}
/>
);
};
25 changes: 23 additions & 2 deletions frontend/src/components/Calendar/Table/index.css.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { style } from '@vanilla-extract/css';
import { recipe } from '@vanilla-extract/recipes';

import { fadeHighlightProps } from '@/theme/animation.css';

import { vars } from '../../../theme/index.css';

export const containerStyle = style({
Expand Down Expand Up @@ -31,6 +33,7 @@ export const sideStyle = style({
export const cellStyle = recipe({
base: {
width: '100%',
boxShadow: `inset 0 0 0 0.5px ${vars.color.Ref.Netural[200]}`,
},
variants: {
day: {
Expand All @@ -52,14 +55,32 @@ export const cellStyle = recipe({
height: 66,
},
},
state: {
selected: {
backgroundColor: vars.color.Ref.Primary[50],
...fadeHighlightProps,
},
default: {},
},
},
});

export const cellDetailStyle = recipe({
base: {
width: '100%',
flexGrow: 1,
cursor: 'pointer',
},
variants: {
state: {
selected: {
backgroundColor: vars.color.Ref.Primary[50],
boxShadow: `inset 0 0 0 0.5px ${vars.color.Ref.Primary[100]}`,
},
default: {
boxShadow: `inset 0 0 0 0.5px ${vars.color.Ref.Netural[200]}`,
done: {
backgroundColor: vars.color.Ref.Primary[50],
},
default: {},
},
},
});
Expand Down
10 changes: 7 additions & 3 deletions frontend/src/components/Calendar/Table/index.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@

import { isSameDate, isWeekend } from '@/utils/date';
import { useClickOutside } from '@/hooks/useClickOutside';
import { isSameDate } from '@/utils/date';

import { useCalendarContext } from '../context/CalendarContext';
import { useTimeTableContext } from '../context/TimeTableContext';
import { CalendarDay } from './CalendarDay';
import { CalendarSide } from './CalendarSide';
import { containerStyle, contentsStyle } from './index.css';

export const CalendarTable = () => {
const { selected, dates } = useCalendarContext();
const { reset } = useTimeTableContext();
const calendarTableRef = useClickOutside<HTMLDivElement>(reset);

return(
<div className={containerStyle}>
<div className={contentsStyle}>
<div className={contentsStyle} ref={calendarTableRef}>
<CalendarSide />
{dates.map((date) =>
<CalendarDay
holiday={isWeekend(date)}
date={date}
key={date.getTime()}
selected={isSameDate(selected, date)}
/>)}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { createContext } from 'react';

import { useSafeContext } from '@/hooks/useSafeContext';
import type { TimeInfo } from '@/hooks/useSelectTime';

export const TimeTableContext = createContext<TimeInfo | null>(null);

export const useTimeTableContext = (): TimeInfo => useSafeContext(TimeTableContext);
14 changes: 14 additions & 0 deletions frontend/src/components/Calendar/context/TimeTableProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import type { PropsWithChildren } from 'react';

import { useSelectTime } from '@/hooks/useSelectTime';

import { TimeTableContext } from './TimeTableContext';

export const TimeTableProvider = ({ children }: PropsWithChildren) => {
const times = useSelectTime();
return (
<TimeTableContext.Provider value={times}>
{children}
</TimeTableContext.Provider>
);
};
11 changes: 7 additions & 4 deletions frontend/src/components/Calendar/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { CalendarProvider } from './context/CalendarProvider';
import { TimeTableProvider } from './context/TimeTableProvider';
import { Core } from './Core';
import { CalendarHeader } from './Header/CalendarHeader';
import { wrapperStyle } from './index.css';
Expand All @@ -7,9 +8,11 @@ import { CalendarTable } from './Table';
export const Calendar = () => (
<CalendarProvider>
<Core />
<div className={wrapperStyle}>
<CalendarHeader />
<CalendarTable />
</div>
<TimeTableProvider>
<div className={wrapperStyle}>
<CalendarHeader />
<CalendarTable />
</div>
</TimeTableProvider>
</CalendarProvider>
);
4 changes: 2 additions & 2 deletions frontend/src/components/Notification/GlobalNotification.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { createPortal } from 'react-dom';

import type { NotificationWithId } from '@/hooks/useNotification';
import { fadeInAndOut } from '@/theme/animation.css';
import { fadeInAndOutStyle } from '@/theme/animation.css';

import { Notification } from '.';
import { notificationsStyle } from './index.css';
Expand All @@ -14,7 +14,7 @@ export const GlobalNotification = ({ notifications }: { notifications: Notificat
{notifications
.map((noti) =>
<Notification
className={fadeInAndOut}
className={fadeInAndOutStyle}
key={noti.id}
{...noti}
/>)}
Expand Down
8 changes: 6 additions & 2 deletions frontend/src/constants/date.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ export type Time = number | 'all' | 'empty';

export type WEEKDAY = 'SUN' | 'MON' | 'TUE' | 'WED' | 'THU' | 'FRI' | 'SAT';

export const TIMES: readonly Time[] = Object.freeze(
export const TIMES: readonly number[] = Object.freeze(
new Array(24).fill(0)
.map((_, i) => i));

Expand All @@ -15,4 +15,8 @@ export const WEEK_MAP: Record<string, string> = Object.freeze({
3: '셋째주',
4: '넷째주',
5: '다섯째주',
});
});

export const MINUTES = Object.freeze(
new Array(4).fill(0)
.map((_, i) => i * 15));
Loading