From 5be8b13ec28f442a588ab87cab17af2491e721c6 Mon Sep 17 00:00:00 2001 From: kikiyeom Date: Mon, 17 Jun 2024 23:46:23 +0900 Subject: [PATCH 1/3] =?UTF-8?q?Feat:=20=ED=94=8C=EB=9E=AB=ED=8F=BC?= =?UTF-8?q?=EB=B3=84=20=EC=8A=A4=EC=BC=80=EC=A4=84=EC=9D=84=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20=EB=B0=8F=20=EC=88=98=EC=A0=95=ED=95=98=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ScheduleTemplate.component.tsx | 55 ++++++++++++++++- .../ScheduleInfoList.component.tsx | 10 +++- .../ScheduleDetail/ScheduleDetail.page.tsx | 2 + src/pages/ScheduleList/ScheduleList.page.tsx | 42 ++++++++++--- src/types/dto/schedule.ts | 5 ++ src/utils/schedule.ts | 59 ++++++++++++++++++- 6 files changed, 161 insertions(+), 12 deletions(-) diff --git a/src/components/Schedule/ScheduleTemplate/ScheduleTemplate.component.tsx b/src/components/Schedule/ScheduleTemplate/ScheduleTemplate.component.tsx index 6e7aab81..f2a4f58b 100644 --- a/src/components/Schedule/ScheduleTemplate/ScheduleTemplate.component.tsx +++ b/src/components/Schedule/ScheduleTemplate/ScheduleTemplate.component.tsx @@ -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 = { @@ -26,8 +26,11 @@ const ScheduleTemplate = () => { const { register, control, formState, getValues, watch, setValue } = useFormContext(); 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', @@ -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 }) { @@ -96,6 +116,37 @@ const ScheduleTemplate = () => { isFullWidth {...register('generationNumber', { required: true })} /> +
+ + 구분 + + + + + + + {scheduleType === ScheduleType.PLATFORM && ( + + )} +
; name: string; createdAt: string; startedAt: string; @@ -20,6 +21,7 @@ interface ScheduleInfoListProps { const ScheduleInfoList = ({ name, generationNumber, + scheduleType, startedAt, createdAt, publishedAt, @@ -36,6 +38,10 @@ const ScheduleInfoList = ({ label: '기수', value: `${generationNumber}기`, }, + { + label: '구분', + value: getScheduleType(scheduleType), + }, { label: '스케줄 일시', value: formatDate(startedAt, 'YYYY년 M월 D일 A hh시 mm분'), @@ -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 ( diff --git a/src/pages/ScheduleDetail/ScheduleDetail.page.tsx b/src/pages/ScheduleDetail/ScheduleDetail.page.tsx index 647cb07f..db2a8554 100644 --- a/src/pages/ScheduleDetail/ScheduleDetail.page.tsx +++ b/src/pages/ScheduleDetail/ScheduleDetail.page.tsx @@ -23,6 +23,7 @@ const ScheduleDetail = () => { const { name, + scheduleType, generationNumber, startedAt, createdAt, @@ -143,6 +144,7 @@ const ScheduleDetail = () => {

스케줄 정보

{ 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) => { + if (!isMaster && teamName !== position) { + handleAddToast({ + type: ToastType.error, + message: '접근 권한이 없는 플랫폼입니다.', + }); + event.preventDefault(); + } + }; const columns: TableColumn[] = [ { @@ -31,7 +53,11 @@ const ScheduleList = () => { widthRatio: '20%', idAccessor: 'scheduleId', renderCustomCell: ({ cellValue, id }) => ( - + {cellValue as string} ), @@ -75,8 +101,9 @@ const ScheduleList = () => { size: parseInt(size, 10), searchWord, generationNumber, + scheduleType: (teamName as ValueOf) ?? 'ALL', }), - [generationNumber, page, searchWord, size], + [generationNumber, page, searchWord, size, teamName], ); const [{ contents }] = useRecoilStateLoadable($schedules(scheduleParams)); @@ -105,6 +132,7 @@ const ScheduleList = () => { 스케줄 정보 + ; } export interface EventCreateRequest { @@ -34,6 +36,7 @@ interface Location { export interface ScheduleCreateRequest extends Location { generationNumber?: number; + scheduleType: ValueOf; endedAt: string; name: string; startedAt: string; @@ -42,6 +45,7 @@ export interface ScheduleCreateRequest extends Location { export interface ScheduleUpdateRequest extends Location { generationNumber?: number; + scheduleType: ValueOf; endedAt: string; name: string; startedAt: string; @@ -51,6 +55,7 @@ export interface ScheduleUpdateRequest extends Location { export interface ScheduleResponse { endedAt: string; generationNumber: number; + scheduleType: ValueOf; name: string; scheduleId: number; createdAt: string; diff --git a/src/utils/schedule.ts b/src/utils/schedule.ts index eb303c9d..1e1c2b3f 100644 --- a/src/utils/schedule.ts +++ b/src/utils/schedule.ts @@ -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; + schedulePlatformType?: ValueOf; date: Dayjs; sessions: EventCreateRequest[]; locationType: ValueOf; @@ -28,6 +45,27 @@ export interface ScheduleFormValues { }; } +export const getScheduleType = (type: ValueOf) => { + 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) => { switch (status) { case ScheduleStatus.ADMIN_ONLY: @@ -45,6 +83,7 @@ export const parseScheduleResponseToFormValues = ( const { name, generationNumber, + scheduleType: responseScheduleType, startedAt, eventList, location: { roadAddress, detailAddress, latitude, longitude }, @@ -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, @@ -82,6 +127,8 @@ export const parseScheduleResponseToFormValues = ( return { name, generationNumber, + scheduleType, + schedulePlatformType, date, sessions, locationType: LocationType.ONLINE, @@ -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'); @@ -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, From dd569040a7de62af727a3a14d079b80be31898ae Mon Sep 17 00:00:00 2001 From: kikiyeom Date: Mon, 1 Jul 2024 19:15:49 +0900 Subject: [PATCH 2/3] =?UTF-8?q?Feat:=20TeamNavigation=EC=97=90=20props?= =?UTF-8?q?=EB=A5=BC=20=EC=B6=94=EA=B0=80=ED=95=98=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TeamNavigationTabs.component.tsx | 11 ++++++++--- .../TeamNavigationTabs/TeamNavigationTabs.styled.ts | 5 +++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/components/common/TeamNavigationTabs/TeamNavigationTabs.component.tsx b/src/components/common/TeamNavigationTabs/TeamNavigationTabs.component.tsx index 6e8f8a5b..fad49577 100644 --- a/src/components/common/TeamNavigationTabs/TeamNavigationTabs.component.tsx +++ b/src/components/common/TeamNavigationTabs/TeamNavigationTabs.component.tsx @@ -4,7 +4,11 @@ import * as Styled from './TeamNavigationTabs.styled'; const TEAMS = ['All', 'Design', 'Android', 'iOS', 'Web', 'Node', 'Spring']; -const TeamNavigationTabs = () => { +interface TeamNavigationTabsProps { + allAltText?: string; +} + +const TeamNavigationTabs = ({ allAltText }: TeamNavigationTabsProps) => { const [searchParams, setSearchParams] = useSearchParams(); const handleClickTab = (teamParam: string) => { @@ -23,7 +27,7 @@ const TeamNavigationTabs = () => { const teamParam = team === 'All' ? '' : team.toUpperCase(); const active = team === 'All' ? !searchParams.has('team') : searchParams.get('team') === teamParam; - + const isAllAltText = team === 'All' && !!allAltText; return ( { aria-label={`${team} tab`} aria-current={active} active={active} + isAllAltText={isAllAltText} onClick={() => handleClickTab(teamParam)} > - {team} + {isAllAltText ? allAltText : team} ); })} diff --git a/src/components/common/TeamNavigationTabs/TeamNavigationTabs.styled.ts b/src/components/common/TeamNavigationTabs/TeamNavigationTabs.styled.ts index 7bd50f3b..8e060b82 100644 --- a/src/components/common/TeamNavigationTabs/TeamNavigationTabs.styled.ts +++ b/src/components/common/TeamNavigationTabs/TeamNavigationTabs.styled.ts @@ -3,6 +3,7 @@ import styled from '@emotion/styled'; interface StyledNavigationItemProps { active: boolean; + isAllAltText?: boolean; } export const Tabs = styled.nav` @@ -15,13 +16,13 @@ export const Tabs = styled.nav` `; export const Tab = styled.button` - ${({ theme, active }) => css` + ${({ theme, active, isAllAltText }) => css` ${theme.fonts.regular16}; display: flex; align-items: center; justify-content: center; - width: 8rem; + width: ${isAllAltText ? '12rem' : '8rem'}; height: 4rem; color: ${active ? theme.colors.purple70 : theme.colors.gray50}; letter-spacing: -0.08rem; From e2efd114587d094d7e81d497bf718fea3277f36a Mon Sep 17 00:00:00 2001 From: kikiyeom Date: Mon, 1 Jul 2024 19:17:17 +0900 Subject: [PATCH 3/3] =?UTF-8?q?Feat:=20=EC=8A=A4=EC=BC=80=EC=A4=84=20?= =?UTF-8?q?=EC=A0=95=EB=B3=B4=EC=9D=98=20=ED=8C=80=EB=84=A4=EB=B9=84?= =?UTF-8?q?=EA=B2=8C=EC=9D=B4=EC=85=98=20=EB=AC=B8=EA=B5=AC=EB=A5=BC=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=ED=95=98=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/ScheduleList/ScheduleList.page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/ScheduleList/ScheduleList.page.tsx b/src/pages/ScheduleList/ScheduleList.page.tsx index f3146746..a473bd7e 100644 --- a/src/pages/ScheduleList/ScheduleList.page.tsx +++ b/src/pages/ScheduleList/ScheduleList.page.tsx @@ -132,7 +132,7 @@ const ScheduleList = () => { 스케줄 정보 - +