diff --git a/apps/member/src/api/schedule.ts b/apps/member/src/api/schedule.ts index fc544b42..ac153804 100644 --- a/apps/member/src/api/schedule.ts +++ b/apps/member/src/api/schedule.ts @@ -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; @@ -30,6 +34,16 @@ export const getSchedule = async ({ return data; }; +/** + * 일정 모아보기 + */ +export const getScheduleCollect = async () => { + const { data } = await server.get>({ + url: END_POINT.SCHEDULE_COLLECT, + }); + + return data; +}; /** * 일정 등록 */ diff --git a/apps/member/src/components/calendar/CalendarStatusSection/CalendarStatusSection.tsx b/apps/member/src/components/calendar/CalendarStatusSection/CalendarStatusSection.tsx new file mode 100644 index 00000000..5db6c04d --- /dev/null +++ b/apps/member/src/components/calendar/CalendarStatusSection/CalendarStatusSection.tsx @@ -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 ( +
+ + + } + label={`${yearData.totalScheduleCount}회`} + description="이번 연도 동아리의 모든 일정 횟수에요." + /> + } + label={`${yearData.totalEventCount}회`} + description="이번 연도 총회, MT 등 중요도가 높은 행사 횟수에요." + /> + } + label={`${monthData.totalItems}회`} + description="이번 달 동아리 일정 횟수에요." + /> + } + label={closestDDay} + description="가장 가까운 일정까지 남은 일수에요." + /> + +
+ ); +}; + +export default CalendarStatusSection; diff --git a/apps/member/src/components/common/StatusCard/StatusCard.types.ts b/apps/member/src/components/common/StatusCard/StatusCard.types.ts index ac3b0d85..e7b8f806 100644 --- a/apps/member/src/components/common/StatusCard/StatusCard.types.ts +++ b/apps/member/src/components/common/StatusCard/StatusCard.types.ts @@ -1,5 +1,5 @@ export interface StatusCardProps { icon: React.ReactNode; - label: string; + label: string | number; description: string; } diff --git a/apps/member/src/constants/api.ts b/apps/member/src/constants/api.ts index 4730e37c..6df04f7d 100644 --- a/apps/member/src/constants/api.ts +++ b/apps/member/src/constants/api.ts @@ -5,8 +5,10 @@ export const API_BASE_URL: string = import.meta.env.VITE_API_BASE_URL; export const ACCESS_TOKEN_KEY = 'ACCESS_TOKEN'; export const REFRESH_TOKEN_KEY = 'REFRESH_TOKEN'; + export const FORM_DATA_KEY = 'multipartFile'; export const STORAGE_PERIOD = (period: number) => `?storagePeriod=${period}`; +export const MAX_PAGINATION_SIZE = 99999; export const END_POINT = { LOGIN_REISSUE: '/v1/login/reissue', @@ -35,6 +37,7 @@ export const END_POINT = { MY_BIRTHDAY: `/v1/members/birthday`, MY_ACTIVITY: `/v1/schedule/activity`, MAIN_SCHEDULE: `/v1/schedule`, + SCHEDULE_COLLECT: `/v1/schedule/collect`, MAIN_ACTIVITY_PHOTO: `/v1/activity-photos`, MEMBERSHIP_FEE: `/v1/membership-fees`, SHARED_ACCOUNT: `/v1/shared-accounts`, diff --git a/apps/member/src/constants/key.ts b/apps/member/src/constants/key.ts index 56fbade4..0ce8a96d 100644 --- a/apps/member/src/constants/key.ts +++ b/apps/member/src/constants/key.ts @@ -24,6 +24,7 @@ export const QUERY_KEY = { HIRE: 'Hire', BIRTHDAY: 'Birthday', SCHEDULE: 'Schedule', + SCHEDULE_COLLECT: 'ScheduleCollect', MAIN_ACTIVITY_PHOTO: 'MainActivityPhoto', COMMENTS: 'Comments', MEMBERSHIP_FEE: 'MembershipFee', diff --git a/apps/member/src/hooks/queries/useScheduleCollect.ts b/apps/member/src/hooks/queries/useScheduleCollect.ts new file mode 100644 index 00000000..08b93337 --- /dev/null +++ b/apps/member/src/hooks/queries/useScheduleCollect.ts @@ -0,0 +1,13 @@ +import { getScheduleCollect } from '@api/schedule'; +import { QUERY_KEY } from '@constants/key'; +import { useSuspenseQuery } from '@tanstack/react-query'; + +/** + * 일정 모아보기를 조회합니다. + */ +export const useScheduleCollect = () => { + return useSuspenseQuery({ + queryKey: [QUERY_KEY.SCHEDULE_COLLECT], + queryFn: getScheduleCollect, + }); +}; diff --git a/apps/member/src/pages/CalendarPage/CalendarPage.tsx b/apps/member/src/pages/CalendarPage/CalendarPage.tsx index 557dd4a4..1f03acaf 100644 --- a/apps/member/src/pages/CalendarPage/CalendarPage.tsx +++ b/apps/member/src/pages/CalendarPage/CalendarPage.tsx @@ -1,52 +1,19 @@ -import { startTransition, useState } from 'react'; +import { Suspense } from 'react'; import Content from '@components/common/Content/Content'; import Header from '@components/common/Header/Header'; -import Section from '@components/common/Section/Section'; -import Calendar from '@components/calendar/Calendar/Calendar'; -import { now } from '@utils/date'; -import { Dayjs } from 'dayjs'; - -const today = now(); +import CalendarSection from '@components/calendar/CalendarSection/CalendarSection'; +import CalendarStatusSection from '@components/calendar/CalendarStatusSection/CalendarStatusSection'; const CalendarPage = () => { - const [date, setDate] = useState(today); - const onClickPrev = () => { - startTransition(() => { - setDate((prev) => prev.subtract(1, 'month')); - }); - }; - - const onClickNext = () => { - startTransition(() => { - setDate((prev) => prev.add(1, 'month')); - }); - }; - - const onClickToday = () => { - startTransition(() => { - setDate(today); - }); - }; - return (
-
- - - - - - - - -
+ + + + + + ); }; diff --git a/apps/member/src/types/schedule.ts b/apps/member/src/types/schedule.ts index fefb463b..ca3b039b 100644 --- a/apps/member/src/types/schedule.ts +++ b/apps/member/src/types/schedule.ts @@ -1,3 +1,5 @@ +type SchedulePriority = 'HIGH' | 'MIDDLE' | 'LOW'; + export interface ScheduleItem { id: number; title: string; @@ -5,6 +7,7 @@ export interface ScheduleItem { activityName: string | null; startDate: string; endDate: string; + priority: SchedulePriority; } export interface ScheduleRegisterItem { @@ -15,3 +18,8 @@ export interface ScheduleRegisterItem { endDateTime: string; activityGroupId?: number; } + +export interface ScheduleCollect { + totalScheduleCount: number; + totalEventCount: number; +}