Skip to content

Commit

Permalink
Feat: 플랫폼별 스케줄을 추가 및 수정하다
Browse files Browse the repository at this point in the history
  • Loading branch information
kikiyeom committed Jun 17, 2024
1 parent 00cf270 commit 0195d34
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import { useRecoilValue } from 'recoil';
import { Button, DatePickerField, InputField, RadioButtonField, SelectField } from '@/components';
import { InputSize } from '@/components/common/Input/Input.component';
import * as Styled from './ScheduleTemplate.styled';
import { $generations } from '@/store';
import { $generations, $profile, $teams } from '@/store';
import { SelectOption } from '@/components/common/Select/Select.component';
import { SessionTemplate } from '../SessionTemplate';
import Plus from '@/assets/svg/plus-20.svg';
import { EventCreateRequest } from '@/types';
import { LocationType, ScheduleFormValues } from '@/utils';
import { LocationType, ScheduleFormValues, ScheduleType } from '@/utils';
import { useScript } from '@/hooks';

const DEFAULT_SESSION: EventCreateRequest = {
Expand All @@ -26,8 +26,11 @@ const ScheduleTemplate = () => {
const { register, control, formState, getValues, watch, setValue } =
useFormContext<ScheduleFormValues>();
const generations = useRecoilValue($generations);
const [position] = useRecoilValue($profile);
const teams = useRecoilValue($teams);

const locationType = watch('locationType');
const scheduleType = watch('scheduleType');

const { fields, append, remove } = useFieldArray({
name: 'sessions',
Expand All @@ -46,6 +49,23 @@ const ScheduleTemplate = () => {
const defaultOption = generationOptions.find(
(option) => option.value === getValues('generationNumber')?.toString(),
);

const generationPlatformOptions = teams.map(({ name }) => ({
value: name.toUpperCase(),
label: name,
}));

const getTeamSelectOptions = () => {
const myTeamOptionObject = generationPlatformOptions.find(({ value }) => value === position);
return myTeamOptionObject ? [myTeamOptionObject] : generationPlatformOptions;
};

const teamSelectOptions = getTeamSelectOptions();

const defaultPlatformOption = generationPlatformOptions.find(
(option) => option.value === getValues('schedulePlatformType'),
);

const handleClickAddressSearch = () => {
new window.daum.Postcode({
async oncomplete(data: { address: string }) {
Expand Down Expand Up @@ -96,6 +116,37 @@ const ScheduleTemplate = () => {
isFullWidth
{...register('generationNumber', { required: true })}
/>
<div>
<Styled.InputLabel htmlFor="location">
<span>구분</span>
<Styled.RequiredDot />
</Styled.InputLabel>
<Styled.RadioButtonGroup>
<RadioButtonField
label="플랫폼"
required
value={ScheduleType.PLATFORM}
{...register('scheduleType', { required: true })}
/>
<RadioButtonField
label="전체"
required
value={ScheduleType.ALL}
{...register('scheduleType', { required: true })}
/>
</Styled.RadioButtonGroup>
{scheduleType === ScheduleType.PLATFORM && (
<SelectField
size="md"
options={teamSelectOptions}
defaultValue={defaultPlatformOption}
required
{...register('schedulePlatformType', {
required: scheduleType === ScheduleType.PLATFORM,
})}
/>
)}
</div>
<DatePickerField
label="스케줄 일시"
$size="md"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ import React, { useMemo } from 'react';
import { ScheduleStatus, ValueOf } from '@/types';

import * as Styled from './ScheduleInfoList.styled';
import { formatDate, getScheduleStatusText } from '@/utils';
import { formatDate, getScheduleStatusText, getScheduleType, SchedulePlatformType } from '@/utils';

interface ScheduleInfoListProps {
generationNumber: number;
scheduleType: ValueOf<typeof SchedulePlatformType>;
name: string;
createdAt: string;
startedAt: string;
Expand All @@ -20,6 +21,7 @@ interface ScheduleInfoListProps {
const ScheduleInfoList = ({
name,
generationNumber,
scheduleType,
startedAt,
createdAt,
publishedAt,
Expand All @@ -36,6 +38,10 @@ const ScheduleInfoList = ({
label: '기수',
value: `${generationNumber}기`,
},
{
label: '구분',
value: getScheduleType(scheduleType),
},
{
label: '스케줄 일시',
value: formatDate(startedAt, 'YYYY년 M월 D일 A hh시 mm분'),
Expand All @@ -62,7 +68,7 @@ const ScheduleInfoList = ({
value: getScheduleStatusText(status),
},
];
}, [createdAt, generationNumber, name, publishedAt, startedAt, status, location]);
}, [createdAt, generationNumber, name, publishedAt, startedAt, status, location, scheduleType]);

return (
<Styled.ScheduleInfoList>
Expand Down
2 changes: 2 additions & 0 deletions src/pages/ScheduleDetail/ScheduleDetail.page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const ScheduleDetail = () => {

const {
name,
scheduleType,
generationNumber,
startedAt,
createdAt,
Expand Down Expand Up @@ -143,6 +144,7 @@ const ScheduleDetail = () => {
<h3>스케줄 정보</h3>
<ScheduleInfoList
name={name}
scheduleType={scheduleType}
generationNumber={generationNumber}
startedAt={startedAt}
createdAt={createdAt}
Expand Down
42 changes: 35 additions & 7 deletions src/pages/ScheduleList/ScheduleList.page.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,50 @@
import React, { useEffect, useMemo } from 'react';
import React, { useEffect, useMemo, MouseEvent } from 'react';
import { useLocation, useSearchParams } from 'react-router-dom';
import { useRecoilStateLoadable, useRecoilValue } from 'recoil';
import { BottomCTA, Button, Link, Pagination, SearchOptionBar, Table } from '@/components';
import {
BottomCTA,
Button,
Link,
Pagination,
SearchOptionBar,
Table,
TeamNavigationTabs,
} from '@/components';
import * as Styled from './ScheduleList.styled';
import { TableColumn } from '@/components/common/Table/Table.component';
import { ScheduleRequest, ScheduleResponse, ScheduleStatus } from '@/types/dto/schedule';
import { formatDate } from '@/utils/date';
import { getScheduleDetailPage, PATH } from '@/constants';
import { ButtonShape, ButtonSize } from '@/components/common/Button/Button.component';
import { usePagination } from '@/hooks';
import { $generationNumber } from '@/store';
import { usePagination, useToast } from '@/hooks';
import { $generationNumber, $isMaster, $profile } from '@/store';
import { $schedules } from '@/store/schedule';
import { ValueOf } from '@/types';
import { getScheduleStatusText } from '@/utils';
import { getScheduleStatusText, SchedulePlatformType } from '@/utils';
import { ToastType } from '@/styles';

const ScheduleList = () => {
const [searchParams, setSearchParams] = useSearchParams();
const teamName = searchParams.get('team');
const generationNumber = useRecoilValue($generationNumber);
const [position] = useRecoilValue($profile);
const isMaster = useRecoilValue($isMaster);
const page = searchParams.get('page') || '1';
const size = searchParams.get('size') || '10';
const searchWord = searchParams.get('searchWord') || '';

const { pathname, search } = useLocation();
const { handleAddToast } = useToast();

const handleClickLink = (event: MouseEvent<HTMLAnchorElement>) => {
if (!isMaster && teamName !== position) {
handleAddToast({
type: ToastType.error,
message: '접근 권한이 없는 플랫폼입니다.',
});
event.preventDefault();
}
};

const columns: TableColumn<ScheduleResponse>[] = [
{
Expand All @@ -31,7 +53,11 @@ const ScheduleList = () => {
widthRatio: '20%',
idAccessor: 'scheduleId',
renderCustomCell: ({ cellValue, id }) => (
<Styled.TitleLink to={getScheduleDetailPage(id)} state={{ from: `${pathname}${search}` }}>
<Styled.TitleLink
to={getScheduleDetailPage(id)}
state={{ from: `${pathname}${search}` }}
onClick={handleClickLink}
>
{cellValue as string}
</Styled.TitleLink>
),
Expand Down Expand Up @@ -75,8 +101,9 @@ const ScheduleList = () => {
size: parseInt(size, 10),
searchWord,
generationNumber,
scheduleType: (teamName as ValueOf<typeof SchedulePlatformType>) ?? 'ALL',
}),
[generationNumber, page, searchWord, size],
[generationNumber, page, searchWord, size, teamName],
);

const [{ contents }] = useRecoilStateLoadable($schedules(scheduleParams));
Expand Down Expand Up @@ -105,6 +132,7 @@ const ScheduleList = () => {
<Styled.PageWrapper>
<Styled.Heading>스케줄 정보 </Styled.Heading>
<Styled.StickyContainer>
<TeamNavigationTabs />
<SearchOptionBar placeholder="스케줄명 검색" />
</Styled.StickyContainer>
<Table
Expand Down
5 changes: 5 additions & 0 deletions src/types/dto/schedule.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { SchedulePlatformType } from '@/utils';
import { ValueOf } from '..';

export const ScheduleStatus = {
Expand All @@ -10,6 +11,7 @@ export interface ScheduleRequest {
page?: number;
size?: number;
sort?: string;
scheduleType: ValueOf<typeof SchedulePlatformType>;
}

export interface EventCreateRequest {
Expand All @@ -34,6 +36,7 @@ interface Location {

export interface ScheduleCreateRequest extends Location {
generationNumber?: number;
scheduleType: ValueOf<typeof SchedulePlatformType>;
endedAt: string;
name: string;
startedAt: string;
Expand All @@ -42,6 +45,7 @@ export interface ScheduleCreateRequest extends Location {

export interface ScheduleUpdateRequest extends Location {
generationNumber?: number;
scheduleType: ValueOf<typeof SchedulePlatformType>;
endedAt: string;
name: string;
startedAt: string;
Expand All @@ -51,6 +55,7 @@ export interface ScheduleUpdateRequest extends Location {
export interface ScheduleResponse {
endedAt: string;
generationNumber: number;
scheduleType: ValueOf<typeof SchedulePlatformType>;
name: string;
scheduleId: number;
createdAt: string;
Expand Down
59 changes: 58 additions & 1 deletion src/utils/schedule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,26 @@ export const LocationType = {
ONLINE: 'online',
} as const;

export const ScheduleType = {
PLATFORM: 'PLATFORM',
ALL: 'ALL',
} as const;

export const SchedulePlatformType = {
ALL: 'ALL',
ANDROID: 'ANDROID',
IOS: 'IOS',
WEB: 'WEB',
SPRING: 'SPRING',
NODE: 'NODE',
DESIGN: 'DESIGN',
} as const;

export interface ScheduleFormValues {
name: string;
generationNumber: number;
scheduleType: ValueOf<typeof ScheduleType>;
schedulePlatformType?: ValueOf<typeof SchedulePlatformType>;
date: Dayjs;
sessions: EventCreateRequest[];
locationType: ValueOf<typeof LocationType>;
Expand All @@ -28,6 +45,27 @@ export interface ScheduleFormValues {
};
}

export const getScheduleType = (type: ValueOf<typeof SchedulePlatformType>) => {
switch (type) {
case SchedulePlatformType.ALL:
return '전체';
case SchedulePlatformType.ANDROID:
return 'Android';
case SchedulePlatformType.IOS:
return 'iOS';
case SchedulePlatformType.WEB:
return 'Web';
case SchedulePlatformType.SPRING:
return 'Spring';
case SchedulePlatformType.NODE:
return 'Node';
case SchedulePlatformType.DESIGN:
return 'Design';
default:
return '';
}
};

export const getScheduleStatusText = (status: ValueOf<typeof ScheduleStatus>) => {
switch (status) {
case ScheduleStatus.ADMIN_ONLY:
Expand All @@ -45,6 +83,7 @@ export const parseScheduleResponseToFormValues = (
const {
name,
generationNumber,
scheduleType: responseScheduleType,
startedAt,
eventList,
location: { roadAddress, detailAddress, latitude, longitude },
Expand All @@ -63,10 +102,16 @@ export const parseScheduleResponseToFormValues = (
})),
}));

const isScheduleAll = responseScheduleType === 'ALL';
const scheduleType = isScheduleAll ? ScheduleType.ALL : ScheduleType.PLATFORM;
const schedulePlatformType = isScheduleAll ? undefined : responseScheduleType;

if (roadAddress) {
return {
name,
generationNumber,
scheduleType,
schedulePlatformType,
date,
sessions,
locationType: LocationType.OFFLINE,
Expand All @@ -82,6 +127,8 @@ export const parseScheduleResponseToFormValues = (
return {
name,
generationNumber,
scheduleType,
schedulePlatformType,
date,
sessions,
locationType: LocationType.ONLINE,
Expand All @@ -91,7 +138,16 @@ export const parseScheduleResponseToFormValues = (
export const parseFormValuesToScheduleRequest = (
formValues: ScheduleFormValues,
): ScheduleCreateRequest | ScheduleUpdateRequest => {
const { generationNumber, date, sessions, name, locationType, locationInfo } = formValues;
const {
generationNumber,
scheduleType: formScheduleType,
schedulePlatformType,
date,
sessions,
name,
locationType,
locationInfo,
} = formValues;

const formattedDate = date.format('YYYY-MM-DD');

Expand All @@ -109,6 +165,7 @@ export const parseFormValuesToScheduleRequest = (
const endedAt = toUtcFormat(`${formattedDate} ${sessions[sessions.length - 1]?.endedAt}`);

const scheduleRequest: ScheduleCreateRequest | ScheduleUpdateRequest = {
scheduleType: formScheduleType === ScheduleType.ALL ? ScheduleType.ALL : schedulePlatformType!,
generationNumber,
name,
startedAt,
Expand Down

0 comments on commit 0195d34

Please sign in to comment.