@uniai-fe/uds-templates 0.1.16 → 0.1.17

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 (92) hide show
  1. package/dist/styles.css +139 -10
  2. package/package.json +18 -11
  3. package/src/auth/common/complete/Template.tsx +3 -0
  4. package/src/auth/common/complete/types.ts +4 -1
  5. package/src/auth/common/find/markup/CodeStep.tsx +2 -1
  6. package/src/auth/common/find/markup/InfoStep.tsx +2 -1
  7. package/src/auth/common/find/styles/result.scss +1 -1
  8. package/src/auth/find-password/markup/StepResetPassword.tsx +2 -1
  9. package/src/auth/login/markup/FormField.tsx +2 -1
  10. package/src/auth/signup/markup/AccountForm.tsx +2 -1
  11. package/src/auth/signup/markup/Complete.tsx +2 -1
  12. package/src/auth/signup/markup/UserInfoForm.tsx +2 -1
  13. package/src/auth/signup/markup/VerificationForm.tsx +4 -2
  14. package/src/index.scss +1 -0
  15. package/src/index.tsx +1 -0
  16. package/src/modal/core/components/FooterButtons.tsx +4 -1
  17. package/src/modal/templates/Dialog.tsx +4 -2
  18. package/src/modal/types/footer.ts +4 -2
  19. package/src/page-frame/container/index.scss +14 -8
  20. package/src/page-frame/desktop/components/header/Container.tsx +22 -0
  21. package/src/page-frame/desktop/components/header/Section.tsx +20 -0
  22. package/src/page-frame/desktop/components/header/index.tsx +19 -0
  23. package/src/page-frame/desktop/components/header/util/Button.tsx +23 -0
  24. package/src/page-frame/desktop/components/header/util/Container.tsx +18 -0
  25. package/src/page-frame/desktop/components/header/util/Item.tsx +13 -0
  26. package/src/page-frame/desktop/components/header/util/Logout.tsx +26 -0
  27. package/src/page-frame/desktop/components/header/util/setting/Button.tsx +39 -0
  28. package/src/page-frame/desktop/components/index.tsx +15 -0
  29. package/src/page-frame/desktop/components/nav/Button.tsx +24 -0
  30. package/src/page-frame/desktop/components/nav/Container.tsx +70 -0
  31. package/src/page-frame/desktop/components/nav/Logo.tsx +46 -0
  32. package/src/page-frame/desktop/components/nav/index.tsx +5 -0
  33. package/src/page-frame/desktop/components/page/Container.tsx +13 -0
  34. package/src/page-frame/desktop/components/page/ServiceFrame.tsx +15 -0
  35. package/src/page-frame/desktop/components/page/ServiceMain.tsx +13 -0
  36. package/src/page-frame/desktop/components/page/ServiceMainWrapper.tsx +24 -0
  37. package/src/page-frame/desktop/components/page/index.tsx +14 -0
  38. package/src/page-frame/desktop/components/popup/Container.tsx +18 -0
  39. package/src/page-frame/desktop/components/popup/frame/Body.tsx +14 -0
  40. package/src/page-frame/desktop/components/popup/frame/Container.tsx +16 -0
  41. package/src/page-frame/desktop/components/popup/frame/Header.tsx +26 -0
  42. package/src/page-frame/desktop/components/popup/frame/index.tsx +11 -0
  43. package/src/page-frame/desktop/components/popup/index.tsx +9 -0
  44. package/src/page-frame/desktop/index.scss +5 -0
  45. package/src/page-frame/desktop/index.tsx +5 -0
  46. package/src/page-frame/desktop/styles/page/common.scss +40 -0
  47. package/src/page-frame/desktop/styles/page/header.scss +49 -0
  48. package/src/page-frame/desktop/styles/page/nav.scss +128 -0
  49. package/src/page-frame/desktop/styles/popup/popup.scss +45 -0
  50. package/src/page-frame/desktop/styles/variables.scss +28 -0
  51. package/src/page-frame/desktop/types/nav.ts +77 -0
  52. package/src/page-frame/index.tsx +2 -0
  53. package/src/page-frame/mobile/index.scss +1 -1
  54. package/src/page-frame/types/index.ts +69 -0
  55. package/src/weather/apis/index.ts +4 -0
  56. package/src/weather/apis/korea/client.ts +93 -0
  57. package/src/weather/apis/korea/server.ts +253 -0
  58. package/src/weather/apis/open-weather-map/client.ts +69 -0
  59. package/src/weather/apis/open-weather-map/server.ts +134 -0
  60. package/src/weather/components/icon/Address.tsx +13 -0
  61. package/src/weather/components/icon/Weather.tsx +32 -0
  62. package/src/weather/components/index.tsx +7 -0
  63. package/src/weather/components/page-header/Address.tsx +21 -0
  64. package/src/weather/components/page-header/Alert.tsx +42 -0
  65. package/src/weather/components/page-header/Container.tsx +14 -0
  66. package/src/weather/components/page-header/Forecast.tsx +26 -0
  67. package/src/weather/components/page-header/NextDays.tsx +32 -0
  68. package/src/weather/components/page-header/Today.tsx +135 -0
  69. package/src/weather/context/mock.tsx +45 -0
  70. package/src/weather/data/alert-regions-meta.json +1286 -0
  71. package/src/weather/data/response.ts +36 -0
  72. package/src/weather/data/weather-regions-meta.json +9833 -0
  73. package/src/weather/hooks/index.ts +4 -0
  74. package/src/weather/hooks/useOpenWeatherMap.ts +42 -0
  75. package/src/weather/hooks/useWeatherKorea.ts +78 -0
  76. package/src/weather/hooks/useWeatherKoreaAlert.ts +36 -0
  77. package/src/weather/index.tsx +11 -0
  78. package/src/weather/jotai/coordinate.ts +16 -0
  79. package/src/weather/jotai/farm-idx.ts +5 -0
  80. package/src/weather/jotai/index.ts +2 -0
  81. package/src/weather/styles/weather.scss +151 -0
  82. package/src/weather/types/api.ts +215 -0
  83. package/src/weather/types/base.ts +50 -0
  84. package/src/weather/types/index.ts +4 -0
  85. package/src/weather/types/korea.ts +228 -0
  86. package/src/weather/types/open-weather-map.ts +164 -0
  87. package/src/weather/utils/alert.ts +30 -0
  88. package/src/weather/utils/date-time.ts +65 -0
  89. package/src/weather/utils/index.ts +4 -0
  90. package/src/weather/utils/location.ts +161 -0
  91. package/src/weather/utils/validate.ts +9 -0
  92. package/src/weather/utils/weather.ts +304 -0
@@ -0,0 +1,28 @@
1
+ :root {
2
+ --uds-page-frame-background: var(--color-common-100);
3
+
4
+ --uds-page-header-height: 7.2rem;
5
+ --uds-page-header-border: var(--color-border-standard-cool-gray);
6
+ --uds-page-header-padding-horizontal: var(--spacing-padding-9, 2.8rem);
7
+ --uds-page-header-padding-vertical: var(--spacing-padding-5, 1.2rem);
8
+ --uds-page-header-background: var(--uds-page-frame-background);
9
+ --uds-page-header-item-gap: var(--spacing-padding-5, 1.2rem);
10
+
11
+ --uds-page-nav-width: 7.2rem;
12
+ --uds-page-nav-border: var(--color-border-standard-cool-gray);
13
+ --uds-page-nav-background: var(--uds-page-frame-background);
14
+
15
+ --uds-page-nav-logo-height: var(--uds-page-header-height, 7.2rem);
16
+
17
+ --uds-page-nav-list-padding-horizontal: 0rem;
18
+ --uds-page-nav-list-padding-vertical: var(--spacing-padding-9, 2.4rem);
19
+ --uds-page-nav-item-height: var(--theme-size-meduum-2, 4.8rem);
20
+ --uds-page-nav-item-gap: var(--spacing-gap-6, 1.6rem);
21
+ --uds-page-nav-item-color-default: var(--color-label-standard);
22
+ --uds-page-nav-item-color-active: var(--color-primary-default);
23
+ --uds-page-nav-icon-size: var(--theme-size-small-2, 2.4rem);
24
+
25
+ --uds-page-body-background: var(--uds-page-frame-background);
26
+ --uds-page-body-padding-horizontal: var(--spacing-padding-9, 2.8rem);
27
+ --uds-page-body-padding-vertical: var(--spacing-padding-9, 2.8rem);
28
+ }
@@ -0,0 +1,77 @@
1
+ import type { SitemapDataType } from "../../types";
2
+
3
+ /**
4
+ * PageFrame; Desktop Nav Logo Props
5
+ */
6
+ export interface PageFrameDesktopNavLogoProps {
7
+ /**
8
+ * 로고 클릭 시 이동할 링크 주소.
9
+ * 기본값은 "/" (홈) 입니다.
10
+ */
11
+ href?: string;
12
+ /**
13
+ * 로고 이미지 src 속성 값.
14
+ */
15
+ src: string;
16
+ /**
17
+ * 로고 이미지 alt 속성 값.
18
+ */
19
+ alt: string;
20
+ /**
21
+ * 로고 이미지 width 속성 값.
22
+ */
23
+ width: number;
24
+ /**
25
+ * 로고 이미지 height 속성 값.
26
+ */
27
+ height: number;
28
+ /**
29
+ * 로고 이미지 priority 속성 값.
30
+ */
31
+ priority?: boolean;
32
+ /**
33
+ * 커스텀 로고 콘텐츠.
34
+ * 제공 시, src, alt, label props는 무시됩니다.
35
+ */
36
+ children?: React.ReactNode;
37
+ }
38
+
39
+ /**
40
+ * PageFrame; Desktop Nav Item Props
41
+ */
42
+ export interface PageFrameDesktopNavItemProps {
43
+ /**
44
+ * 경로.
45
+ */
46
+ path: string;
47
+ /**
48
+ * 아이콘.
49
+ */
50
+ icon?: React.ReactNode;
51
+ /**
52
+ * 메뉴 이름.
53
+ */
54
+ menuName: React.ReactNode;
55
+ /**
56
+ * 이름 숨김 여부.
57
+ */
58
+ isHideName?: boolean;
59
+ }
60
+
61
+ /**
62
+ * PageFrame; Desktop Nav Props
63
+ */
64
+ export interface PageFrameDesktopNavProps {
65
+ /**
66
+ * logo 옵션
67
+ */
68
+ logo?: PageFrameDesktopNavLogoProps;
69
+ /**
70
+ * 사이트맵 데이터 배열.
71
+ */
72
+ sitemap: SitemapDataType[];
73
+ /**
74
+ * 현재 경로.
75
+ */
76
+ currentPath?: string;
77
+ }
@@ -1,3 +1,5 @@
1
1
  export * from "./container";
2
2
  export * from "./mobile";
3
3
  export * from "./navigation";
4
+ export * from "./types";
5
+ export { default as PageFrameDesktop } from "./desktop";
@@ -1,7 +1,7 @@
1
1
  .page-frame-mobile {
2
2
  width: 100%;
3
3
  height: 100%;
4
- min-height: var(--page-frame-height, var(--frame-device-height, 812px));
4
+ min-height: var(--uds-page-frame-height, var(--frame-device-height, 812px));
5
5
  max-height: 100dvh;
6
6
  background-color: var(--color-common-100, #ffffff);
7
7
  }
@@ -0,0 +1,69 @@
1
+ import type { CSSProperties, ReactNode, SyntheticEvent } from "react";
2
+ import type { SitemapBase } from "@uniai-fe/util-functions";
3
+
4
+ /**
5
+ * page-frame 컴포넌트에서 공통으로 사용하는 기본 Props
6
+ */
7
+ export type ComponentBaseProps<ClickElement extends Element = HTMLElement> = {
8
+ children: ReactNode;
9
+ } & Partial<{
10
+ className: string;
11
+ clickEvent: (event?: SyntheticEvent<ClickElement>) => void;
12
+ }>;
13
+
14
+ /**
15
+ * 커스텀 CSS 변수를 명시적으로 다루기 위한 스타일 타입
16
+ */
17
+ export type CSSVarStyle<Variable extends string> = CSSProperties & {
18
+ [Key in Variable]?: string;
19
+ };
20
+
21
+ /**
22
+ * 페이지 프레임에서 사용하는 네비게이션 옵셔널 속성
23
+ */
24
+ export type SitemapPageOptionsType = {
25
+ popup?: boolean;
26
+ auth?: string[];
27
+ pageStyle?: string;
28
+ };
29
+
30
+ /**
31
+ * Sidebar/ Breadcrumb 등을 구성하는 기본 노드 타입
32
+ */
33
+ export type SitemapDataType = SitemapPageOptionsType &
34
+ SitemapBase & {
35
+ routeKey: string;
36
+ name: string;
37
+ depth: SitemapDataType[];
38
+ icon?: ReactNode;
39
+ navDepthDisabled?: boolean;
40
+ };
41
+
42
+ /**
43
+ * Breadcrumb 매칭 결과 구조
44
+ */
45
+ export type SitemapMatchDataType = {
46
+ category: SitemapDataType | null;
47
+ depth: SitemapDataType | null;
48
+ };
49
+
50
+ /**
51
+ * 헤더 프로필 선택 옵션
52
+ */
53
+ export interface SelectOptionType<OptionDataType = unknown> {
54
+ key: string;
55
+ value: string | number;
56
+ optionName: string | ReactNode;
57
+ selected: boolean;
58
+ disabled?: boolean;
59
+ data?: OptionDataType;
60
+ }
61
+
62
+ /**
63
+ * 헤더 알림 항목 데이터
64
+ */
65
+ export type PageHeaderNotifyDataType = {
66
+ key: string;
67
+ content: ReactNode;
68
+ timestamp: string | Date;
69
+ };
@@ -0,0 +1,4 @@
1
+ export * from "./korea/client";
2
+ export * from "./korea/server";
3
+ export * from "./open-weather-map/client";
4
+ export * from "./open-weather-map/server";
@@ -0,0 +1,93 @@
1
+ "use client";
2
+
3
+ import { useQuery, type UseQueryResult } from "@tanstack/react-query";
4
+ import { getQueryString } from "@uniai-fe/util-functions";
5
+ import type {
6
+ API_Req_WeatherKorea,
7
+ API_Req_WeatherKoreaAlert,
8
+ API_Res_WeatherKoreaAlert,
9
+ API_Res_WeatherKoreaForecast,
10
+ API_Res_WeatherKoreaNow,
11
+ } from "../../types";
12
+ import { isValidGridCoordinate } from "../../utils/validate";
13
+
14
+ /**
15
+ * 기상청 API; 현재날씨 fetch
16
+ * @method GET
17
+ * @param {API_Req_WeatherKorea} params - API 요청 파라미터
18
+ * @param {number} params.nx - X 좌표
19
+ * @param {number} params.ny - Y 좌표
20
+ * @param {string} [params.base_date] - 기준 날짜
21
+ * @param {string} [params.base_time] - 기준 시간
22
+ */
23
+ export const getWeatherKoreaNow = async (params: API_Req_WeatherKorea) =>
24
+ await (await fetch(`/api/weather/korea/now${getQueryString(params)}`)).json();
25
+
26
+ /**
27
+ * 기상청 API; 내일/모레 예보 fetch
28
+ * @method GET
29
+ * @param {API_Req_WeatherKorea} params - API 요청 파라미터
30
+ * @param {number} params.nx - X 좌표
31
+ * @param {string} params.ny - Y 좌표
32
+ * @param {string} [params.base_date] - 기준 날짜
33
+ * @param {string} [params.base_time] - 기준 시간
34
+ */
35
+ export const getWeatherKoreaForecast = async (params: API_Req_WeatherKorea) =>
36
+ await (
37
+ await fetch(`/api/weather/korea/forecast${getQueryString(params)}`)
38
+ ).json();
39
+
40
+ /**
41
+ * 기상청 API; 특보 fetch
42
+ * @method GET
43
+ * @param {API_Req_WeatherKoreaAlert} params - API 요청 파라미터
44
+ * @param {number} params.farm_idx - 농장 ID
45
+ */
46
+ export const getWeatherKoreaAlert = async (params: API_Req_WeatherKoreaAlert) =>
47
+ await (
48
+ await fetch(`/api/weather/korea/alert${getQueryString(params)}`)
49
+ ).json();
50
+
51
+ /**
52
+ * 기상청 API; 현재 날씨 react query
53
+ * @method GET
54
+ */
55
+ export const useQueryWeatherKoreaNow = (
56
+ params: API_Req_WeatherKorea,
57
+ ): UseQueryResult<API_Res_WeatherKoreaNow> =>
58
+ useQuery({
59
+ queryKey: ["weather_korea_now", ...Object.values(params)],
60
+ queryFn: () => getWeatherKoreaNow(params),
61
+ enabled: isValidGridCoordinate({ nx: params.nx, ny: params.ny }),
62
+ staleTime: 10 * 60 * 1000, // 10분
63
+ refetchInterval: 5 * 60 * 1000, // 5분
64
+ refetchOnWindowFocus: true,
65
+ });
66
+
67
+ /**
68
+ * 기상청 API; 내일/모레 예보 react query
69
+ * @method GET
70
+ */
71
+ export const useQueryWeatherKoreaForecast = (
72
+ params: API_Req_WeatherKorea,
73
+ ): UseQueryResult<API_Res_WeatherKoreaForecast> =>
74
+ useQuery({
75
+ queryKey: ["weather_korea_forecast", ...Object.values(params)],
76
+ queryFn: () => getWeatherKoreaForecast(params),
77
+ enabled: isValidGridCoordinate({ nx: params.nx, ny: params.ny }),
78
+ staleTime: 30 * 60 * 1000, // 30분
79
+ });
80
+
81
+ /**
82
+ * 기상청 API; 특보 react query
83
+ * @method GET
84
+ */
85
+ export const useQueryWeatherKoreaAlert = (
86
+ params: API_Req_WeatherKoreaAlert,
87
+ ): UseQueryResult<API_Res_WeatherKoreaAlert> =>
88
+ useQuery({
89
+ queryKey: ["weather_korea_alert", ...Object.values(params)],
90
+ queryFn: () => getWeatherKoreaAlert(params),
91
+ enabled: typeof params.farm_idx === "number" && params.farm_idx > 0,
92
+ staleTime: 60 * 60 * 1000, // 1시간
93
+ });
@@ -0,0 +1,253 @@
1
+ "use server";
2
+
3
+ import { setDebugResponseHeaders } from "@uniai-fe/util-next";
4
+ import type {
5
+ API_Res_WeatherKoreaAlert,
6
+ API_Res_WeatherKoreaForecast,
7
+ API_Res_WeatherKoreaNextDays,
8
+ API_Res_WeatherKoreaNow,
9
+ API_Res_WeatherKoreaToday,
10
+ KMA_Req_Weather,
11
+ KMA_Res_WeatherForecast,
12
+ KMA_Res_WeatherNow,
13
+ } from "../../types";
14
+ import WEATHER_KOREA_RESPONSE from "../../data/response";
15
+ import { getWeatherBaseMoments } from "../../utils/date-time";
16
+ import { extractWeatherSummary } from "../../utils";
17
+ import type { NextResponse } from "next/server";
18
+ import {
19
+ generateBackendQueryUrl_GET,
20
+ nextAPILog,
21
+ } from "@uniai-fe/util-functions";
22
+
23
+ // const { generateBackendQueryUrl_GET } = weatherApi;
24
+ // const weatherLog = weatherApi.logger;
25
+
26
+ /**
27
+ * 기상청 API; base URL
28
+ * "본 저작물은 기상청에서 'OO년'작성하여 공공누리 제1유형으로 개방한 '저작물명(작성자:OOO)'을 이용하였으며, 해당 저작물은 '기상청 API허브(apihub.kma.go.kr)에서 무료로 다운받으실 수 있습니다."
29
+ */
30
+
31
+ const API_BASE = "https://apihub.kma.go.kr/api";
32
+ /**
33
+ * 기상청 API; 날씨정보 URL
34
+ */
35
+ const API_WEATHER = "/typ02/openApi/VilageFcstInfoService_2.0";
36
+
37
+ const QUERY_URL = {
38
+ forecast: `${API_WEATHER}/getVilageFcst`,
39
+ now: `${API_WEATHER}/getUltraSrtFcst`,
40
+ alert: `/avic/weather-alert`,
41
+ };
42
+
43
+ const { API_RES_RAW, API_RES_BASE } = WEATHER_KOREA_RESPONSE;
44
+
45
+ const getWeatherParams = ({
46
+ authKey,
47
+ category,
48
+ searchParams,
49
+ }: {
50
+ authKey: string;
51
+ category: "now" | "forecast";
52
+ searchParams: URLSearchParams;
53
+ }): KMA_Req_Weather => {
54
+ const { base_date, base_time } = getWeatherBaseMoments(category);
55
+
56
+ return {
57
+ pageNo: "1",
58
+ numOfRows: "1000",
59
+ authKey,
60
+ base_date,
61
+ base_time,
62
+ dataType: "JSON",
63
+ nx: 0,
64
+ ny: 0,
65
+ ...Object.fromEntries(searchParams.entries()),
66
+ };
67
+ };
68
+
69
+ /**
70
+ * 기상청 API; 현재 날씨
71
+ * @method GET
72
+ */
73
+ export const routeWeatherKoreaNow = async ({
74
+ domain = API_BASE,
75
+ authKey,
76
+ routeUrl,
77
+ searchParams,
78
+ }: {
79
+ authKey: string;
80
+ routeUrl: string;
81
+ searchParams: URLSearchParams;
82
+ } & Partial<{
83
+ domain: string;
84
+ }>): Promise<API_Res_WeatherKoreaNow> => {
85
+ const NOW_DATA: API_Res_WeatherKoreaToday = {
86
+ ...API_RES_BASE,
87
+ temperature: null,
88
+ humidity: null,
89
+ };
90
+ const resDefault: API_Res_WeatherKoreaNow = {
91
+ raw: API_RES_RAW as KMA_Res_WeatherNow,
92
+ today: NOW_DATA,
93
+ };
94
+
95
+ if (!authKey) {
96
+ nextAPILog("GET", routeUrl, "기상청 현재날씨 API", {
97
+ error: "API Key를 확인하세요.",
98
+ });
99
+ return resDefault;
100
+ }
101
+
102
+ const queryParams = Object.fromEntries(
103
+ Object.entries(
104
+ getWeatherParams({ authKey, category: "now", searchParams }),
105
+ ).map(([key, value]) => [key, String(value)]),
106
+ );
107
+
108
+ // 요청 URL 구성
109
+ const url = generateBackendQueryUrl_GET({
110
+ domain,
111
+ routeUrl,
112
+ queryUrl: QUERY_URL.now,
113
+ searchParams: new URLSearchParams(queryParams),
114
+ });
115
+
116
+ // nextAPILog("GET", routeUrl, url, { searchParams, queryParams });
117
+
118
+ try {
119
+ const res: KMA_Res_WeatherNow = await (await fetch(url)).json();
120
+ resDefault.raw = res;
121
+ return extractWeatherSummary.now(resDefault, res);
122
+ } catch (error) {
123
+ nextAPILog("GET", routeUrl, url, { error });
124
+
125
+ return resDefault;
126
+ }
127
+ };
128
+
129
+ /**
130
+ * 기상청 API; 내일, 모래 예보
131
+ * @method GET
132
+ */
133
+ export const routeWeatherKoreaForecast = async ({
134
+ domain = API_BASE,
135
+ authKey,
136
+ routeUrl,
137
+ searchParams,
138
+ }: {
139
+ authKey: string;
140
+ routeUrl: string;
141
+ searchParams: URLSearchParams;
142
+ } & Partial<{
143
+ domain: string;
144
+ }>): Promise<API_Res_WeatherKoreaForecast> => {
145
+ const FORECAST_DATA: API_Res_WeatherKoreaNextDays = {
146
+ ...API_RES_BASE,
147
+ max_temperature: null,
148
+ min_temperature: null,
149
+ };
150
+ const resDefault: API_Res_WeatherKoreaForecast = {
151
+ raw: API_RES_RAW as KMA_Res_WeatherForecast,
152
+ today: { ...API_RES_BASE, temperature: null, humidity: null },
153
+ day_1: FORECAST_DATA,
154
+ day_2: FORECAST_DATA,
155
+ };
156
+
157
+ if (!authKey) {
158
+ nextAPILog("GET", routeUrl, "기상청 예보날씨 API", {
159
+ error: "API Key를 확인하세요.",
160
+ });
161
+ return resDefault;
162
+ }
163
+
164
+ const queryParams = Object.fromEntries(
165
+ Object.entries(
166
+ getWeatherParams({ authKey, category: "forecast", searchParams }),
167
+ ).map(([key, value]) => [key, String(value)]),
168
+ );
169
+
170
+ // 요청 URL 구성
171
+ const url = generateBackendQueryUrl_GET({
172
+ domain,
173
+ routeUrl,
174
+ queryUrl: QUERY_URL.forecast,
175
+ searchParams: new URLSearchParams(queryParams),
176
+ });
177
+
178
+ // nextAPILog("GET", routeUrl, url, { searchParams, queryParams });
179
+
180
+ try {
181
+ const res: KMA_Res_WeatherForecast = await (await fetch(url)).json();
182
+ resDefault.raw = res;
183
+ return extractWeatherSummary.forecast(resDefault, res);
184
+ } catch (error) {
185
+ nextAPILog("GET", routeUrl, url, { error });
186
+
187
+ return resDefault;
188
+ }
189
+ };
190
+
191
+ /**
192
+ * 기상청 API; 특보 - 구역코드 조회
193
+ */
194
+ // export const getWeatherKoreaAlertRegionCodes = async ({
195
+ // routeUrl,
196
+ // searchParams,
197
+ // }: {
198
+ // routeUrl: string;
199
+ // searchParams: URLSearchParams;
200
+ // }) => {
201
+ // const params = new URLSearchParams({
202
+ // authKey,
203
+ // dataType: "JSON",
204
+ // pageNo: "1",
205
+ // numOfRows: "1000",
206
+ // korName: "",
207
+ // });
208
+ // const url = `${QUERY_URL.alert}?${params.toString()}`;
209
+ // nextAPILog("GET", routeUrl, url, { params, searchParams });
210
+
211
+ // const regions = await (await fetch(url)).json();
212
+
213
+ // return regions;
214
+ // };
215
+
216
+ /**
217
+ * 기상청 API; 특보
218
+ */
219
+ export const routeWeatherKoreaAlert = async ({
220
+ domain,
221
+ routeUrl,
222
+ searchParams,
223
+ }: {
224
+ domain: string;
225
+ routeUrl: string;
226
+ searchParams: URLSearchParams;
227
+ }): Promise<NextResponse<API_Res_WeatherKoreaAlert>> => {
228
+ const params = new URLSearchParams({
229
+ // authKey,
230
+ // dataType: "JSON",
231
+ // reg: "",
232
+ // wrn: "",
233
+ // disp: "0",
234
+ // fe: "f",
235
+ // tm: "",
236
+ });
237
+ const url = generateBackendQueryUrl_GET({
238
+ domain,
239
+ routeUrl,
240
+ queryUrl: QUERY_URL.alert,
241
+ searchParams,
242
+ });
243
+
244
+ nextAPILog("GET", routeUrl, url, { params, searchParams });
245
+ const info = await (await fetch(url)).json();
246
+
247
+ return setDebugResponseHeaders<API_Res_WeatherKoreaAlert>({
248
+ res: info,
249
+ domain,
250
+ queryUrl: QUERY_URL.alert,
251
+ searchParams,
252
+ });
253
+ };
@@ -0,0 +1,69 @@
1
+ "use client";
2
+
3
+ import { useQuery, type UseQueryResult } from "@tanstack/react-query";
4
+ import type { OWM_Res_Weather_Now, WeatherGeoCoordinate } from "../../types";
5
+ import { getQueryString, isValidNumber } from "@uniai-fe/util-functions";
6
+
7
+ /**
8
+ * 글로벌 날씨 API; 현재 날씨 fetch
9
+ * @method GET
10
+ * @route https://api.openweathermap.org/data/2.5/weather
11
+ * @see https://openweathermap.org/current
12
+ * @param {WeatherGeoCoordinate} params - API 요청 파라미터
13
+ * @param {number} params.lat - 위도
14
+ * @param {number} params.lon - 경도
15
+ */
16
+ export const getWeatherOpenWeatherMapNow = async (
17
+ params: WeatherGeoCoordinate,
18
+ ) =>
19
+ await (
20
+ await fetch(`/api/weather/open-weather-map/now${getQueryString(params)}`)
21
+ ).json();
22
+
23
+ /**
24
+ * 글로벌 날씨 API; 예보 날씨 (4 days) fetch
25
+ * @method GET
26
+ * @route https://pro.openweathermap.org/data/2.5/weather/forecast/hourly
27
+ * @see https://openweathermap.org/api/hourly-forecast
28
+ * @param {WeatherGeoCoordinate} params - API 요청 파라미터
29
+ * @param {number} params.lat - 위도
30
+ * @param {number} params.lon - 경도
31
+ */
32
+ export const getWeatherOpenWeatherMapForecast = async (
33
+ params: WeatherGeoCoordinate,
34
+ ) =>
35
+ await (
36
+ await fetch(
37
+ `/api/weather/open-weather-map/forecast${getQueryString(params)}`,
38
+ )
39
+ ).json();
40
+
41
+ /**
42
+ * 글로벌 날씨 API; 현재 날씨 react query
43
+ * @method GET
44
+ */
45
+ export const useQueryWeatherOpenWeatherMapNow = (
46
+ params: WeatherGeoCoordinate,
47
+ ): UseQueryResult<OWM_Res_Weather_Now> =>
48
+ useQuery({
49
+ queryKey: ["weather_open_weather_map_now", ...Object.values(params)],
50
+ queryFn: () => getWeatherOpenWeatherMapNow(params),
51
+ enabled: isValidNumber(params.lat) && isValidNumber(params.lng),
52
+ staleTime: 10 * 60 * 1000, // 10분
53
+ refetchInterval: 5 * 60 * 1000, // 5분
54
+ refetchOnWindowFocus: true,
55
+ });
56
+
57
+ /**
58
+ * 글로벌 날씨 API; 예보 날씨 (4 days) react query
59
+ * @method GET
60
+ */
61
+ export const useQueryWeatherOpenWeatherMapForecast = (
62
+ params: WeatherGeoCoordinate,
63
+ ) =>
64
+ useQuery({
65
+ queryKey: ["weather_open_weather_map_forecast", ...Object.values(params)],
66
+ queryFn: () => getWeatherOpenWeatherMapForecast(params),
67
+ enabled: isValidNumber(params.lat) && isValidNumber(params.lng),
68
+ staleTime: 30 * 60 * 1000, // 30분
69
+ });