diff --git a/frontend/src/apis/schedule.ts b/frontend/src/apis/schedule.ts index 2cbfd7475..80bec682b 100644 --- a/frontend/src/apis/schedule.ts +++ b/frontend/src/apis/schedule.ts @@ -11,6 +11,18 @@ export const fetchSchedules = ( ); }; +export const fetchScheduleById = (teamPlaceId: number, scheduleId: number) => { + return http.get( + `/api/team-place/${teamPlaceId}/calendar/schedules/${scheduleId}`, + ); +}; + +export const deleteSchedule = (teamPlaceId: number, scheduleId: number) => { + return http.delete( + `/api/team-place/${teamPlaceId}/calendar/schedules/${scheduleId}`, + ); +}; + export const sendSchedule = (teamPlaceId: number, body: ScheduleWithoutId) => { return http.post(`/api/team-place/${teamPlaceId}/calendar/schedules`, body); }; diff --git a/frontend/src/components/Calendar/Calendar.tsx b/frontend/src/components/Calendar/Calendar.tsx index 8a6a93069..c654ebd85 100644 --- a/frontend/src/components/Calendar/Calendar.tsx +++ b/frontend/src/components/Calendar/Calendar.tsx @@ -6,21 +6,27 @@ import useCalendar from '~/hooks/useCalendar'; import * as S from './Calendar.styled'; import ScheduleBar from '~/components/ScheduleBar/ScheduleBar'; import { generateScheduleBars } from '~/utils/generateScheduleBars'; -import { useSchedules } from '~/hooks/queries/useSchedules'; -import { DAYS_OF_WEEK } from '~/constants/calendar'; +import ScheduleModal from '~/components/ScheduleModal/ScheduleModal'; +import { useScheduleModal } from '~/hooks/schedule/useScheduleModal'; import { useModal } from '~/hooks/useModal'; +import { DAYS_OF_WEEK } from '~/constants/calendar'; import ScheduleAddModal from '~/components/ScheduleAddModal/ScheduleAddModal'; +import { useFetchSchedules } from '~/hooks/queries/useFetchSchedules'; const Calendar = () => { const { year, month, calendar, - handlers: { handlePrevButtonClick, handleNextButtonClick }, } = useCalendar(); - const { schedules } = useSchedules(1, year, month); + const { schedules } = useFetchSchedules(1, year, month); const { isModalOpen, openModal } = useModal(); + const { + modalScheduleId, + modalPosition, + handlers: { onScheduleModalOpen }, + } = useScheduleModal(); if (schedules === undefined) { return null; @@ -67,11 +73,27 @@ const Calendar = () => { <> {scheduleBars.map((scheduleBar) => { - const { id, row, ...rest } = scheduleBar; + const { id, row, column, level, scheduleId, ...rest } = + scheduleBar; if (row === rowIndex) return ( - + + onScheduleModalOpen({ + scheduleId, + row, + column, + level, + }) + } + {...rest} + /> ); return null; @@ -95,6 +117,9 @@ const Calendar = () => { {isModalOpen && } + {isModalOpen && ( + + )} ); }; diff --git a/frontend/src/components/ScheduleBar/ScheduleBar.stories.tsx b/frontend/src/components/ScheduleBar/ScheduleBar.stories.tsx index aebcfeb7a..8a1dced5d 100644 --- a/frontend/src/components/ScheduleBar/ScheduleBar.stories.tsx +++ b/frontend/src/components/ScheduleBar/ScheduleBar.stories.tsx @@ -20,5 +20,6 @@ export const Default: Story = { column: 2, duration: 3, level: 0, + onScheduleModalOpen: () => console.log('click'), }, }; diff --git a/frontend/src/components/ScheduleBar/ScheduleBar.styled.ts b/frontend/src/components/ScheduleBar/ScheduleBar.styled.ts index 5a38de621..6833c3dd5 100644 --- a/frontend/src/components/ScheduleBar/ScheduleBar.styled.ts +++ b/frontend/src/components/ScheduleBar/ScheduleBar.styled.ts @@ -17,7 +17,9 @@ export const Inner = styled.div>` height: 100%; background-color: ${({ color }) => color}; + border-radius: 4px; + filter: brightness(${({ level }) => 1 + level * 0.5}); - border-radius: 4px; + cursor: pointer; `; diff --git a/frontend/src/components/ScheduleBar/ScheduleBar.tsx b/frontend/src/components/ScheduleBar/ScheduleBar.tsx index a797deb51..dca6707b6 100644 --- a/frontend/src/components/ScheduleBar/ScheduleBar.tsx +++ b/frontend/src/components/ScheduleBar/ScheduleBar.tsx @@ -9,17 +9,18 @@ export interface ScheduleBarProps { duration: number; level: number; color?: string; + onScheduleModalOpen?: () => void; } const ScheduleBar = (props: ScheduleBarProps) => { - const { color = '#516FFF', title, ...rest } = props; + const { color = '#516FFF', title, onScheduleModalOpen, ...rest } = props; return ( alert(title)} > diff --git a/frontend/src/components/ScheduleModal/ScheduleModal.stories.tsx b/frontend/src/components/ScheduleModal/ScheduleModal.stories.tsx index 4388f9361..cc35566ec 100644 --- a/frontend/src/components/ScheduleModal/ScheduleModal.stories.tsx +++ b/frontend/src/components/ScheduleModal/ScheduleModal.stories.tsx @@ -1,7 +1,6 @@ import type { Meta, StoryObj } from '@storybook/react'; import { useModal } from '~/hooks/useModal'; import ScheduleModal from '~/components/ScheduleModal/ScheduleModal'; -import { useRef, useState } from 'react'; import { arrayOf } from '~/utils/arrayOf'; const meta = { @@ -16,38 +15,37 @@ type Story = StoryObj; export const Default: Story = { render: () => { const { openModal } = useModal(); - const refs = arrayOf(5).map(() => useRef(null)); - const [targetRef, setTargetRef] = useState>( - refs[0], - ); - - const handleOpen = (index: number) => { + const handleOpen = () => { openModal(); - setTargetRef(refs[index]); }; return ( <> {arrayOf(5).map((_, index) => { return ( -
handleOpen(index)} - > +
handleOpen()}> 모달 열기
); })} - + ); }, args: { - id: 1, - // eslint-disable-next-line - //@ts-ignore - targetRef: null, + scheduleId: 1, + position: { + row: 0, + column: 0, + level: 0, + }, }, }; diff --git a/frontend/src/components/ScheduleModal/Schedule.styled.ts b/frontend/src/components/ScheduleModal/ScheduleModal.styled.ts similarity index 95% rename from frontend/src/components/ScheduleModal/Schedule.styled.ts rename to frontend/src/components/ScheduleModal/ScheduleModal.styled.ts index 906cc784b..f01419b05 100644 --- a/frontend/src/components/ScheduleModal/Schedule.styled.ts +++ b/frontend/src/components/ScheduleModal/ScheduleModal.styled.ts @@ -18,6 +18,7 @@ export const Container = styled.div` 0 15px 25px #1b1d1f33, 0 5px 10px #1b1d1f1f; `; + export const Backdrop = styled.div` position: fixed; top: 0; @@ -45,14 +46,6 @@ export const TeamColor = styled.div` background-color: ${({ theme }) => theme.color.PRIMARY}; `; -export const TeamName = css` - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - - max-width: 200px; -`; - export const MenuWrapper = styled.div` display: flex; align-items: center; @@ -64,7 +57,15 @@ export const PeriodWrapper = styled.div` gap: 2px; `; -export const Button = css` +export const teamName = css` + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + + max-width: 200px; +`; + +export const closeButton = css` display: flex; justify-content: center; align-items: center; diff --git a/frontend/src/components/ScheduleModal/ScheduleModal.tsx b/frontend/src/components/ScheduleModal/ScheduleModal.tsx index 510a5442a..8df776825 100644 --- a/frontend/src/components/ScheduleModal/ScheduleModal.tsx +++ b/frontend/src/components/ScheduleModal/ScheduleModal.tsx @@ -2,22 +2,43 @@ import type { CSSProperties } from 'react'; import Modal from '~/components/common/Modal/Modal'; import Text from '~/components/common/Text/Text'; import { useModal } from '~/hooks/useModal'; -import * as S from './Schedule.styled'; +import * as S from './ScheduleModal.styled'; import { CloseIcon, DeleteIcon, EditIcon } from '~/assets/svg'; import Button from '~/components/common/Button/Button'; +import { formatDateTime } from '~/utils/formatDateTime'; +import type { SchedulePosition } from '~/types/schedule'; +import { useFetchScheduleById } from '~/hooks/queries/useFetchScheduleById'; +import { useDeleteSchedule } from '~/hooks/queries/useDeleteSchedule'; interface ScheduleModalProps { - id: number; - targetRef: React.RefObject; + scheduleId: number; + position: SchedulePosition; } + const ScheduleModal = (props: ScheduleModalProps) => { - const { targetRef } = props; + const { scheduleId, position } = props; const { closeModal } = useModal(); + const { scheduleById } = useFetchScheduleById(1, scheduleId); + const { mutateScheduleDelete } = useDeleteSchedule(1, scheduleId); + + if (scheduleById === undefined) return; + const { title, startDateTime, endDateTime } = scheduleById; + const { row, column, level } = position; const modalLocation: CSSProperties = { position: 'absolute', - top: `${targetRef.current?.getBoundingClientRect().bottom}px`, - left: `${targetRef.current?.getBoundingClientRect().left}px`, + top: row < 3 ? `${(row + 1) * 120 + level * 18 + 60}px` : 'none', + bottom: row >= 3 ? `${(6 - row) * 120 - level * 18}px` : 'none', + left: column < 3 ? `${(column * 100) / 7}%` : 'none', + right: column >= 3 ? `${((6 - column) * 100) / 7}%` : 'none', + }; + + const handleScheduleDelete = () => { + if (confirm('일정을 삭제하시겠어요?')) { + mutateScheduleDelete(undefined, { + onSuccess: () => closeModal(), + }); + } }; return ( @@ -27,22 +48,15 @@ const ScheduleModal = (props: ScheduleModalProps) => { -

- - 현대사회와 범죄 5조현대사회와 범죄 5조현대사회와 - 범죄5조현대사회와 범죄 5조현대사회와 범죄 5조 - -

+
+ 현대사회와 범죄 5조 +
-
- 1차 데모데이 + {title} - 07월 13일 15:00 + {formatDateTime(startDateTime)} ~ - 07월 13일 19:00 + {formatDateTime(endDateTime)}