Skip to content

Commit

Permalink
Merge pull request #92 from KGU-C-Lab/refactor/#91
Browse files Browse the repository at this point in the history
일정 코드 개선 완료
  • Loading branch information
gwansikk authored Apr 9, 2024
2 parents d05560d + dd31e47 commit fa6b59b
Show file tree
Hide file tree
Showing 23 changed files with 421 additions and 221 deletions.
16 changes: 15 additions & 1 deletion apps/member/src/api/schedule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ import type {
PaginationPramsType,
PaginationType,
} from '@type/api';
import type { ScheduleItem, ScheduleRegisterItem } from '@type/schedule';
import type {
ScheduleCollect,
ScheduleItem,
ScheduleRegisterItem,
} from '@type/schedule';

interface GetScheduleParams extends PaginationPramsType {
startDate: string;
Expand All @@ -30,6 +34,16 @@ export const getSchedule = async ({

return data;
};
/**
* 일정 모아보기
*/
export const getScheduleCollect = async () => {
const { data } = await server.get<BaseResponse<ScheduleCollect>>({
url: END_POINT.SCHEDULE_COLLECT,
});

return data;
};
/**
* 일정 등록
*/
Expand Down
77 changes: 0 additions & 77 deletions apps/member/src/components/calendar/Calendar/Calendar.tsx

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,36 +1,64 @@
import useModal from '@hooks/common/useModal';
import { formattedDate } from '@utils/date';
import type { ScheduleItem } from '@type/schedule';
import { useCallback } from 'react';
import { cn } from '@utils/string';
import dayjs from 'dayjs';

interface CalendarScheduleProps extends ScheduleItem {
day: dayjs.Dayjs;
}

const CalendarSchedule = ({
day,
title,
detail,
startDate,
endDate,
}: ScheduleItem) => {
}: CalendarScheduleProps) => {
const { openModal } = useModal();
const isDateDiff = dayjs(startDate).diff(endDate, 'd');

const onClickSchedule = (detail: string, start: string, end: string) => {
let date = `${formattedDate(start)} ~ ${formattedDate(end)}`;

if (start === end) {
const handleScheduleClick = useCallback(
(detail: string, start: string, end: string) => {
// 시작일과 종료일이 같은 경우, 종료일은 표시하지 않는다.
date = `${formattedDate(start)}`;
}
const date =
start === end
? `${formattedDate(start)}`
: `${formattedDate(start)} ~ ${formattedDate(end)}`;

openModal({
title: '📆 일정',
content: `내용: ${detail}\n일시: ${date}`,
});
};
openModal({
title: '📆 일정',
content: `일시: ${date}\n내용: ${detail}`,
});
},
[openModal],
);

return (
<p
className="cursor-pointer text-xs border-l-2 border-red-500 hover:bg-gray-50"
onClick={() => onClickSchedule(detail, startDate, endDate)}
<button
className={cn(
'w-full px-2 text-xs text-left truncate',
isDateDiff === 0 ? 'bg-blue-100 rounded' : 'bg-red-100',
{
'rounded-l bg-red-100':
isDateDiff !== 0 && day.isSame(startDate, 'date'),
},
{
'bg-red-100':
isDateDiff !== 0 &&
day.isAfter(startDate, 'date') &&
day.isBefore(endDate, 'date'),
},
{
'rounded-r bg-red-100':
isDateDiff !== 0 && day.isSame(endDate, 'date'),
},
)}
onClick={() => handleScheduleClick(detail, startDate, endDate)}
>
{title}
</p>
</button>
);
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { startTransition, useCallback, useState } from 'react';
import ArrowButton from '@components/common/ArrowButton/ArrowButton';
import Section from '@components/common/Section/Section';
import { useSchedule } from '@hooks/queries';
import { now, transformEvents } from '@utils/date';
import { cn } from '@utils/string';
import CalendarSchedule from '../CalendarSchedule/CalendarSchedule';

const today = now();

const CalendarSection = () => {
const [date, setDate] = useState(today);
const { data } = useSchedule({
startDate: date.startOf('month').format('YYYY-MM-DD'),
endDate: date.endOf('month').format('YYYY-MM-DD'),
});

const handleDateClick = useCallback((action: 'prev' | 'next' | 'today') => {
startTransition(() => {
setDate((current) => {
switch (action) {
case 'prev':
return current.subtract(1, 'month');
case 'next':
return current.add(1, 'month');
case 'today':
return today;
}
});
});
}, []);

const events = transformEvents(data.items);
const startDay = date.startOf('month').startOf('week'); // 현재 월의 첫 날짜의 주의 시작일
const endDay = date.endOf('month').endOf('week'); // 현재 월의 마지막 날짜의 주의 마지막일

const days = [];
let day = startDay;

while (day.isBefore(endDay)) {
const isToday = day.isSame(today, 'day');

days.push(
<td key={day.format('DD-MM-YYYY')} className="border h-28">
<div className="flex flex-col items-end h-full space-y-1">
<p
className={cn('text-sm text-center rounded-full size-5 m-1', {
'text-white bg-red-500': isToday,
})}
>
{day.format('D')}
</p>
{events[day.format('YYYY-MM-DD')]?.map((event) => (
<CalendarSchedule key={event.id} day={day} {...event} />
))}
</div>
</td>,
);
day = day.add(1, 'day');
}

const weeks = [];
for (let i = 0; i < days.length; i += 7) {
weeks.push(<tr key={i}>{days.slice(i, i + 7)}</tr>);
}

return (
<Section>
<Section.Header title={date.format('YYYY년 MM월')}>
<ArrowButton onClick={() => handleDateClick('prev')} />
<button
className="px-3 hover:underline"
onClick={() => handleDateClick('today')}
>
오늘
</button>
<ArrowButton direction="next" onClick={() => handleDateClick('next')} />
</Section.Header>
<Section.Body>
<table className="w-full table-fixed">
<thead>
<tr>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody className="border">{weeks}</tbody>
</table>
</Section.Body>
</Section>
);
};

export default CalendarSection;
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import Section from '@components/common/Section/Section';
import StatusCard from '@components/common/StatusCard/StatusCard';
import { useSchedule } from '@hooks/queries';
import { calculateDDay, findClosestEvent, transformEvents } from '@utils/date';
import { FcCalendar, FcLeave, FcOvertime, FcAlarmClock } from 'react-icons/fc';
import { useScheduleCollect } from '@hooks/queries/useScheduleCollect';

const CalendarStatusSection = () => {
const { data: yearData } = useScheduleCollect();
const { data: monthData } = useSchedule();

const closestEvent = findClosestEvent(transformEvents(monthData.items));
const closestDDay = closestEvent?.startDate
? `D-${calculateDDay(closestEvent.startDate)}`
: '이번 달에 남은 일정이 없어요';

return (
<Section>
<Section.Header
title="모아보기"
description="일정을 한 눈에 확인하세요"
/>
<Section.Body className="grid grid-cols-2 gap-4 md:grid-cols-4 break-keep">
<StatusCard
icon={<FcCalendar size={32} />}
label={`${yearData.totalScheduleCount}회`}
description="이번 연도 동아리의 모든 일정 횟수에요."
/>
<StatusCard
icon={<FcLeave size={32} />}
label={`${yearData.totalEventCount}회`}
description="이번 연도 총회, MT 등 중요도가 높은 행사 횟수에요."
/>
<StatusCard
icon={<FcOvertime size={32} />}
label={`${monthData.totalItems}회`}
description="이번 달 동아리 일정 횟수에요."
/>
<StatusCard
icon={<FcAlarmClock size={32} />}
label={closestDDay}
description="가장 가까운 일정까지 남은 일수에요."
/>
</Section.Body>
</Section>
);
};

export default CalendarStatusSection;
26 changes: 26 additions & 0 deletions apps/member/src/components/common/ArrowButton/ArrowButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { cn } from '@utils/string';
import { ComponentPropsWithRef, forwardRef } from 'react';
import { MdOutlineNavigateNext } from 'react-icons/md';

interface ArrowButtonProps extends ComponentPropsWithRef<'button'> {
direction?: 'prev' | 'next';
}

const ArrowButton = forwardRef<HTMLButtonElement, ArrowButtonProps>(
({ direction = 'prev', className, ...rest }, ref) => {
return (
<button
ref={ref}
className={cn('px-0.5 text-gray-500 border rounded', className)}
{...rest}
>
<MdOutlineNavigateNext
size={20}
className={direction === 'prev' ? 'rotate-180' : 'rotate-0'}
/>
</button>
);
},
);

export default ArrowButton;
2 changes: 1 addition & 1 deletion apps/member/src/components/common/Linker/Linker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Link } from 'react-router-dom';
interface LinkerProps extends PropsWithChildren {
to: string | Partial<Location>;
className?: string;
target: React.HTMLAttributeAnchorTarget;
target?: React.HTMLAttributeAnchorTarget;
}

const Linker = ({ to, target, className, children }: LinkerProps) => {
Expand Down
Loading

0 comments on commit fa6b59b

Please sign in to comment.