Skip to content

Commit

Permalink
Feat: 스케줄에 장소가 포함된다.
Browse files Browse the repository at this point in the history
  • Loading branch information
kikiyeom committed Mar 5, 2024
1 parent eed7bfd commit d254ea4
Show file tree
Hide file tree
Showing 11 changed files with 158 additions and 8 deletions.
Binary file not shown.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"@testing-library/react": "^12.1.2",
"@testing-library/react-hooks": "^7.0.2",
"@testing-library/user-event": "^13.5.0",
"@types/daum-postcode": "^2.0.3",
"@types/editorjs__header": "^2.6.0",
"@types/jest": "^27.4.0",
"@types/lodash-es": "^4.17.6",
Expand Down
1 change: 1 addition & 0 deletions public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
/>
<meta property="og:image" content="/assets/og-image.png" />
<link rel="icon" href="/assets/favicon.svg" />
<script src="//t1.daumcdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js"></script>
</head>
<body>
<div id="root"></div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import React, { useMemo } from 'react';
import { useFieldArray, useFormContext } from 'react-hook-form';
import { useRecoilValue } from 'recoil';
import { DatePickerField, InputField, SelectField } from '@/components';
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 { SelectOption } from '@/components/common/Select/Select.component';
import { SessionTemplate } from '../SessionTemplate';
import Plus from '@/assets/svg/plus-20.svg';
import { EventCreateRequest } from '@/types';
import { ScheduleFormValues } from '@/utils';
import { LocationType, ScheduleFormValues } from '@/utils';

const DEFAULT_SESSION: EventCreateRequest = {
startedAt: '',
Expand All @@ -19,9 +19,12 @@ const DEFAULT_SESSION: EventCreateRequest = {
};

const ScheduleTemplate = () => {
const { register, control, formState, getValues } = useFormContext<ScheduleFormValues>();
const { register, control, formState, getValues, watch, setValue } =
useFormContext<ScheduleFormValues>();
const generations = useRecoilValue($generations);

const locationType = watch('locationType');

const { fields, append, remove } = useFieldArray({
name: 'sessions',
control,
Expand All @@ -37,6 +40,31 @@ const ScheduleTemplate = () => {
const defaultOption = generationOptions.find(
(option) => option.value === getValues('generationNumber')?.toString(),
);
const handleClickAddressSearch = () => {
new window.daum.Postcode({

Check failure on line 44 in src/components/Schedule/ScheduleTemplate/ScheduleTemplate.component.tsx

View workflow job for this annotation

GitHub Actions / build (18.x)

Property 'daum' does not exist on type 'Window & typeof globalThis'.
async oncomplete(data: { address: string }) {
const res = await fetch(
`https://dapi.kakao.com/v2/local/search/address?query=${data.address}`,
{
method: 'GET',
headers: {
'Content-Type': 'application/json',
Authorization: 'KakaoAK cc4af66dc10aa1a20830f3cc62c40a87',
},
},
);
const json = await res.json();
const roadAddress = json.documents[0].road_address;
setValue('locationInfo', {
address: roadAddress.address_name,
latitude: roadAddress.y,
longitude: roadAddress.x,
placeName: roadAddress.building_name ?? roadAddress.address_name,
});
setValue('placeName', roadAddress.building_name);
},
}).open();
};

return (
<>
Expand Down Expand Up @@ -66,6 +94,38 @@ const ScheduleTemplate = () => {
defaultDate={getValues('date')}
{...register('date', { required: true })}
/>
<div>
<Styled.InputLabel htmlFor="location">
<span>장소</span>
<Styled.RequiredDot />
</Styled.InputLabel>
<Styled.RadioButtonGroup>
<RadioButtonField
label="오프라인"
required
value={LocationType.OFFLINE}
{...register('locationType', { required: true })}
/>
<RadioButtonField
label="온라인"
required
value={LocationType.ONLINE}
{...register('locationType', { required: true })}
/>
</Styled.RadioButtonGroup>
{locationType === LocationType.OFFLINE && (
<Styled.InputWithButton>
<InputField
$size="md"
placeholder="장소"
{...register('placeName', { required: locationType === LocationType.OFFLINE })}
/>
<Button shape="primaryLine" $size="md" onClick={handleClickAddressSearch}>
주소 검색
</Button>
</Styled.InputWithButton>
)}
</div>
</Styled.ScheduleContent>
<Styled.SessionContent>
<Styled.Title>세션 정보</Styled.Title>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ export const ScheduleContent = styled.div`
display: flex;
flex-direction: column;
gap: 2rem;
height: 36.9rem;
padding: 2.4rem;
background-color: ${theme.colors.white};
border: 0.1rem solid ${theme.colors.gray30};
Expand Down Expand Up @@ -43,3 +42,32 @@ export const AddButton = styled.button`
margin-top: 2.4rem;
background-color: transparent;
`;

export const InputLabel = styled.label`
${({ theme }) => css`
${theme.fonts.medium15}
display: flex;
margin-bottom: 0.6rem;
color: ${theme.colors.gray70};
`}
`;

export const RequiredDot = styled.span`
width: 0.6rem;
min-width: 0.6rem;
height: 0.6rem;
margin: 0.8rem 0 0 0.6rem;
background-color: #eb6963;
border-radius: 50%;
`;

export const RadioButtonGroup = styled.div`
display: flex;
gap: 2rem;
margin-bottom: 1rem;
`;

export const InputWithButton = styled.div`
display: flex;
gap: 1rem;
`;
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ interface ScheduleInfoListProps {
startedAt: string;
publishedAt?: string;
status: ValueOf<typeof ScheduleStatus>;
location: {
address: string | null;
placeName: string;
};
}

const ScheduleInfoList = ({
Expand All @@ -20,6 +24,7 @@ const ScheduleInfoList = ({
createdAt,
publishedAt,
status,
location,
}: ScheduleInfoListProps) => {
const scheduleInfoListItem = useMemo(() => {
return [
Expand All @@ -39,6 +44,13 @@ const ScheduleInfoList = ({
label: '등록 일시',
value: formatDate(createdAt, 'YYYY년 M월 D일 A hh시 mm분'),
},
{
label: '장소',
value:
location.address === null
? location.placeName
: `${location.placeName}, ${location.address}`,
},
{
label: '배포 일시',
value: formatDate(publishedAt, 'YYYY년 M월 D일 A hh시 mm분'),
Expand All @@ -48,7 +60,7 @@ const ScheduleInfoList = ({
value: getScheduleStatusText(status),
},
];
}, [createdAt, generationNumber, name, publishedAt, startedAt, status]);
}, [createdAt, generationNumber, name, publishedAt, startedAt, status, location]);

return (
<Styled.ScheduleInfoList>
Expand Down
2 changes: 1 addition & 1 deletion src/components/common/RadioButton/RadioButton.styled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,6 @@ export const RadioButtonMark = styled.span`
export const RadioButtonText = styled.span`
${({ theme }) => css`
${theme.fonts.medium14}
padding-left: 3.8rem;
padding-left: 3rem;
`}
`;
2 changes: 2 additions & 0 deletions src/pages/ScheduleDetail/ScheduleDetail.page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const ScheduleDetail = () => {
publishedAt,
status,
eventList: sessionList,
location,
} = useRecoilValue($scheduleDetail({ scheduleId: scheduleId ?? '' }));

const isPublished = status === ScheduleStatus.PUBLIC;
Expand Down Expand Up @@ -147,6 +148,7 @@ const ScheduleDetail = () => {
createdAt={createdAt}
publishedAt={publishedAt}
status={status}
location={location}
/>
</Styled.Content>
<Styled.Content>
Expand Down
14 changes: 14 additions & 0 deletions src/types/dto/schedule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ export interface ScheduleCreateRequest {
name: string;
startedAt: string;
eventsCreateRequests: EventCreateRequest[];
address?: string;
latitude?: number;
longitude?: number;
placeName?: string;
}

export interface ScheduleUpdateRequest {
Expand All @@ -39,6 +43,10 @@ export interface ScheduleUpdateRequest {
name: string;
startedAt: string;
eventsCreateRequests: EventCreateRequest[];
address?: string;
latitude?: number;
longitude?: number;
placeName?: string;
}

export interface ScheduleResponse {
Expand All @@ -51,6 +59,12 @@ export interface ScheduleResponse {
publishedAt?: string;
eventList: Session[];
status: ValueOf<typeof ScheduleStatus>;
location: {
address: string | null;
latitude: number | null;
longitude: number | null;
placeName: string;
};
}

export interface QRCodeRequest {
Expand Down
28 changes: 26 additions & 2 deletions src/utils/schedule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,24 @@ import {
} from '@/types';
import { formatDate, toUtcFormat } from '.';

export const LocationType = {
OFFLINE: 'offline',
ONLINE: 'online',
} as const;

export interface ScheduleFormValues {
name: string;
generationNumber: number;
date: Dayjs;
sessions: EventCreateRequest[];
locationType: ValueOf<typeof LocationType>;
placeName?: string;
locationInfo?: {
address: string;
latitude: string;
longitude: string;
placeName: string;
};
}

export const getScheduleStatusText = (status: ValueOf<typeof ScheduleStatus>) => {
Expand All @@ -30,7 +43,7 @@ export const getScheduleStatusText = (status: ValueOf<typeof ScheduleStatus>) =>
export const parseScheduleResponseToFormValues = (
response: ScheduleResponse,
): ScheduleFormValues => {
const { name, generationNumber, startedAt, eventList } = response;
const { name, generationNumber, startedAt, eventList, location } = response;

const date: Dayjs = dayjs(startedAt, 'YYYY-MM-DD').startOf('day');

Expand All @@ -45,18 +58,22 @@ export const parseScheduleResponseToFormValues = (
})),
}));

const isOffline = !!location.address;

return {
name,
generationNumber,
date,
sessions,
locationType: isOffline ? LocationType.OFFLINE : LocationType.ONLINE,
placeName: isOffline ? location.placeName : undefined,
};
};

export const parseFormValuesToScheduleRequest = (
formValues: ScheduleFormValues,
): ScheduleCreateRequest | ScheduleUpdateRequest => {
const { generationNumber, date, sessions, name } = formValues;
const { generationNumber, date, sessions, name, locationType, locationInfo } = formValues;

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

Expand All @@ -81,5 +98,12 @@ export const parseFormValuesToScheduleRequest = (
eventsCreateRequests,
};

if (locationType === LocationType.OFFLINE && locationInfo) {
scheduleRequest.address = locationInfo.address;
scheduleRequest.latitude = Number(locationInfo.latitude);
scheduleRequest.longitude = Number(locationInfo.longitude);
scheduleRequest.placeName = locationInfo.placeName;
}

return scheduleRequest;
};
8 changes: 8 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3921,6 +3921,13 @@ __metadata:
languageName: node
linkType: hard

"@types/daum-postcode@npm:^2.0.3":
version: 2.0.3
resolution: "@types/daum-postcode@npm:2.0.3"
checksum: 72283bd2c3bb17073eb1324089e2bc5f5ff6df89c8731e1b9123620328cca0f7b77ac6480a06b5e35c0436c652782af376a896af5044416e2dfb809d040ee728
languageName: node
linkType: hard

"@types/editorjs__header@npm:^2.6.0":
version: 2.6.0
resolution: "@types/editorjs__header@npm:2.6.0"
Expand Down Expand Up @@ -12951,6 +12958,7 @@ __metadata:
"@testing-library/react": ^12.1.2
"@testing-library/react-hooks": ^7.0.2
"@testing-library/user-event": ^13.5.0
"@types/daum-postcode": ^2.0.3
"@types/editorjs__header": ^2.6.0
"@types/jest": ^27.4.0
"@types/lodash-es": ^4.17.6
Expand Down

0 comments on commit d254ea4

Please sign in to comment.