Skip to content

Commit cb2d900

Browse files
committed
feat: 맵 컴포넌트 테스트 페이지 추가
1 parent 5d3a09f commit cb2d900

File tree

2 files changed

+111
-2
lines changed

2 files changed

+111
-2
lines changed

apps/pyconkr/src/components/pages/test.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@ import { Button, Stack } from "@mui/material";
22
import * as React from "react";
33

44
import { BackendTestPage } from "../../debug/page/backend_test";
5+
import { MapTestPage } from "../../debug/page/map_test";
56
import { MdiTestPage } from "../../debug/page/mdi_test";
67
import { ShopTestPage } from "../../debug/page/shop_test";
78

89
const LOCAL_STORAGE_KEY = "selectedTab";
9-
type SelectedTabType = "shop" | "mdi" | "backend";
10+
type SelectedTabType = "shop" | "mdi" | "backend" | "map";
1011

1112
const getTabFromLocalStorage = (): SelectedTabType =>
1213
(localStorage.getItem(LOCAL_STORAGE_KEY) as SelectedTabType) || "shop";
@@ -20,6 +21,7 @@ const TabList: { [key in SelectedTabType]: React.ReactNode } = {
2021
shop: <ShopTestPage />,
2122
mdi: <MdiTestPage />,
2223
backend: <BackendTestPage />,
24+
map: <MapTestPage />,
2325
};
2426

2527
export const Test: React.FC = () => {
@@ -32,7 +34,7 @@ export const Test: React.FC = () => {
3234
);
3335

3436
return (
35-
<Stack>
37+
<Stack sx={{ width: "100%", height: "100%", minHeight: "100%", flexGrow: 1, py: 2 }} spacing={2}>
3638
<Stack direction="row" spacing={2} sx={{ width: "100%", justifyContent: "center" }}>
3739
{Object.keys(TabList).map((tab) => (
3840
<TabButton key={tab} tab={tab as SelectedTabType} />
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import * as Common from "@frontend/common";
2+
import { Box, Button, FormControlLabel, Stack, Switch, TextField } from "@mui/material";
3+
import * as React from "react";
4+
5+
type MapTestPageStateType = {
6+
checked: boolean;
7+
mapProps: Common.Components.MDX.MapPropType;
8+
};
9+
10+
const INITIAL_DATA: Common.Components.MDX.MapPropType = {
11+
language: "ko",
12+
geo: { lat: 37.5580918, lng: 126.9982178 },
13+
placeName: {
14+
ko: "동국대학교 신공학관",
15+
en: "Dongguk University\nNew Engineering Building",
16+
},
17+
placeCode: {
18+
kakao: "17579989",
19+
google: "gryFHrZub6tsXdwb9",
20+
naver: "5IieESq8",
21+
},
22+
googleMapIframeSrc:
23+
"https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3162.871473157695!2d126.99821779999999!3d37.5580918!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x357ca302befa0c31%3A0xbc66c66731962172!2z64-Z6rWt64yA7ZWZ6rWQIOyLoOqzte2Vmeq0gA!5e0!3m2!1sko!2sen!4v1748768615566!5m2!1sko!2sen",
24+
};
25+
26+
export const MapTestPage: React.FC = () => {
27+
const geoFormRef = React.useRef<HTMLFormElement>(null);
28+
const placeNameFormRef = React.useRef<HTMLFormElement>(null);
29+
const placeCodeFormRef = React.useRef<HTMLFormElement>(null);
30+
const gMapIframeUrlInputRef = React.useRef<HTMLInputElement>(null);
31+
32+
const [state, setState] = React.useState<MapTestPageStateType>({ checked: false, mapProps: INITIAL_DATA });
33+
const setChecked = (checked: boolean) => setState((ps) => ({ ...ps, checked }));
34+
const language = state.checked ? "en" : "ko";
35+
36+
const onApply = () => {
37+
const geoForm = geoFormRef.current;
38+
const pNameForm = placeNameFormRef.current;
39+
const pCodeForm = placeCodeFormRef.current;
40+
const gMapIframeUrl = gMapIframeUrlInputRef.current;
41+
42+
[geoForm, pNameForm, pCodeForm, gMapIframeUrl].forEach((formOrInput, index) => {
43+
if (!formOrInput) throw new Error(`${formOrInput}[${index}] is not defined.`);
44+
45+
if (formOrInput instanceof HTMLFormElement && !Common.Utils.isFormValid(formOrInput))
46+
throw new Error(`${formOrInput}[${index}] is not valid.`);
47+
48+
if (formOrInput instanceof HTMLInputElement && !formOrInput.checkValidity())
49+
throw new Error(`${formOrInput}[${index}] is not valid.`);
50+
});
51+
if (!(geoForm && pNameForm && pCodeForm && gMapIframeUrl)) return;
52+
53+
const strGeo = Common.Utils.getFormValue<{ lat: string; lng: string }>({ form: geoForm });
54+
if (!strGeo.lat || !strGeo.lng || isNaN(parseFloat(strGeo.lat)) || isNaN(parseFloat(strGeo.lng))) {
55+
alert("위도와 경도를 올바르게 입력해주세요.");
56+
return;
57+
}
58+
const geo = { lat: parseFloat(strGeo.lat), lng: parseFloat(strGeo.lng) };
59+
const googleMapIframeSrc = gMapIframeUrl.value.trim();
60+
const placeCode = Common.Utils.getFormValue<{ kakao: string; naver: string; google: string }>({ form: pCodeForm });
61+
const placeName = Common.Utils.getFormValue<{ ko: string; en: string }>({ form: pNameForm });
62+
placeName.ko = placeName.ko.trim().replace("\\n", "\n");
63+
placeName.en = placeName.en.trim().replace("\\n", "\n");
64+
65+
setState((ps) => ({ ...ps, mapProps: { language, geo, placeCode, placeName, googleMapIframeSrc } }));
66+
};
67+
68+
return (
69+
<Stack direction="row" spacing={2} sx={{ p: 2 }}>
70+
<Stack spacing={2} sx={{ width: "50%", maxWidth: "50%" }}>
71+
<FormControlLabel
72+
control={<Switch checked={state.checked} onChange={(e) => setChecked(e.target.checked)} />}
73+
label={language}
74+
/>
75+
<form ref={geoFormRef}>
76+
<Stack spacing={1}>
77+
<TextField label="Latitude" name="lat" defaultValue={state.mapProps.geo.lat} />
78+
<TextField label="Longitude" name="lng" defaultValue={state.mapProps.geo.lng} />
79+
</Stack>
80+
</form>
81+
<form ref={placeNameFormRef}>
82+
<Stack spacing={1}>
83+
<TextField label="명칭 (KR)" name="ko" defaultValue={state.mapProps.placeName.ko} />
84+
<TextField label="명칭 (EN)" name="en" defaultValue={state.mapProps.placeName.en} />
85+
</Stack>
86+
</form>
87+
<form ref={placeCodeFormRef}>
88+
<Stack spacing={1}>
89+
<TextField label="Kakaomap Code" name="kakao" defaultValue={state.mapProps.placeCode.kakao} />
90+
<TextField label="Google Maps Code" name="google" defaultValue={state.mapProps.placeCode.google} />
91+
<TextField label="Naver Shortened URL Code" name="naver" defaultValue={state.mapProps.placeCode.naver} />
92+
</Stack>
93+
</form>
94+
<TextField
95+
label="Google Map Iframe URL"
96+
type="url"
97+
inputRef={gMapIframeUrlInputRef}
98+
defaultValue={state.mapProps.googleMapIframeSrc}
99+
/>
100+
<Button onClick={onApply}>적용</Button>
101+
</Stack>
102+
<Box sx={{ width: "50%", maxWidth: "50%" }}>
103+
<Common.Components.MDX.Map {...state.mapProps} />
104+
</Box>
105+
</Stack>
106+
);
107+
};

0 commit comments

Comments
 (0)