@uniai-fe/uds-templates 0.5.29 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/README.md +3 -6
  2. package/package.json +1 -1
  3. package/src/weather/_legacy/apis/index.ts +4 -0
  4. package/src/weather/_legacy/data/response.ts +36 -0
  5. package/src/weather/_legacy/hooks/index.ts +5 -0
  6. package/src/weather/{hooks → _legacy/hooks}/useOpenWeatherMap.ts +1 -1
  7. package/src/weather/{hooks → _legacy/hooks}/useWeatherKorea.ts +4 -7
  8. package/src/weather/{hooks → _legacy/hooks}/useWeatherKoreaAlert.ts +2 -4
  9. package/src/weather/_legacy/types/api.ts +221 -0
  10. package/src/weather/_legacy/types/base.ts +70 -0
  11. package/src/weather/_legacy/types/index.ts +4 -0
  12. package/src/weather/_legacy/utils/index.ts +5 -0
  13. package/src/weather/_legacy/utils/locale.ts +28 -0
  14. package/src/weather/_legacy/utils/location.ts +139 -0
  15. package/src/weather/_legacy/utils/weather.ts +460 -0
  16. package/src/weather/apis/client.ts +339 -0
  17. package/src/weather/apis/index.ts +2 -4
  18. package/src/weather/apis/server.ts +264 -0
  19. package/src/weather/components/icon/Address.tsx +7 -0
  20. package/src/weather/components/icon/Weather.tsx +7 -6
  21. package/src/weather/components/page-header/Address.tsx +14 -0
  22. package/src/weather/components/page-header/Alert.tsx +17 -13
  23. package/src/weather/components/page-header/Container.tsx +12 -19
  24. package/src/weather/components/page-header/Forecast.tsx +21 -28
  25. package/src/weather/components/page-header/NextDays.tsx +10 -0
  26. package/src/weather/components/page-header/Today.tsx +86 -158
  27. package/src/weather/components/page-header/index.ts +5 -0
  28. package/src/weather/data/response.ts +4 -23
  29. package/src/weather/hooks/index.ts +3 -3
  30. package/src/weather/hooks/useWeather.ts +52 -0
  31. package/src/weather/hooks/useWeatherAlert.ts +35 -0
  32. package/src/weather/index.tsx +2 -2
  33. package/src/weather/jotai/coordinate.ts +4 -0
  34. package/src/weather/jotai/farm-idx.ts +4 -0
  35. package/src/weather/types/api.ts +393 -114
  36. package/src/weather/types/base.ts +15 -32
  37. package/src/weather/types/index.ts +0 -3
  38. package/src/weather/types/page-header.ts +118 -68
  39. package/src/weather/utils/index.ts +6 -4
  40. package/src/weather/utils/locale.ts +7 -69
  41. package/src/weather/utils/location.ts +6 -141
  42. package/src/weather/utils/weather.ts +53 -456
  43. package/src/weather/data/alert-regions-meta.json +0 -1286
  44. package/src/weather/data/weather-regions-meta.json +0 -9833
  45. package/src/weather/types/provider.ts +0 -34
  46. package/src/weather/utils/alert.ts +0 -30
  47. /package/src/weather/{apis → _legacy/apis}/korea/client.ts +0 -0
  48. /package/src/weather/{apis → _legacy/apis}/korea/server.ts +0 -0
  49. /package/src/weather/{apis → _legacy/apis}/open-weather-map/client.ts +0 -0
  50. /package/src/weather/{apis → _legacy/apis}/open-weather-map/server.ts +0 -0
  51. /package/src/weather/{types → _legacy/types}/korea.ts +0 -0
  52. /package/src/weather/{types → _legacy/types}/open-weather-map.ts +0 -0
  53. /package/src/weather/{utils → _legacy/utils}/date-time.ts +0 -0
  54. /package/src/weather/{utils → _legacy/utils}/validate.ts +0 -0
@@ -1,15 +1,12 @@
1
1
  import type {
2
- API_Res_WeatherKoreaForecast,
3
- API_Res_WeatherKoreaNextDays,
4
- API_Res_WeatherKoreaNow,
2
+ API_Res_WeatherAlertItem,
3
+ API_Res_WeatherForecast,
4
+ API_Res_WeatherNextDays,
5
+ API_Res_WeatherNow,
5
6
  } from "./api";
6
- import type {
7
- OWM_Res_Weather_Forecast,
8
- OWM_Res_Weather_Now,
9
- } from "./open-weather-map";
10
7
 
11
8
  /**
12
- * Weather Page Header; locale 옵션
9
+ * Weather Page Header; locale 옵션.
13
10
  * @property {string} [locale] 표시 언어 코드. 기본 지원값은 ko, en, ja이며 타입은 확장 가능한 string으로 유지한다.
14
11
  */
15
12
  export interface WeatherLocaleOptions {
@@ -20,7 +17,7 @@ export interface WeatherLocaleOptions {
20
17
  }
21
18
 
22
19
  /**
23
- * Weather Page Header; 텍스트 옵션
20
+ * Weather Page Header; 텍스트 옵션.
24
21
  * @property {string} currentWeatherLoading 현재 날씨 로딩 문구
25
22
  * @property {string} forecastWeatherLoading 예보 날씨 로딩 문구
26
23
  * @property {string} alertLoading 특보 로딩 문구
@@ -106,11 +103,15 @@ export interface WeatherPageHeaderTexts {
106
103
  }
107
104
 
108
105
  /**
109
- * Weather Page Header; locale과 텍스트 override 조합 옵션
106
+ * Weather Page Header; locale과 텍스트 override 조합 옵션.
110
107
  * @property {string} [locale] 표시 언어 코드
111
108
  * @property {Partial<WeatherPageHeaderTexts>} [texts] 서비스에서 주입한 표시 문구
112
109
  */
113
110
  export interface WeatherPageHeaderLocaleOptions extends WeatherLocaleOptions {
111
+ /**
112
+ * 표시 언어 코드
113
+ */
114
+ locale?: string;
114
115
  /**
115
116
  * 서비스에서 주입한 표시 문구
116
117
  */
@@ -118,47 +119,32 @@ export interface WeatherPageHeaderLocaleOptions extends WeatherLocaleOptions {
118
119
  }
119
120
 
120
121
  /**
121
- * Weather Page Header; KMA weather query 결과
122
- * @property {API_Res_WeatherKoreaNow} [now] 현재 날씨 응답
123
- * @property {API_Res_WeatherKoreaForecast} [forecast] 예보 날씨 응답
122
+ * Weather Page Header; 통합 weather query 결과.
123
+ * @property {API_Res_WeatherNow} [now] 현재 날씨 응답
124
+ * @property {API_Res_WeatherForecast} [forecast] 예보 날씨 응답
125
+ * @property {API_Res_WeatherAlertItem[]} alert 특보 목록
126
+ * @property {boolean} isFetching 현재/예보/특보 조회 상태
124
127
  * @property {boolean} isFetchingNow 현재 날씨 조회 상태
125
128
  * @property {boolean} isFetchingForecast 예보 날씨 조회 상태
129
+ * @property {boolean} isFetchingAlert 특보 조회 상태
126
130
  */
127
- export interface WeatherPageHeaderKoreaWeather {
131
+ export interface WeatherPageHeaderWeather {
128
132
  /**
129
133
  * 현재 날씨 응답
130
134
  */
131
- now?: API_Res_WeatherKoreaNow;
135
+ now?: API_Res_WeatherNow;
132
136
  /**
133
137
  * 예보 날씨 응답
134
138
  */
135
- forecast?: API_Res_WeatherKoreaForecast;
136
- /**
137
- * 현재 날씨 조회 상태
138
- */
139
- isFetchingNow: boolean;
140
- /**
141
- * 예보 날씨 조회 상태
142
- */
143
- isFetchingForecast: boolean;
144
- }
145
-
146
- /**
147
- * Weather Page Header; OpenWeatherMap query 결과
148
- * @property {OWM_Res_Weather_Now} [now] 현재 날씨 응답
149
- * @property {OWM_Res_Weather_Forecast} [forecast] 예보 날씨 응답
150
- * @property {boolean} isFetchingNow 현재 날씨 조회 상태
151
- * @property {boolean} isFetchingForecast 예보 날씨 조회 상태
152
- */
153
- export interface WeatherPageHeaderOpenWeatherMapWeather {
139
+ forecast?: API_Res_WeatherForecast;
154
140
  /**
155
- * 현재 날씨 응답
141
+ * 특보 목록
156
142
  */
157
- now?: OWM_Res_Weather_Now;
143
+ alert: API_Res_WeatherAlertItem[];
158
144
  /**
159
- * 예보 날씨 응답
145
+ * 현재/예보/특보 조회 상태
160
146
  */
161
- forecast?: OWM_Res_Weather_Forecast;
147
+ isFetching: boolean;
162
148
  /**
163
149
  * 현재 날씨 조회 상태
164
150
  */
@@ -167,73 +153,137 @@ export interface WeatherPageHeaderOpenWeatherMapWeather {
167
153
  * 예보 날씨 조회 상태
168
154
  */
169
155
  isFetchingForecast: boolean;
156
+ /**
157
+ * 특보 조회 상태
158
+ */
159
+ isFetchingAlert: boolean;
170
160
  }
171
161
 
172
162
  /**
173
- * Weather Page Header; 상위 container에서 준비한 weather query 결과
174
- * @property {WeatherPageHeaderKoreaWeather} [koreaWeather] KMA weather query 결과
175
- * @property {WeatherPageHeaderOpenWeatherMapWeather} [openWeatherMapWeather] OpenWeatherMap query 결과
163
+ * Weather Page Header; 상위 container에서 준비한 weather query 결과.
164
+ * @property {WeatherPageHeaderWeather} [weather] 통합 weather query 결과
176
165
  */
177
166
  export interface WeatherPageHeaderDataOptions {
178
167
  /**
179
- * KMA weather query 결과
168
+ * 통합 weather query 결과
180
169
  */
181
- koreaWeather?: WeatherPageHeaderKoreaWeather;
182
- /**
183
- * OpenWeatherMap query 결과
184
- */
185
- openWeatherMapWeather?: WeatherPageHeaderOpenWeatherMapWeather;
170
+ weather?: WeatherPageHeaderWeather;
186
171
  }
187
172
 
188
173
  /**
189
- * Weather Page Header; container props
174
+ * Weather Page Header; container props.
190
175
  * @property {string} [locale] 표시 언어 코드
191
176
  * @property {Partial<WeatherPageHeaderTexts>} [texts] 서비스에서 주입한 표시 문구
192
177
  */
193
- export type WeatherPageHeaderContainerProps = WeatherPageHeaderLocaleOptions;
178
+ export interface WeatherPageHeaderContainerProps extends WeatherPageHeaderLocaleOptions {
179
+ /**
180
+ * 표시 언어 코드
181
+ */
182
+ locale?: string;
183
+ /**
184
+ * 서비스에서 주입한 표시 문구
185
+ */
186
+ texts?: Partial<WeatherPageHeaderTexts>;
187
+ }
194
188
 
195
189
  /**
196
- * Weather Page Header; address props
190
+ * Weather Page Header; address props.
197
191
  * @property {string} [locale] 표시 언어 코드
198
192
  * @property {Partial<WeatherPageHeaderTexts>} [texts] 서비스에서 주입한 표시 문구
199
193
  */
200
- export type WeatherPageHeaderAddressProps = WeatherPageHeaderLocaleOptions;
194
+ export interface WeatherPageHeaderAddressProps extends WeatherPageHeaderLocaleOptions {
195
+ /**
196
+ * 표시 언어 코드
197
+ */
198
+ locale?: string;
199
+ /**
200
+ * 서비스에서 주입한 표시 문구
201
+ */
202
+ texts?: Partial<WeatherPageHeaderTexts>;
203
+ }
201
204
 
202
205
  /**
203
- * Weather Page Header; today props
206
+ * Weather Page Header; today props.
204
207
  * @property {string} [locale] 표시 언어 코드
205
208
  * @property {Partial<WeatherPageHeaderTexts>} [texts] 서비스에서 주입한 표시 문구
206
- * @property {WeatherPageHeaderKoreaWeather} [koreaWeather] KMA weather query 결과
207
- * @property {WeatherPageHeaderOpenWeatherMapWeather} [openWeatherMapWeather] OpenWeatherMap query 결과
209
+ * @property {WeatherPageHeaderWeather} [weather] 상위 container에서 준비한 통합 weather query 결과
208
210
  */
209
- export type WeatherPageHeaderTodayProps = WeatherPageHeaderLocaleOptions &
210
- WeatherPageHeaderDataOptions;
211
+ export interface WeatherPageHeaderTodayProps
212
+ extends WeatherPageHeaderLocaleOptions, WeatherPageHeaderDataOptions {
213
+ /**
214
+ * 표시 언어 코드
215
+ */
216
+ locale?: string;
217
+ /**
218
+ * 서비스에서 주입한 표시 문구
219
+ */
220
+ texts?: Partial<WeatherPageHeaderTexts>;
221
+ /**
222
+ * 통합 weather query 결과
223
+ */
224
+ weather?: WeatherPageHeaderWeather;
225
+ }
211
226
 
212
227
  /**
213
- * Weather Page Header; forecast props
228
+ * Weather Page Header; forecast props.
214
229
  * @property {string} [locale] 표시 언어 코드
215
230
  * @property {Partial<WeatherPageHeaderTexts>} [texts] 서비스에서 주입한 표시 문구
216
- * @property {WeatherPageHeaderKoreaWeather} [koreaWeather] KMA weather query 결과
217
- * @property {WeatherPageHeaderOpenWeatherMapWeather} [openWeatherMapWeather] OpenWeatherMap query 결과
231
+ * @property {WeatherPageHeaderWeather} [weather] 상위 container에서 준비한 통합 weather query 결과
218
232
  */
219
- export type WeatherPageHeaderForecastProps = WeatherPageHeaderLocaleOptions &
220
- WeatherPageHeaderDataOptions;
233
+ export interface WeatherPageHeaderForecastProps
234
+ extends WeatherPageHeaderLocaleOptions, WeatherPageHeaderDataOptions {
235
+ /**
236
+ * 표시 언어 코드
237
+ */
238
+ locale?: string;
239
+ /**
240
+ * 서비스에서 주입한 표시 문구
241
+ */
242
+ texts?: Partial<WeatherPageHeaderTexts>;
243
+ /**
244
+ * 통합 weather query 결과
245
+ */
246
+ weather?: WeatherPageHeaderWeather;
247
+ }
221
248
 
222
249
  /**
223
- * Weather Page Header; alert props
250
+ * Weather Page Header; alert props.
224
251
  * @property {string} [locale] 표시 언어 코드
225
252
  * @property {Partial<WeatherPageHeaderTexts>} [texts] 서비스에서 주입한 표시 문구
253
+ * @property {WeatherPageHeaderWeather} [weather] 상위 container에서 준비한 통합 weather query 결과
226
254
  */
227
- export type WeatherPageHeaderAlertProps = WeatherPageHeaderLocaleOptions;
255
+ export interface WeatherPageHeaderAlertProps
256
+ extends WeatherPageHeaderLocaleOptions, WeatherPageHeaderDataOptions {
257
+ /**
258
+ * 표시 언어 코드
259
+ */
260
+ locale?: string;
261
+ /**
262
+ * 서비스에서 주입한 표시 문구
263
+ */
264
+ texts?: Partial<WeatherPageHeaderTexts>;
265
+ /**
266
+ * 통합 weather query 결과
267
+ */
268
+ weather?: WeatherPageHeaderWeather;
269
+ }
228
270
 
229
271
  /**
230
- * Weather Page Header; next days props
272
+ * Weather Page Header; next days props.
231
273
  * @property {string} title 날짜 라벨
232
- * @property {API_Res_WeatherKoreaNextDays} [data] 예보 데이터
274
+ * @property {API_Res_WeatherNextDays} [data] 예보 데이터
233
275
  * @property {string} [locale] 표시 언어 코드
234
276
  * @property {Partial<WeatherPageHeaderTexts>} [texts] 서비스에서 주입한 표시 문구
235
277
  */
236
278
  export interface WeatherPageHeaderNextDaysProps extends WeatherPageHeaderLocaleOptions {
279
+ /**
280
+ * 표시 언어 코드
281
+ */
282
+ locale?: string;
283
+ /**
284
+ * 서비스에서 주입한 표시 문구
285
+ */
286
+ texts?: Partial<WeatherPageHeaderTexts>;
237
287
  /**
238
288
  * 날짜 라벨
239
289
  */
@@ -241,11 +291,11 @@ export interface WeatherPageHeaderNextDaysProps extends WeatherPageHeaderLocaleO
241
291
  /**
242
292
  * 예보 데이터
243
293
  */
244
- data?: API_Res_WeatherKoreaNextDays;
294
+ data?: API_Res_WeatherNextDays;
245
295
  }
246
296
 
247
297
  /**
248
- * Weather Icon; 날씨 아이콘 props
298
+ * Weather Icon; 날씨 아이콘 props.
249
299
  * @property {string | null} [code] 날씨 아이콘 코드
250
300
  * @property {string | null} [name] 날씨 상태 이름
251
301
  * @property {string} [alt] 아이콘 대체 텍스트 fallback
@@ -266,7 +316,7 @@ export interface WeatherIconProps {
266
316
  }
267
317
 
268
318
  /**
269
- * Weather Address Icon; 위치 아이콘 props
319
+ * Weather Address Icon; 위치 아이콘 props.
270
320
  * @property {string} [alt] 아이콘 대체 텍스트
271
321
  */
272
322
  export interface WeatherAddressIconProps {
@@ -1,5 +1,7 @@
1
1
  export * from "./location";
2
- export * from "./date-time";
3
- export * from "./weather";
4
- export * from "./alert";
5
- export * from "./locale";
2
+ export {
3
+ isWeatherForecastResponse,
4
+ isWeatherNowResponse,
5
+ isWeatherSummaryResponse,
6
+ } from "./weather";
7
+ export { getWeatherLocaleKey, resolveWeatherPageHeaderTexts } from "./locale";
@@ -1,8 +1,4 @@
1
- import type {
2
- WeatherPageHeaderTexts,
3
- WeatherProviderCapabilityRegistry,
4
- WeatherProviderKey,
5
- } from "../types";
1
+ import type { WeatherPageHeaderTexts } from "../types";
6
2
 
7
3
  const WEATHER_PAGE_HEADER_DEFAULT_TEXTS: WeatherPageHeaderTexts = {
8
4
  currentWeatherLoading: "현재 날씨 불러오는 중...",
@@ -23,34 +19,10 @@ const WEATHER_PAGE_HEADER_DEFAULT_TEXTS: WeatherPageHeaderTexts = {
23
19
  alertIssueCommandLabel: "발령",
24
20
  };
25
21
 
26
- const OPEN_WEATHER_MAP_LANG_BY_LOCALE: Record<string, string> = {
27
- ko: "kr",
28
- en: "en",
29
- ja: "ja",
30
- };
31
-
32
- const WEATHER_DEFAULT_PROVIDER: WeatherProviderKey = "openWeatherMap";
33
-
34
- const WEATHER_PROVIDER_BY_LOCALE_KEY: Record<string, WeatherProviderKey> = {
35
- ko: "kma",
36
- };
37
-
38
- export const WEATHER_PROVIDER_CAPABILITIES: WeatherProviderCapabilityRegistry =
39
- {
40
- kma: {
41
- now: true,
42
- forecast: true,
43
- alert: true,
44
- },
45
- openWeatherMap: {
46
- now: true,
47
- forecast: true,
48
- alert: false,
49
- },
50
- };
51
-
52
22
  /**
53
- * Weather Locale; locale 기준 키 정규화
23
+ * Weather Locale; locale 기준 키 정규화.
24
+ * @util
25
+ * @desc service locale 문자열에서 weather API/표시 로직에 사용할 기본 언어 키를 추출한다.
54
26
  * @param {string} [locale] locale 코드
55
27
  * @return {string} 전달된 locale의 기본 언어 코드
56
28
  * @example
@@ -60,30 +32,9 @@ export const getWeatherLocaleKey = (locale?: string): string =>
60
32
  locale?.trim().toLowerCase().split(/[-_]/)[0] || "ko";
61
33
 
62
34
  /**
63
- * Weather Locale; locale 기준 provider 선택
64
- * @param {string} [locale] locale 코드
65
- * @return {WeatherProviderKey} 현재 locale에 사용할 weather provider
66
- * @example
67
- * resolveWeatherProvider("ko-KR")
68
- */
69
- export const resolveWeatherProvider = (locale?: string): WeatherProviderKey => {
70
- const localeKey = getWeatherLocaleKey(locale);
71
-
72
- return WEATHER_PROVIDER_BY_LOCALE_KEY[localeKey] ?? WEATHER_DEFAULT_PROVIDER;
73
- };
74
-
75
- /**
76
- * Weather Locale; KMA provider 사용 여부
77
- * @param {string} [locale] locale 코드
78
- * @return {boolean} KMA provider 대상 locale 여부
79
- * @example
80
- * isKoreaWeatherLocale("ko-KR")
81
- */
82
- export const isKoreaWeatherLocale = (locale?: string): boolean =>
83
- resolveWeatherProvider(locale) === "kma";
84
-
85
- /**
86
- * Weather Locale; page-header 텍스트 병합
35
+ * Weather Locale; page-header 텍스트 병합.
36
+ * @util
37
+ * @desc service가 주입한 일부 표시 문구를 weather page-header 기본 문구와 병합한다.
87
38
  * @param {Partial<WeatherPageHeaderTexts>} [texts] 서비스에서 주입한 텍스트
88
39
  * @return {WeatherPageHeaderTexts} 기본 fallback과 서비스 주입 텍스트를 병합한 텍스트
89
40
  * @example
@@ -95,16 +46,3 @@ export const resolveWeatherPageHeaderTexts = (
95
46
  ...WEATHER_PAGE_HEADER_DEFAULT_TEXTS,
96
47
  ...texts,
97
48
  });
98
-
99
- /**
100
- * Weather Locale; OpenWeatherMap API lang 값 변환
101
- * @param {string} [locale] locale 코드
102
- * @return {string} OpenWeatherMap lang 파라미터
103
- * @example
104
- * getOpenWeatherMapLang("ko")
105
- */
106
- export const getOpenWeatherMapLang = (locale?: string): string => {
107
- const localeKey = getWeatherLocaleKey(locale);
108
-
109
- return OPEN_WEATHER_MAP_LANG_BY_LOCALE[localeKey] ?? localeKey;
110
- };
@@ -1,18 +1,13 @@
1
- import type {
2
- GeoCoordinate,
3
- KMA_GridCoordinate,
4
- KMA_Req_BaseGridCoordinate,
5
- WeatherCoordinate,
6
- } from "../types";
1
+ import type { GeoCoordinate } from "../types";
7
2
 
8
3
  /**
9
- * 날씨 도구; 접속위치 추출
4
+ * 날씨 도구; 접속위치 추출.
10
5
  * @util
11
- * @return {GeoCoordinate}}
6
+ * @desc 브라우저 geolocation API에서 현재 위치를 읽고, 사용할 수 없으면 null 좌표를 반환한다.
7
+ * @return {Promise<GeoCoordinate>} 브라우저 geolocation에서 읽은 위경도
12
8
  */
13
9
  export const userLocation = async (): Promise<GeoCoordinate> => {
14
10
  if (typeof window === "undefined" || !window.navigator.geolocation) {
15
- // console.log("[userLocation] window 없음");
16
11
  return { latitude: null, longitude: null };
17
12
  }
18
13
 
@@ -22,143 +17,13 @@ export const userLocation = async (): Promise<GeoCoordinate> => {
22
17
  window.navigator.geolocation.getCurrentPosition(resolve, reject);
23
18
  },
24
19
  );
25
- // console.log("[userLocation] 위치 정보:", position.coords);
26
- const res = {
20
+
21
+ return {
27
22
  latitude: position.coords.latitude,
28
23
  longitude: position.coords.longitude,
29
24
  };
30
- return res;
31
25
  } catch (error) {
32
26
  console.error("[userLocation] 위치 정보 에러", error);
33
27
  return { latitude: null, longitude: null };
34
28
  }
35
29
  };
36
-
37
- /**
38
- * 날씨 도구; 위경도 -> 격자 좌표 변환
39
- * @util
40
- * @param {GeoCoordinate} coordinate - 위경도 좌표
41
- * @param {number} coordinate.latitude - 위도
42
- * @param {number} coordinate.longitude - 경도
43
- * @return {KMA_GridCoordinate} 격자 좌표
44
- * @desc
45
- * - 위경도 좌표를 기상청 격자 좌표로 변환합니다.
46
- * - 출처: 기상청
47
- * @see https://apihub.kma.go.kr/
48
- * @see https://apihub.kma.go.kr/getAttachFile.do?fileName=%EB%8B%A8%EA%B8%B0%EC%98%88%EB%B3%B4%20%EC%A1%B0%ED%9A%8C%EC%84%9C%EB%B9%84%EC%8A%A4_API%ED%99%9C%EC%9A%A9%EA%B0%80%EC%9D%B4%EB%93%9C_241128.docx
49
- */
50
- export function convertCoordinateToGrid({
51
- latitude,
52
- longitude,
53
- }: GeoCoordinate): KMA_GridCoordinate {
54
- const res: KMA_GridCoordinate = { x: 0, y: 0 };
55
-
56
- if (latitude === null || longitude === null) return res;
57
-
58
- const RE = 6371.00877; // Earth radius (km)
59
- const GRID = 5.0; // Grid spacing (km)
60
- const SLAT1 = 30.0; // Projection latitude 1 (degree)
61
- const SLAT2 = 60.0; // Projection latitude 2 (degree)
62
- const ORIGIN_LONGITUDE = 126.0; // Origin longitude (degree)
63
- const ORIGIN_LATITUDE = 38.0; // Origin latitude (degree)
64
- const XO = 43; // Origin X coordinate (GRID)
65
- const YO = 136; // Origin Y coordinate (GRID)
66
-
67
- const RADIAN = Math.PI / 180.0;
68
- const re = RE / GRID;
69
- const slat1 = SLAT1 * RADIAN;
70
- const slat2 = SLAT2 * RADIAN;
71
- const origin_longitude = ORIGIN_LONGITUDE * RADIAN;
72
- const origin_latitude = ORIGIN_LATITUDE * RADIAN;
73
-
74
- const sn =
75
- Math.log(Math.cos(slat1) / Math.cos(slat2)) /
76
- Math.log(
77
- Math.tan(Math.PI * 0.25 + slat2 * 0.5) /
78
- Math.tan(Math.PI * 0.25 + slat1 * 0.5),
79
- );
80
-
81
- const sf = Math.tan(Math.PI * 0.25 + slat1 * 0.5);
82
- const sfPow = (Math.pow(sf, sn) * Math.cos(slat1)) / sn;
83
-
84
- const ro =
85
- (re * sfPow) /
86
- Math.pow(Math.tan(Math.PI * 0.25 + origin_latitude * 0.5), sn);
87
-
88
- const ra =
89
- (re * sfPow) /
90
- Math.pow(Math.tan(Math.PI * 0.25 + latitude * RADIAN * 0.5), sn);
91
- let theta = longitude * RADIAN - origin_longitude;
92
- if (theta > Math.PI) theta -= 2.0 * Math.PI;
93
- if (theta < -Math.PI) theta += 2.0 * Math.PI;
94
- theta *= sn;
95
-
96
- res.x = Math.floor(ra * Math.sin(theta) + XO + 0.5);
97
- res.y = Math.floor(ro - ra * Math.cos(theta) + YO + 0.5);
98
-
99
- // console.log("[WEATHER] 위/경도 -> 기상청 격자값", res);
100
-
101
- return res;
102
- }
103
-
104
- /**
105
- * 날씨 도구; 위도/경도 -> 기상청 격자 좌표 변환
106
- * @util
107
- * @param {WeatherCoordinate} [coordinate] - 사용자 위치 이외의 특정 위도/경도 좌표
108
- * @param {number} coordinate.lat - 위도
109
- * @param {number} coordinate.lng - 경도
110
- * @return {KMA_Req_BaseGridCoordinate} 기상청 격자 좌표
111
- */
112
- export async function getWeatherGridLocation(
113
- coordinate?: WeatherCoordinate,
114
- ): Promise<KMA_Req_BaseGridCoordinate> {
115
- const res: KMA_Req_BaseGridCoordinate = { nx: 0, ny: 0 };
116
-
117
- if (typeof window === "undefined") return res;
118
-
119
- const geo: GeoCoordinate = {
120
- latitude: coordinate?.lat ?? null,
121
- longitude: coordinate?.lng ?? null,
122
- };
123
- const hasInjectedAddress =
124
- typeof coordinate?.address === "string" && coordinate.address.trim() !== "";
125
-
126
- // console.log("[getWeatherLocation] 특정 좌표지정 확인", coordinate);
127
-
128
- // 변경 설명: 서비스가 address만 명시적으로 주입한 경우에는 geolocation fallback을 재시도하지 않는다.
129
- if (
130
- typeof window !== "undefined" &&
131
- !hasInjectedAddress &&
132
- (typeof coordinate === "undefined" ||
133
- geo.latitude === null ||
134
- geo.longitude === null)
135
- ) {
136
- const { latitude, longitude } = await userLocation();
137
-
138
- if (latitude === null || longitude === null) {
139
- // console.log("[getWeatherLocation] window.navigator 실패", geo);
140
- return res;
141
- }
142
- geo.latitude = latitude;
143
- geo.longitude = longitude;
144
- // console.log("[getWeatherLocation] 사용자 위치", geo);
145
- }
146
-
147
- // 위경도 좌표를 기상청 격자좌표로 변환
148
- const grid = convertCoordinateToGrid(geo);
149
-
150
- if (grid.x === 0 || grid.y === 0) {
151
- // console.error("[getWeatherLocation] 위치 정보를 가져오는데 실패했습니다.", {
152
- // latitude: geo.latitude,
153
- // longitude: geo.longitude,
154
- // });
155
- return res;
156
- }
157
- // console.log("[getWeatherLocation] 기상청 격자좌표", grid);
158
-
159
- res.nx = grid.x;
160
- res.ny = grid.y;
161
-
162
- // console.log("[getWeatherLocation] result", res);
163
- return res;
164
- }