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

스케줄 상세주소 추가 작업 #300

Merged
merged 4 commits into from
Mar 8, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
/>
<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
Expand Up @@ -10,6 +10,7 @@ import { SessionTemplate } from '../SessionTemplate';
import Plus from '@/assets/svg/plus-20.svg';
import { EventCreateRequest } from '@/types';
import { LocationType, ScheduleFormValues } from '@/utils';
import { useScript } from '@/hooks';

const DEFAULT_SESSION: EventCreateRequest = {
startedAt: '',
Expand All @@ -18,6 +19,9 @@ const DEFAULT_SESSION: EventCreateRequest = {
contentsCreateRequests: [],
};

const DAUM_POSTCODE_SCRIPT = '//t1.daumcdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js';
const DAUM_POSTCODE_API_URL = 'https://dapi.kakao.com/v2/local/search/address';

const ScheduleTemplate = () => {
const { register, control, formState, getValues, watch, setValue } =
useFormContext<ScheduleFormValues>();
Expand All @@ -30,6 +34,8 @@ const ScheduleTemplate = () => {
control,
});

useScript(DAUM_POSTCODE_SCRIPT);

const generationOptions = useMemo<SelectOption[]>(() => {
return generations.map(({ generationNumber }) => ({
label: `${generationNumber}기`,
Expand All @@ -43,25 +49,30 @@ const ScheduleTemplate = () => {
const handleClickAddressSearch = () => {
new window.daum.Postcode({
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 res = await fetch(`${DAUM_POSTCODE_API_URL}?query=${data.address}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
Authorization: 'KakaoAK cc4af66dc10aa1a20830f3cc62c40a87',
Copy link
Member

Choose a reason for hiding this comment

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

우리 public 레포인데 이건 이렇게 노출해도 되는건가?.?

Copy link
Member Author

Choose a reason for hiding this comment

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

띠용..😓 처리할게용

},
);
});
const json = await res.json();
const roadAddress = json.documents[0].road_address;

const {
address_name: address,
x: longitude,
y: latitude,
building_name: buildingName,
} = json.documents[0].road_address;
const placeName = buildingName || address;

setValue('locationInfo', {
address: roadAddress.address_name,
latitude: roadAddress.y,
longitude: roadAddress.x,
placeName: roadAddress.building_name ?? roadAddress.address_name,
address,
latitude,
longitude,
placeName,
});
setValue('placeName', roadAddress.building_name);
setValue('placeName', placeName);
},
}).open();
};
Expand Down Expand Up @@ -114,16 +125,23 @@ const ScheduleTemplate = () => {
/>
</Styled.RadioButtonGroup>
{locationType === LocationType.OFFLINE && (
<Styled.InputWithButton>
<Styled.LocationWrapper>
<Styled.InputWithButton>
<InputField
$size="md"
placeholder="장소"
{...register('placeName', { required: locationType === LocationType.OFFLINE })}
/>
<Button shape="primaryLine" $size="md" onClick={handleClickAddressSearch}>
주소 검색
</Button>
</Styled.InputWithButton>
<InputField
$size="md"
placeholder="장소"
{...register('placeName', { required: locationType === LocationType.OFFLINE })}
placeholder="상세 주소를 입력해 주세요 (ex. 동, 호, 층 등)"
{...register('detailAddress')}
/>
<Button shape="primaryLine" $size="md" onClick={handleClickAddressSearch}>
주소 검색
</Button>
</Styled.InputWithButton>
</Styled.LocationWrapper>
)}
</div>
</Styled.ScheduleContent>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,16 @@ export const RequiredDot = styled.span`
export const RadioButtonGroup = styled.div`
display: flex;
gap: 2rem;
margin-bottom: 1rem;
margin-bottom: 0.6rem;
`;

export const InputWithButton = styled.div`
display: flex;
gap: 1rem;
`;

export const LocationWrapper = styled.div`
display: flex;
flex-direction: column;
gap: 0.6rem;
`;
1 change: 1 addition & 0 deletions src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ export { default as useHistory } from './useHistory';
export { default as usePrompt } from './usePrompt';
export { default as useMyTeam } from './useMyTeam';
export { default as useRefreshSelectorFamilyByKey } from './useRefreshSelectorFamilyByKey';
export { default as useScript } from './useScript';
15 changes: 15 additions & 0 deletions src/hooks/useScript.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { useEffect } from 'react';

const useScript = (url: string) => {
Copy link
Member

Choose a reason for hiding this comment

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

해당 hook에서 isScriptLoaded 같은 상태를 관리하고 hook 외부로 헤딩 싱태를 return 해주면 hook의 사용도가 더 올라갈거 같다는 생각!

useEffect(() => {
const script = document.createElement('script');
script.src = url;
script.async = true;
document.body.appendChild(script);
return () => {
document.body.removeChild(script);
};
}, [url]);
};

export default useScript;
38 changes: 32 additions & 6 deletions src/utils/schedule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export interface ScheduleFormValues {
longitude: string;
placeName: string;
};
detailAddress?: string;
}

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

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

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

const isOffline = !!location.address;
if (address) {
// address의 형식: 주소 (상세주소)
const baseAddress = address.replace(/\s*\(.*?\)\s*/g, '');
const [, detailAddress] = address.match(/\(([^)]+)\)/) ?? [];
Comment on lines +70 to +71
Copy link
Member

Choose a reason for hiding this comment

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

이건 내 개인취향인데 정규식은 최대한 하는일에 맞게 이름을 지어주면 코드 파악이나 유지보수 할때 좋은거 같아! 사실 정규식이 한눈에 딱 보고 뭐하는지 알기가 힘드니ㅎㅎ

return {
name,
generationNumber,
date,
sessions,
locationType: LocationType.OFFLINE,
placeName,
detailAddress,
locationInfo: {
address: baseAddress,
latitude: String(latitude),
longitude: String(longitude),
placeName,
},
};
}

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

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

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

Expand All @@ -99,7 +125,7 @@ export const parseFormValuesToScheduleRequest = (
};

if (locationType === LocationType.OFFLINE && locationInfo) {
scheduleRequest.address = locationInfo.address;
scheduleRequest.address = `${locationInfo.address}${detailAddress ? `(${detailAddress})` : ''}`;
scheduleRequest.latitude = Number(locationInfo.latitude);
scheduleRequest.longitude = Number(locationInfo.longitude);
scheduleRequest.placeName = locationInfo.placeName;
Expand Down
Loading