Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FE] 하루 일정 모달 구현 #153

Merged
merged 9 commits into from
Jul 25, 2023
9 changes: 6 additions & 3 deletions frontend/src/apis/schedule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@ export const fetchSchedules = (
teamPlaceId: number,
year: number,
month: number,
day?: number,
) => {
const query = day
? `year=${year}&month=${month}&day=${day}`
: `year=${year}&month=${month}`;

return http.get<{
schedules: Schedule[];
}>(
`/api/team-place/${teamPlaceId}/calendar/schedules?year=${year}&month=${month}`,
);
}>(`/api/team-place/${teamPlaceId}/calendar/schedules?${query}`);
};

export const fetchScheduleById = (teamPlaceId: number, scheduleId: number) => {
Expand Down
44 changes: 38 additions & 6 deletions frontend/src/components/Calendar/Calendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ import { useModal } from '~/hooks/useModal';
import { generateScheduleBars } from '~/utils/generateScheduleBars';
import { DAYS_OF_WEEK, MODAL_OPEN_TYPE } from '~/constants/calendar';
import { ArrowLeftIcon, ArrowRightIcon, PlusIcon } from '~/assets/svg';
import type { ModalOpenType } from '~/types/schedule';
import { arrayOf } from '~/utils/arrayOf';
import ScheduleMoreCell from '~/components/ScheduleMoreCell/ScheduleMoreCell';
import type { Position, ModalOpenType } from '~/types/schedule';
import DailyScheduleModal from '~/components/DailyScheduleModal/DailyScheduleModal';

const Calendar = () => {
const {
Expand All @@ -35,17 +36,32 @@ const Calendar = () => {
const [modalType, setModalType] = useState<ModalOpenType>(
MODAL_OPEN_TYPE.ADD,
);

if (schedules === undefined) {
return null;
}
const [dailyModalDate, setDailyModalDate] = useState<Date>(new Date());
const [dailyModalPosition, setDailyModalPosition] = useState<Position>({
row: 0,
column: 0,
});
const scheduleBars = generateScheduleBars(year, month, schedules);

const handleModalOpen = (modalOpenType: ModalOpenType) => {
setModalType(() => modalOpenType);
openModal();
};

const handleDailyScheduleModalOpen = (
day: Date,
row: number,
col: number,
) => {
setModalType(() => MODAL_OPEN_TYPE.DAILY);
setDailyModalDate(() => day);
setDailyModalPosition({
row,
column: col,
});
openModal();
};

return (
<>
<S.Container>
Expand Down Expand Up @@ -119,13 +135,21 @@ const Calendar = () => {
})}
</S.ScheduleBarContainer>
<S.DateView>
{week.map((day) => {
{week.map((day, colIndex) => {
return (
<DateCell
key={day.toISOString()}
rawDate={day}
currentMonth={month}
onClick={() => handleModalOpen(MODAL_OPEN_TYPE.ADD)}
onDayClick={(e) => {
e.stopPropagation();
handleDailyScheduleModalOpen(
day,
rowIndex,
colIndex,
);
}}
/>
);
})}
Expand Down Expand Up @@ -155,6 +179,14 @@ const Calendar = () => {
)}
/>
)}
{isModalOpen && modalType === MODAL_OPEN_TYPE.DAILY && (
<DailyScheduleModal
rawDate={dailyModalDate}
position={dailyModalPosition}
onScheduleModalOpen={handleScheduleModalOpen}
onSetModalType={() => setModalType(() => MODAL_OPEN_TYPE.VIEW)}
/>
)}
</>
);
};
Expand Down
19 changes: 18 additions & 1 deletion frontend/src/components/Calendar/DateCell/DateCell.styled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ interface WrapperProps {
}

export const Wrapper = styled.div<WrapperProps>`
display: flex;
flex-direction: column;
align-items: flex-end;
${({ size }) => {
if (size === 'sm')
return css`
Expand All @@ -18,7 +21,7 @@ export const Wrapper = styled.div<WrapperProps>`
if (size === 'md') return css``;
if (size === 'lg')
return css`
padding: 8px 8px 0 0;
padding: 2px 2px 0 0;
text-align: right;
`;
}};
Expand All @@ -31,3 +34,17 @@ export const Wrapper = styled.div<WrapperProps>`

cursor: pointer;
`;

export const TeamColorBadge = styled.div`
display: flex;
justify-content: center;
align-items: center;

width: 20px;
height: 20px;
border-radius: 50%;

&:hover {
background-color: ${({ theme }) => theme.color.GRAY300};
}
`;
22 changes: 13 additions & 9 deletions frontend/src/components/Calendar/DateCell/DateCell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,18 @@ import { parseDate } from '~/utils/parseDate';
import Text from '~/components/common/Text/Text';
import * as S from './DateCell.styled';
import type { DateCellSize } from '~/types/size';
import type { MouseEventHandler } from 'react';

interface DateCellProps {
rawDate: Date;
currentMonth: number;
onClick?: () => void;
onDayClick?: MouseEventHandler<HTMLDivElement>;
size?: DateCellSize;
}

const DateCell = (props: DateCellProps) => {
const { rawDate, currentMonth, size = 'lg', onClick } = props;
const { rawDate, currentMonth, size = 'lg', onClick, onDayClick } = props;
const { date, day } = parseDate(rawDate);

const isSunday = day === 0;
Expand All @@ -26,14 +28,16 @@ const DateCell = (props: DateCellProps) => {
size={size}
onClick={onClick}
>
<Text
css={css`
font-size: 12px;
opacity: ${isCurrentMonth ? 1 : 0.3};
`}
>
{date}
</Text>
<S.TeamColorBadge onClick={onDayClick}>
<Text
css={css`
font-size: 12px;
opacity: ${isCurrentMonth ? 1 : 0.3};
`}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

현재 우리가 정했던 코딩 컨벤션에 따르면, 인라인 css 스타일은 항상 사용하지 않는 것으로 결정되었을 거야.
만약 인라인 css 스타일을 사용해야만 하는 불가피한 상황이라면, 따로 회의를 진행해서 정하는 게 필요할 것 같아

물론...원래부터 코드가 이랬다는 건 나도 알고 있어

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

뿌에에에엥

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image image

두 방식 다 안되네 다른 분리 방법 있으면 알려줘

>
{date}
</Text>
</S.TeamColorBadge>
</S.Wrapper>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import type { Meta, StoryObj } from '@storybook/react';
import DailyScheduleModal from '~/components/DailyScheduleModal/DailyScheduleModal';
import Button from '~/components/common/Button/Button';
import { useModal } from '~/hooks/useModal';
import type { SchedulePosition } from '~/types/schedule';

const meta = {
title: 'DailyScheduleModal',
component: DailyScheduleModal,
} satisfies Meta<typeof DailyScheduleModal>;

export default meta;
type Story = StoryObj<typeof meta>;

export const Default: Story = {
render: () => {
const { openModal } = useModal();

return (
<>
<Button onClick={openModal}>모달 열기</Button>
<DailyScheduleModal
onSetModalType={() => console.log('hi')}
rawDate={new Date()}
position={{ row: 0, column: 0 }}
onScheduleModalOpen={({ scheduleId, row, column, level }) =>
alert(`${scheduleId}, ${row}, ${column}, ${level}`)
}
/>
</>
);
},
args: {
onScheduleModalOpen: ({
scheduleId,
row,
column,
level,
}: SchedulePosition & {
scheduleId: number;
}) => {
alert(`${scheduleId}, ${row}, ${column}, ${level}`);
},
onSetModalType: () => alert('hi'),
position: { row: 0, column: 0 },
rawDate: new Date(),
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { css, styled } from 'styled-components';
import type { DailyScheduleModalProps } from '~/components/DailyScheduleModal/DailyScheduleModal';

export const Backdrop = styled.div`
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
`;

export const Container = styled.div`
display: flex;
position: absolute;
flex-direction: column;
z-index: ${({ theme }) => theme.zIndex.MODAL};

width: 300px;
height: 338px;
padding: 10px 20px 20px 20px;

border-radius: 10px;
background-color: ${({ theme }) => theme.color.WHITE};

box-shadow:
0 0 1px #1b1d1f33,
0 15px 25px #1b1d1f33,
0 5px 10px #1b1d1f1f;
`;

export const Header = styled.div`
display: flex;
justify-content: space-between;
align-items: center;

width: 100%;
height: 38px;
padding-bottom: 4px;
margin-bottom: 24px;

border-bottom: ${({ theme }) => `1px solid ${theme.color.GRAY300}`};
`;

export const ScheduleWrapper = styled.div`
display: flex;
position: relative;
flex-wrap: wrap;
overflow: auto;

width: 100%;
max-height: 80%;
height: auto;

gap: 10px;
`;

export const ScheduleBox = styled.div<Pick<DailyScheduleModalProps, 'color'>>`
display: flex;
justify-content: center;
align-items: center;

width: 100%;
height: 40px;

background-color: ${({ color }) => color};
border-radius: 4px;

filter: brightness(1.5);

cursor: pointer;
`;

export const closeButton = css`
width: 22px;
height: 38px;
padding: 8px 0;
`;

export const teamName = css`
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;

max-width: 200px;
`;
Loading