@uniai-fe/uds-templates 0.1.16 → 0.1.18
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.
- package/dist/styles.css +139 -10
- package/package.json +18 -11
- package/src/auth/common/complete/Template.tsx +3 -0
- package/src/auth/common/complete/types.ts +4 -1
- package/src/auth/common/find/markup/CodeStep.tsx +2 -1
- package/src/auth/common/find/markup/InfoStep.tsx +2 -1
- package/src/auth/common/find/styles/result.scss +1 -1
- package/src/auth/find-password/markup/StepResetPassword.tsx +2 -1
- package/src/auth/login/markup/FormField.tsx +2 -1
- package/src/auth/signup/markup/AccountForm.tsx +2 -1
- package/src/auth/signup/markup/Complete.tsx +2 -1
- package/src/auth/signup/markup/UserInfoForm.tsx +2 -1
- package/src/auth/signup/markup/VerificationForm.tsx +4 -2
- package/src/index.scss +1 -0
- package/src/index.tsx +1 -0
- package/src/modal/core/components/FooterButtons.tsx +4 -1
- package/src/modal/templates/Dialog.tsx +4 -2
- package/src/modal/types/footer.ts +4 -2
- package/src/page-frame/container/index.scss +14 -8
- package/src/page-frame/desktop/components/header/Container.tsx +22 -0
- package/src/page-frame/desktop/components/header/Section.tsx +20 -0
- package/src/page-frame/desktop/components/header/index.tsx +19 -0
- package/src/page-frame/desktop/components/header/util/Button.tsx +23 -0
- package/src/page-frame/desktop/components/header/util/Container.tsx +18 -0
- package/src/page-frame/desktop/components/header/util/Item.tsx +13 -0
- package/src/page-frame/desktop/components/header/util/Logout.tsx +26 -0
- package/src/page-frame/desktop/components/header/util/setting/Button.tsx +39 -0
- package/src/page-frame/desktop/components/index.tsx +15 -0
- package/src/page-frame/desktop/components/nav/Button.tsx +24 -0
- package/src/page-frame/desktop/components/nav/Container.tsx +70 -0
- package/src/page-frame/desktop/components/nav/Logo.tsx +46 -0
- package/src/page-frame/desktop/components/nav/index.tsx +5 -0
- package/src/page-frame/desktop/components/page/Container.tsx +13 -0
- package/src/page-frame/desktop/components/page/ServiceFrame.tsx +15 -0
- package/src/page-frame/desktop/components/page/ServiceMain.tsx +13 -0
- package/src/page-frame/desktop/components/page/ServiceMainWrapper.tsx +24 -0
- package/src/page-frame/desktop/components/page/index.tsx +14 -0
- package/src/page-frame/desktop/components/popup/Container.tsx +18 -0
- package/src/page-frame/desktop/components/popup/frame/Body.tsx +14 -0
- package/src/page-frame/desktop/components/popup/frame/Container.tsx +16 -0
- package/src/page-frame/desktop/components/popup/frame/Header.tsx +26 -0
- package/src/page-frame/desktop/components/popup/frame/index.tsx +11 -0
- package/src/page-frame/desktop/components/popup/index.tsx +9 -0
- package/src/page-frame/desktop/index.scss +5 -0
- package/src/page-frame/desktop/index.tsx +7 -0
- package/src/page-frame/desktop/styles/page/common.scss +40 -0
- package/src/page-frame/desktop/styles/page/header.scss +49 -0
- package/src/page-frame/desktop/styles/page/nav.scss +128 -0
- package/src/page-frame/desktop/styles/popup/popup.scss +45 -0
- package/src/page-frame/desktop/styles/variables.scss +28 -0
- package/src/page-frame/desktop/types/index.ts +1 -0
- package/src/page-frame/desktop/types/nav.ts +77 -0
- package/src/page-frame/index.tsx +2 -0
- package/src/page-frame/mobile/index.scss +1 -1
- package/src/page-frame/types/index.ts +69 -0
- package/src/weather/apis/index.ts +4 -0
- package/src/weather/apis/korea/client.ts +93 -0
- package/src/weather/apis/korea/server.ts +253 -0
- package/src/weather/apis/open-weather-map/client.ts +69 -0
- package/src/weather/apis/open-weather-map/server.ts +134 -0
- package/src/weather/components/icon/Address.tsx +13 -0
- package/src/weather/components/icon/Weather.tsx +32 -0
- package/src/weather/components/index.tsx +7 -0
- package/src/weather/components/page-header/Address.tsx +21 -0
- package/src/weather/components/page-header/Alert.tsx +42 -0
- package/src/weather/components/page-header/Container.tsx +14 -0
- package/src/weather/components/page-header/Forecast.tsx +26 -0
- package/src/weather/components/page-header/NextDays.tsx +32 -0
- package/src/weather/components/page-header/Today.tsx +135 -0
- package/src/weather/context/mock.tsx +45 -0
- package/src/weather/data/alert-regions-meta.json +1286 -0
- package/src/weather/data/response.ts +36 -0
- package/src/weather/data/weather-regions-meta.json +9833 -0
- package/src/weather/hooks/index.ts +4 -0
- package/src/weather/hooks/useOpenWeatherMap.ts +42 -0
- package/src/weather/hooks/useWeatherKorea.ts +78 -0
- package/src/weather/hooks/useWeatherKoreaAlert.ts +36 -0
- package/src/weather/index.tsx +11 -0
- package/src/weather/jotai/coordinate.ts +16 -0
- package/src/weather/jotai/farm-idx.ts +5 -0
- package/src/weather/jotai/index.ts +2 -0
- package/src/weather/styles/weather.scss +151 -0
- package/src/weather/types/api.ts +215 -0
- package/src/weather/types/base.ts +50 -0
- package/src/weather/types/index.ts +4 -0
- package/src/weather/types/korea.ts +228 -0
- package/src/weather/types/open-weather-map.ts +164 -0
- package/src/weather/utils/alert.ts +30 -0
- package/src/weather/utils/date-time.ts +65 -0
- package/src/weather/utils/index.ts +4 -0
- package/src/weather/utils/location.ts +161 -0
- package/src/weather/utils/validate.ts +9 -0
- package/src/weather/utils/weather.ts +304 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useAtomValue } from "jotai";
|
|
4
|
+
import { weatherCoordinate } from "../jotai";
|
|
5
|
+
import {
|
|
6
|
+
useQueryWeatherOpenWeatherMapForecast,
|
|
7
|
+
useQueryWeatherOpenWeatherMapNow,
|
|
8
|
+
} from "../apis/open-weather-map/client";
|
|
9
|
+
import { useWeatherMock } from "../context/mock";
|
|
10
|
+
|
|
11
|
+
export default function useOpenWeatherMap() {
|
|
12
|
+
const mock = useWeatherMock();
|
|
13
|
+
const coordinate = useAtomValue(weatherCoordinate);
|
|
14
|
+
const shouldUseMock = Boolean(mock?.openWeather);
|
|
15
|
+
// mock 모드일 때는 Query가 실행되지 않도록 NaN 좌표를 전달한다.
|
|
16
|
+
const queryCoordinate = shouldUseMock
|
|
17
|
+
? { lat: Number.NaN, lng: Number.NaN }
|
|
18
|
+
: coordinate;
|
|
19
|
+
|
|
20
|
+
const { data: now, isFetching: isFetchingNow } =
|
|
21
|
+
useQueryWeatherOpenWeatherMapNow(queryCoordinate);
|
|
22
|
+
const { data: forecast, isFetching: isFetchingForecast } =
|
|
23
|
+
useQueryWeatherOpenWeatherMapForecast(queryCoordinate);
|
|
24
|
+
|
|
25
|
+
if (mock?.openWeather) {
|
|
26
|
+
return {
|
|
27
|
+
coordinate: mock.openWeather.coordinate,
|
|
28
|
+
now: mock.openWeather.now,
|
|
29
|
+
forecast: mock.openWeather.forecast,
|
|
30
|
+
isFetchingNow: mock.openWeather.isFetchingNow ?? false,
|
|
31
|
+
isFetchingForecast: mock.openWeather.isFetchingForecast ?? false,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
coordinate,
|
|
37
|
+
now,
|
|
38
|
+
forecast,
|
|
39
|
+
isFetchingNow,
|
|
40
|
+
isFetchingForecast,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useState, useEffect } from "react";
|
|
4
|
+
import { useAtomValue } from "jotai";
|
|
5
|
+
import {
|
|
6
|
+
useQueryWeatherKoreaForecast,
|
|
7
|
+
useQueryWeatherKoreaNow,
|
|
8
|
+
} from "../apis/korea/client"; // 클라이언트 전용 API만 import해 Storybook 번들에서 server 코드를 배제한다.
|
|
9
|
+
import type { API_Req_WeatherKorea } from "../types";
|
|
10
|
+
import { weatherCoordinate } from "../jotai/coordinate";
|
|
11
|
+
import { getWeatherBaseMoments } from "../utils/date-time";
|
|
12
|
+
import { getWeatherGridLocation } from "../utils/location";
|
|
13
|
+
import { useWeatherMock } from "../context/mock";
|
|
14
|
+
|
|
15
|
+
export default function useWeatherKorea() {
|
|
16
|
+
const mock = useWeatherMock();
|
|
17
|
+
const coordinate = useAtomValue(weatherCoordinate);
|
|
18
|
+
const [params, setParams] = useState<{
|
|
19
|
+
[categoryKey: string]: API_Req_WeatherKorea;
|
|
20
|
+
}>({
|
|
21
|
+
now: { nx: 0, ny: 0 },
|
|
22
|
+
forecast: { nx: 0, ny: 0 },
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
if (mock?.korea) return;
|
|
27
|
+
if (typeof window === "undefined") return;
|
|
28
|
+
|
|
29
|
+
const nowMoments = getWeatherBaseMoments("now");
|
|
30
|
+
const forecastMoments = getWeatherBaseMoments("forecast");
|
|
31
|
+
|
|
32
|
+
async function updater() {
|
|
33
|
+
const grid = await getWeatherGridLocation(coordinate);
|
|
34
|
+
setParams({
|
|
35
|
+
now: {
|
|
36
|
+
...grid,
|
|
37
|
+
...nowMoments,
|
|
38
|
+
},
|
|
39
|
+
forecast: {
|
|
40
|
+
...grid,
|
|
41
|
+
...forecastMoments,
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
updater();
|
|
47
|
+
}, [coordinate, mock]);
|
|
48
|
+
|
|
49
|
+
const { data: now, isFetching: isFetchingNow } = useQueryWeatherKoreaNow(
|
|
50
|
+
params.now,
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
const { data: forecast, isFetching: isFetchingForecast } =
|
|
54
|
+
useQueryWeatherKoreaForecast(params.forecast);
|
|
55
|
+
|
|
56
|
+
if (mock?.korea) {
|
|
57
|
+
return {
|
|
58
|
+
params: {
|
|
59
|
+
now: { nx: 0, ny: 0 },
|
|
60
|
+
forecast: { nx: 0, ny: 0 },
|
|
61
|
+
},
|
|
62
|
+
coordinate: mock.korea.coordinate,
|
|
63
|
+
now: mock.korea.now,
|
|
64
|
+
forecast: mock.korea.forecast,
|
|
65
|
+
isFetchingNow: mock.korea.isFetchingNow ?? false,
|
|
66
|
+
isFetchingForecast: mock.korea.isFetchingForecast ?? false,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
params,
|
|
72
|
+
coordinate,
|
|
73
|
+
now,
|
|
74
|
+
forecast,
|
|
75
|
+
isFetchingNow,
|
|
76
|
+
isFetchingForecast,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useMemo } from "react";
|
|
4
|
+
import { useAtomValue } from "jotai";
|
|
5
|
+
import { useQueryWeatherKoreaAlert } from "../apis/korea/client"; // server 번들을 피하기 위해 client 모듈에서 직접 import한다.
|
|
6
|
+
import { weatherFarmIdx } from "../jotai/farm-idx";
|
|
7
|
+
import { useWeatherMock } from "../context/mock";
|
|
8
|
+
|
|
9
|
+
export default function useWeatherKoreaAlert() {
|
|
10
|
+
const mock = useWeatherMock();
|
|
11
|
+
const farm_idx = useAtomValue(weatherFarmIdx);
|
|
12
|
+
const shouldUseMock = Boolean(mock?.koreaAlert);
|
|
13
|
+
const resolvedFarmIdx = farm_idx === 507 || !farm_idx ? 507 : (farm_idx ?? 0);
|
|
14
|
+
const queryFarmIdx = shouldUseMock ? 0 : resolvedFarmIdx;
|
|
15
|
+
|
|
16
|
+
const { data, isFetching } = useQueryWeatherKoreaAlert({
|
|
17
|
+
farm_idx: queryFarmIdx,
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const alert = useMemo(() => data?.alerts || [], [data]);
|
|
21
|
+
|
|
22
|
+
if (mock?.koreaAlert) {
|
|
23
|
+
// WeatherMockProvider를 사용하면 네트워크 호출 없이 스토리/테스트 전용 alert 데이터를 주입할 수 있다.
|
|
24
|
+
return {
|
|
25
|
+
farm_idx: null,
|
|
26
|
+
alert: mock.koreaAlert.alert?.alerts ?? [],
|
|
27
|
+
isFetching: mock.koreaAlert.isFetching ?? false,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
farm_idx: resolvedFarmIdx,
|
|
33
|
+
alert,
|
|
34
|
+
isFetching,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Weather UI 컴포넌트 전용 스타일을 로드한다.
|
|
2
|
+
import "./styles/weather.scss";
|
|
3
|
+
|
|
4
|
+
export * from "./utils";
|
|
5
|
+
export * from "./apis";
|
|
6
|
+
export * from "./jotai";
|
|
7
|
+
export * from "./hooks";
|
|
8
|
+
export * from "./context/mock";
|
|
9
|
+
export * from "./types";
|
|
10
|
+
export { default as WeatherComponents } from "./components";
|
|
11
|
+
export { default as WeatherPageHeaderContainer } from "./components/page-header/Container";
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import type { WeatherCoordinate } from "../types";
|
|
4
|
+
import { atomWithReset } from "jotai/utils";
|
|
5
|
+
|
|
6
|
+
export const weatherCoordinate = atomWithReset<WeatherCoordinate>({
|
|
7
|
+
address: null,
|
|
8
|
+
lat: null,
|
|
9
|
+
lng: null,
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
export const harimCoordinate: WeatherCoordinate = {
|
|
13
|
+
address: "전북 익산시",
|
|
14
|
+
lat: 35.9372719,
|
|
15
|
+
lng: 126.9601241,
|
|
16
|
+
};
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
.weather-base-container {
|
|
2
|
+
width: fit-content;
|
|
3
|
+
display: flex;
|
|
4
|
+
align-items: center;
|
|
5
|
+
|
|
6
|
+
span {
|
|
7
|
+
font-size: 1.4rem;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.weather-base-icon {
|
|
12
|
+
width: 2.5rem;
|
|
13
|
+
height: 2.4rem;
|
|
14
|
+
position: relative;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.weather-base-text-info {
|
|
18
|
+
display: flex;
|
|
19
|
+
align-items: center;
|
|
20
|
+
|
|
21
|
+
dt {
|
|
22
|
+
margin-right: 0.8rem;
|
|
23
|
+
font-size: 0;
|
|
24
|
+
|
|
25
|
+
span {
|
|
26
|
+
color: var(--color-cool-gray-35);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
dd {
|
|
31
|
+
font-size: 0;
|
|
32
|
+
display: flex;
|
|
33
|
+
align-items: flex-start;
|
|
34
|
+
|
|
35
|
+
span {
|
|
36
|
+
color: var(--color-cool-gray-10);
|
|
37
|
+
font-weight: 600;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.weather-base-divider {
|
|
43
|
+
width: 1px;
|
|
44
|
+
height: 1.3rem;
|
|
45
|
+
margin: 0 0.8rem;
|
|
46
|
+
background: var(--color-cool-gray-85);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.weather-address {
|
|
50
|
+
display: flex;
|
|
51
|
+
align-items: center;
|
|
52
|
+
width: fit-content;
|
|
53
|
+
|
|
54
|
+
&-icon {
|
|
55
|
+
width: 1.6rem;
|
|
56
|
+
height: 1.6rem;
|
|
57
|
+
margin-right: 0.4rem;
|
|
58
|
+
position: relative;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
&-text {
|
|
62
|
+
width: fit-content;
|
|
63
|
+
margin-right: 1rem;
|
|
64
|
+
display: flex;
|
|
65
|
+
align-items: center;
|
|
66
|
+
|
|
67
|
+
span {
|
|
68
|
+
font-size: 1.6rem;
|
|
69
|
+
color: var(--color-cool-gray-10);
|
|
70
|
+
font-weight: 600;
|
|
71
|
+
white-space: nowrap;
|
|
72
|
+
transform: translateY(0.1rem);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.weather-today-container {
|
|
78
|
+
@extend .weather-base-container;
|
|
79
|
+
|
|
80
|
+
span {
|
|
81
|
+
white-space: nowrap;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.empty-text {
|
|
85
|
+
font-size: 1.4rem;
|
|
86
|
+
padding-right: 4rem;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.weather-today-temperature {
|
|
91
|
+
margin-left: 1rem;
|
|
92
|
+
display: flex;
|
|
93
|
+
align-items: flex-start;
|
|
94
|
+
|
|
95
|
+
span {
|
|
96
|
+
font-size: 2rem;
|
|
97
|
+
font-weight: 700;
|
|
98
|
+
color: var(--color-blue-55);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.unit {
|
|
102
|
+
font-size: 1.2rem;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.weather-today-humidity {
|
|
107
|
+
margin-left: 1.4rem;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.weather-alert {
|
|
111
|
+
width: fit-content;
|
|
112
|
+
height: 2.6rem;
|
|
113
|
+
padding: 0 1rem;
|
|
114
|
+
margin-left: 1rem;
|
|
115
|
+
border-radius: 0.8rem;
|
|
116
|
+
background-color: var(--color-cool-gray-95, #f4f6f8);
|
|
117
|
+
display: flex;
|
|
118
|
+
align-items: center;
|
|
119
|
+
|
|
120
|
+
&-text {
|
|
121
|
+
height: fit-content;
|
|
122
|
+
font-size: 0;
|
|
123
|
+
|
|
124
|
+
span {
|
|
125
|
+
font-size: 1.2rem;
|
|
126
|
+
color: var(--color-blue-55, #007cdb);
|
|
127
|
+
font-weight: 600;
|
|
128
|
+
line-height: 1.6;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.weather-next-days-container {
|
|
134
|
+
@extend .weather-base-container;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.weather-next-days-text {
|
|
138
|
+
@extend .weather-base-text-info;
|
|
139
|
+
|
|
140
|
+
dt {
|
|
141
|
+
margin-right: 0.8rem;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
dd:nth-of-type(n + 2) {
|
|
145
|
+
margin-left: 0.8rem;
|
|
146
|
+
|
|
147
|
+
.unit {
|
|
148
|
+
font-size: 1rem;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
KMA_Res_WeatherNow,
|
|
3
|
+
KMA_Res_WeatherForecast,
|
|
4
|
+
KMA_Res_Base,
|
|
5
|
+
KMA_Req_BaseGridCoordinate,
|
|
6
|
+
KMA_Req_BaseMoments,
|
|
7
|
+
KMA_Res_AlertType,
|
|
8
|
+
KMA_Res_AlertLevel,
|
|
9
|
+
KMA_Res_AlertCommand,
|
|
10
|
+
KMA_Res_WeatherItem,
|
|
11
|
+
} from "./korea";
|
|
12
|
+
|
|
13
|
+
export type API_Req_WeatherKoreaGrid = KMA_Req_BaseGridCoordinate;
|
|
14
|
+
export type API_Req_WeatherKoreaMoments = KMA_Req_BaseMoments;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* 기상청 API; 날씨 요청.
|
|
18
|
+
*/
|
|
19
|
+
export type API_Req_WeatherKorea = API_Req_WeatherKoreaGrid &
|
|
20
|
+
Partial<API_Req_WeatherKoreaMoments>;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* 기상청 API; 특보 요청 파라미터
|
|
24
|
+
* @property {number | null} farm_idx 농장 식별자
|
|
25
|
+
*/
|
|
26
|
+
export type API_Req_WeatherKoreaAlert = { farm_idx: number | null };
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* 기상청 API; 특보 응답 타입 - 지역별 특보정보
|
|
30
|
+
*/
|
|
31
|
+
export type API_Res_WeatherKoreaAlertEach = {
|
|
32
|
+
/**
|
|
33
|
+
* 상위 지역 코드
|
|
34
|
+
* @see https://apihub.kma.go.kr/api/typ01/url/wrn_reg.php?tmfc=0&authKey=njld-D40Rb25Xfg-NAW9hA
|
|
35
|
+
*/
|
|
36
|
+
upper_region_code: string;
|
|
37
|
+
/**
|
|
38
|
+
* 상위 지역 이름
|
|
39
|
+
* @see https://apihub.kma.go.kr/api/typ01/url/wrn_reg.php?tmfc=0&authKey=njld-D40Rb25Xfg-NAW9hA
|
|
40
|
+
*/
|
|
41
|
+
upper_region_name: string;
|
|
42
|
+
/**
|
|
43
|
+
* 특보 지역 코드
|
|
44
|
+
* @see https://apihub.kma.go.kr/api/typ01/url/wrn_reg.php?tmfc=0&authKey=njld-D40Rb25Xfg-NAW9hA
|
|
45
|
+
*/
|
|
46
|
+
alert_region_code: string;
|
|
47
|
+
/**
|
|
48
|
+
* 특보 지역 이름
|
|
49
|
+
* @see https://apihub.kma.go.kr/api/typ01/url/wrn_reg.php?tmfc=0&authKey=njld-D40Rb25Xfg-NAW9hA
|
|
50
|
+
*/
|
|
51
|
+
alert_region_name: string;
|
|
52
|
+
/**
|
|
53
|
+
* 특보 발표시간
|
|
54
|
+
* - yyyymmddhhmm
|
|
55
|
+
*/
|
|
56
|
+
announcement_time: string;
|
|
57
|
+
/**
|
|
58
|
+
* 특보 발효시간
|
|
59
|
+
* - yyyymmddhhmm
|
|
60
|
+
*/
|
|
61
|
+
effective_time: string;
|
|
62
|
+
/** * 특보 종류 (한글) */
|
|
63
|
+
alert_type: KMA_Res_AlertType;
|
|
64
|
+
/**
|
|
65
|
+
* 특보 수준 (한글)
|
|
66
|
+
* - 경보, 주의, 예비
|
|
67
|
+
*/
|
|
68
|
+
alert_level: KMA_Res_AlertLevel;
|
|
69
|
+
/**
|
|
70
|
+
* 특보 명령 (한글)
|
|
71
|
+
* - 발표, 변경, 해제
|
|
72
|
+
*/
|
|
73
|
+
alert_command: KMA_Res_AlertCommand;
|
|
74
|
+
/**
|
|
75
|
+
* 특보 해제 예고시점 (한글)
|
|
76
|
+
* - dd일 오전/오후/밤(HH시 ~ HH시)
|
|
77
|
+
*/
|
|
78
|
+
cancel_notice_time: string;
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* 기상청 API; 특보 응답 타입
|
|
82
|
+
*/
|
|
83
|
+
export type API_Res_WeatherKoreaAlert = {
|
|
84
|
+
/** * 특보 발표 시간 */
|
|
85
|
+
api_announcement_time: string | null;
|
|
86
|
+
/** * 총 특보 개수 */
|
|
87
|
+
total_count: number;
|
|
88
|
+
/** * 지역별 특보 */
|
|
89
|
+
alerts: API_Res_WeatherKoreaAlertEach[];
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* 기상청 API; 기초 정보
|
|
94
|
+
* @property {string} condition - 개황 정보
|
|
95
|
+
*/
|
|
96
|
+
export type API_Res_WeatherKoreaBase = {
|
|
97
|
+
/**
|
|
98
|
+
* 하늘상태 코드
|
|
99
|
+
* - 1(맑음)
|
|
100
|
+
* - 2(구름조금)
|
|
101
|
+
* - 3(구름많음)
|
|
102
|
+
* - 4(흐림)
|
|
103
|
+
*/
|
|
104
|
+
sky: string | null;
|
|
105
|
+
/**
|
|
106
|
+
* 강수형태 코드
|
|
107
|
+
* - 0(없음)
|
|
108
|
+
* - 1(비)
|
|
109
|
+
* - 2(비/눈)
|
|
110
|
+
* - 3(눈)
|
|
111
|
+
* - 4(소나기)
|
|
112
|
+
*/
|
|
113
|
+
drop: string | null;
|
|
114
|
+
/**
|
|
115
|
+
* 강수량 코드
|
|
116
|
+
* - 1(약한 비); 3mm/h 미만
|
|
117
|
+
* - 2(보통 비); 3mm/h 이상 15mm/h 미만
|
|
118
|
+
* - 3(강한 비); 15mm/h 이상
|
|
119
|
+
*/
|
|
120
|
+
rainAmount: string | null;
|
|
121
|
+
/**
|
|
122
|
+
* 강설량 코드
|
|
123
|
+
* - 1(보통 눈); 1cm/h 미만
|
|
124
|
+
* - 2(많은 눈); 1cm/h 이상
|
|
125
|
+
*/
|
|
126
|
+
snowAmount: string | null;
|
|
127
|
+
/**
|
|
128
|
+
* 풍속 코드
|
|
129
|
+
* - 1(약한 바람); 4m/s 미만
|
|
130
|
+
* - 2(약간 강한 바람); 4m/s 이상 9m/s 미만
|
|
131
|
+
* - 3(강한 바람); 9m/s 이상
|
|
132
|
+
*/
|
|
133
|
+
windSpeed: string | null;
|
|
134
|
+
/**
|
|
135
|
+
* 날씨 상태 코드
|
|
136
|
+
* - sky-1(맑음)
|
|
137
|
+
* - sky-2(구름조금)
|
|
138
|
+
* - sky-3(구름많음)
|
|
139
|
+
* - sky-4(흐림)
|
|
140
|
+
* - drop-rain-shower(소나기)
|
|
141
|
+
* - drop-rain(비)
|
|
142
|
+
* - drop-rain-1(약한 비)
|
|
143
|
+
* - drop-rain-2(보통 비)
|
|
144
|
+
* - drop-rain-3(강한 비)
|
|
145
|
+
* - drop-rain-snow(비/눈)
|
|
146
|
+
* - drop-rain-snow-1(약한 비/눈)
|
|
147
|
+
* - drop-rain-snow-2(보통 비/눈)
|
|
148
|
+
* - drop-rain-snow-3(강한 비/눈)
|
|
149
|
+
* - drop-snow(눈)
|
|
150
|
+
* - drop-snow-1(보통 눈)
|
|
151
|
+
* - drop-snow-2(많은 눈)
|
|
152
|
+
*/
|
|
153
|
+
condition: string | null;
|
|
154
|
+
/** 날씨 상태 텍스트 */
|
|
155
|
+
conditionName: string | null;
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* 기상청 API; 오늘 날씨
|
|
160
|
+
* @property {number|string|null} temperature 기온(℃)
|
|
161
|
+
* @property {number|string|null} humidity 습도(%)
|
|
162
|
+
*/
|
|
163
|
+
export type API_Res_WeatherKoreaToday = API_Res_WeatherKoreaBase & {
|
|
164
|
+
/** 기온(℃) */
|
|
165
|
+
temperature: number | string | null;
|
|
166
|
+
/** 습도(%) */
|
|
167
|
+
humidity: number | string | null;
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* 기상청 API; 내일/모레 날씨
|
|
172
|
+
* @property {number|string|null} max_temperature 최고기온(℃)
|
|
173
|
+
* @property {number|string|null} min_temperature 최저기온(℃)
|
|
174
|
+
*/
|
|
175
|
+
export type API_Res_WeatherKoreaNextDays = API_Res_WeatherKoreaBase & {
|
|
176
|
+
/** 최고 기온(℃) */
|
|
177
|
+
max_temperature: number | string | null;
|
|
178
|
+
/** 최저 기온(℃) */
|
|
179
|
+
min_temperature: number | string | null;
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* 기상청 API; 원본 응답
|
|
184
|
+
* @property {RAW} raw API 원본 데이터
|
|
185
|
+
*/
|
|
186
|
+
export type API_Res_WeatherKoreaRaw<RAW = KMA_Res_Base<KMA_Res_WeatherItem>> = {
|
|
187
|
+
/** API 원본 */
|
|
188
|
+
raw: RAW;
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* 기상청 API; 초단기 실황 구조
|
|
193
|
+
* @property {API_Res_WeatherKoreaToday} today 오늘 데이터
|
|
194
|
+
*/
|
|
195
|
+
export type API_Res_WeatherKoreaNow =
|
|
196
|
+
API_Res_WeatherKoreaRaw<KMA_Res_WeatherNow> & {
|
|
197
|
+
/** 오늘 날씨 */
|
|
198
|
+
today: API_Res_WeatherKoreaToday;
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* 기상청 API; 단기 예보 구조
|
|
203
|
+
* @property {API_Res_WeatherKoreaToday} today 오늘 데이터
|
|
204
|
+
* @property {API_Res_WeatherKoreaNextDays} day_1 내일 데이터
|
|
205
|
+
* @property {API_Res_WeatherKoreaNextDays} day_2 모레 데이터
|
|
206
|
+
*/
|
|
207
|
+
export type API_Res_WeatherKoreaForecast =
|
|
208
|
+
API_Res_WeatherKoreaRaw<KMA_Res_WeatherForecast> & {
|
|
209
|
+
/** 오늘 날씨 */
|
|
210
|
+
today: API_Res_WeatherKoreaToday;
|
|
211
|
+
/** 내일 날씨 */
|
|
212
|
+
day_1: API_Res_WeatherKoreaNextDays;
|
|
213
|
+
/** 모레 날씨 */
|
|
214
|
+
day_2: API_Res_WeatherKoreaNextDays;
|
|
215
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 위경도 좌표.
|
|
3
|
+
* @property {number | null} latitude 위도
|
|
4
|
+
* @property {number | null} longitude 경도
|
|
5
|
+
*/
|
|
6
|
+
export type GeoCoordinate = {
|
|
7
|
+
/** 위도 */
|
|
8
|
+
latitude: number | null;
|
|
9
|
+
/** 경도 */
|
|
10
|
+
longitude: number | null;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 날씨 API에서 사용하는 위경도 좌표.
|
|
15
|
+
* @property {number | null} lat 위도
|
|
16
|
+
* @property {number | null} lng 경도
|
|
17
|
+
*/
|
|
18
|
+
export type WeatherGeoCoordinate = {
|
|
19
|
+
/** 위도 */
|
|
20
|
+
lat: number | null;
|
|
21
|
+
/** 경도 */
|
|
22
|
+
lng: number | null;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* 좌표와 주소 정보를 함께 담는 구조.
|
|
27
|
+
* @property {string | null} address 좌표 주소
|
|
28
|
+
*/
|
|
29
|
+
export type WeatherCoordinate = {
|
|
30
|
+
/** 좌표 주소 */
|
|
31
|
+
address: string | null;
|
|
32
|
+
} & WeatherGeoCoordinate;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* 날씨 로직에서 사용하는 날짜 기준값 모음.
|
|
36
|
+
* @property {Date} now 현재 시각
|
|
37
|
+
* @property {string} today 오늘 날짜(yyyymmdd)
|
|
38
|
+
* @property {string} tomorrow 내일 날짜(yyyymmdd)
|
|
39
|
+
* @property {string} dayAfterTomorrow 모레 날짜(yyyymmdd)
|
|
40
|
+
*/
|
|
41
|
+
export type WeatherUtilDateTimeMoments = {
|
|
42
|
+
/** 현재 시각 */
|
|
43
|
+
now: Date;
|
|
44
|
+
/** 오늘 날짜(yyyymmdd) */
|
|
45
|
+
today: string;
|
|
46
|
+
/** 내일 날짜(yyyymmdd) */
|
|
47
|
+
tomorrow: string;
|
|
48
|
+
/** 모레 날짜(yyyymmdd) */
|
|
49
|
+
dayAfterTomorrow: string;
|
|
50
|
+
};
|