diff --git a/.eslintrc.js b/.eslintrc.js index bfd4b2e5..02040472 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -5,4 +5,7 @@ module.exports = { "plugin:prettier/recommended", "plugin:storybook/recommended", ], + rules: { + "react-hooks/exhaustive-deps": "off", + }, }; diff --git a/pages/api/weather.ts b/pages/api/weather.ts new file mode 100644 index 00000000..684d29df --- /dev/null +++ b/pages/api/weather.ts @@ -0,0 +1,82 @@ +import axios from "axios"; +import { LOCATION_OBJECT } from "create/WeatherBox/const"; +import { getCorrectBaseTime } from "create/WeatherBox/helper"; +import { WeatherItem, WeatherResponse } from "create/WeatherBox/interfaces"; +import { isEmpty, isUndefined } from "lodash"; +import { NextApiRequest, NextApiResponse } from "next"; + +export default async function handler( + req: NextApiRequest, + res: NextApiResponse, +) { + const { date, locationCode } = req.query; + if (isEmpty(date) || isEmpty(locationCode)) return res.status(400).end(); + const { x, y } = LOCATION_OBJECT[locationCode as string]; + + const params = { + serviceKey: process.env.NEXT_PUBLIC_WEATHER_API_KEY ?? "", + numOfRows: "846", + pageNo: "1", + nx: x, + ny: y, + dataType: "JSON", + ...getCorrectBaseTime(), + }; + + const result = await axios.get( + "http://apis.data.go.kr/1360000/VilageFcstInfoService_2.0/getVilageFcst", + { params }, + ); + + const items = result.data.response.body.items.item as WeatherItem[]; + const newWeatherObject = items.reduce((acc, cur) => { + const date = cur.fcstDate; + if (isUndefined(acc[date])) { + acc[date] = { + TMP: Array(24), + SKY: Array(24), + PTY: Array(24), + }; + } + + switch (cur.category) { + case "TMP": + case "SKY": + case "PTY": + const time = Number(cur.fcstTime.slice(0, 2)); + acc[date][cur.category][time] = Number(cur.fcstValue); + break; + case "TMN": + case "TMX": + acc[date][cur.category] = Number(cur.fcstValue); + break; + } + return acc; + }, {} as WeatherResponse); + + res.json(newWeatherObject); +} + +/** + * + * 하늘상태(SKY) 코드 : 맑음(1), 구름많음(3), 흐림(4) + * 강수형태(PTY) 코드 : 없음(0), 비(1), 비/눈(2), 눈(3), 소나기(4) + * + * 단기예보 제공 시간대는 0200, 0500, 0800, 1100, 1400, 1700, 2000, 2300 + * API 제공 시간(~이후) : 02:10, 05:10, 08:10, 11:10, 14:10, 17:10, 20:10, 23:10 + * + * POP 강수확률 + * PTY 강수형태 + * PCP 1시간 강수량 + * REH 습도 + * SNO 1시간 신적설 + * SKY 하늘상태 + * TMP 1시간 기온 + * TMN 일 최저기온 + * TMX 일 최고기온 + * UUU 풍속(동서성분) + * VVV 풍속(남북성분) + * WAV 파고 + * VEC 풍향 + * WSD 풍속 + */ diff --git a/pages/test/weather-test.tsx b/pages/test/weather-test.tsx new file mode 100644 index 00000000..f75c5dc3 --- /dev/null +++ b/pages/test/weather-test.tsx @@ -0,0 +1,57 @@ +import WeatherBox from "create/WeatherBox"; +import { + getLoc1Arrays, + getLoc2Arrays, + getLocationCode, +} from "create/WeatherBox/helper"; +import { ChangeEvent, useEffect, useState } from "react"; +import SelectBox from "@shared/components/SelectBox"; + +const WeatherTest = () => { + const [loc1Arrays] = useState(getLoc1Arrays()); + const [loc2Arrays, setLoc2Arrays] = useState([]); + + const [selectedLoc1, setSelectedLoc1] = useState(""); + const [selectedLoc2, setSelectedLoc2] = useState(""); + + const [date, setDate] = useState(""); + + useEffect(() => { + setLoc2Arrays(getLoc2Arrays(selectedLoc1)); + setSelectedLoc2(""); + }, [selectedLoc1]); + + const handleChangeSelectBoxLoc1 = (e: ChangeEvent) => { + setSelectedLoc1(e.target.value); + }; + + const handleChangeSelectBoxLoc2 = (e: ChangeEvent) => { + setSelectedLoc2(e.target.value); + }; + + const handleChangeDate = (e: ChangeEvent) => { + setDate(e.target.value); + }; + + return ( +
+ + + + +
+ ); +}; + +export default WeatherTest; diff --git a/public/assets/weather/hailstone.png b/public/assets/weather/hailstone.png new file mode 100644 index 00000000..3b08504c Binary files /dev/null and b/public/assets/weather/hailstone.png differ diff --git a/public/assets/weather/rainy.png b/public/assets/weather/rainy.png new file mode 100644 index 00000000..477ddbb0 Binary files /dev/null and b/public/assets/weather/rainy.png differ diff --git a/public/assets/weather/snow.png b/public/assets/weather/snow.png new file mode 100644 index 00000000..4976e1a3 Binary files /dev/null and b/public/assets/weather/snow.png differ diff --git a/public/assets/weather/storm.png b/public/assets/weather/storm.png new file mode 100644 index 00000000..8330761f Binary files /dev/null and b/public/assets/weather/storm.png differ diff --git a/public/assets/weather/sunny.png b/public/assets/weather/sunny.png new file mode 100644 index 00000000..18a4df13 Binary files /dev/null and b/public/assets/weather/sunny.png differ diff --git a/public/assets/weather/windy.png b/public/assets/weather/windy.png new file mode 100644 index 00000000..da4f2992 Binary files /dev/null and b/public/assets/weather/windy.png differ diff --git a/src/create/WeatherBox/const.ts b/src/create/WeatherBox/const.ts new file mode 100644 index 00000000..b099cf45 --- /dev/null +++ b/src/create/WeatherBox/const.ts @@ -0,0 +1,269 @@ +import { LocationProps } from "./interfaces"; + +export const BASE_TIMES = [ + "0200", + "0500", + "0800", + "1100", + "1400", + "1700", + "2000", + "2300", +]; +export const LOCATION_OBJECT: Record = { + "1111000000": { loc1: "서울특별시", loc2: "종로구", x: 60, y: 127 }, + "1114000000": { loc1: "서울특별시", loc2: "중구", x: 60, y: 127 }, + "1117000000": { loc1: "서울특별시", loc2: "용산구", x: 60, y: 126 }, + "1120000000": { loc1: "서울특별시", loc2: "성동구", x: 61, y: 127 }, + "1121500000": { loc1: "서울특별시", loc2: "광진구", x: 62, y: 126 }, + "1123000000": { loc1: "서울특별시", loc2: "동대문구", x: 61, y: 127 }, + "1126000000": { loc1: "서울특별시", loc2: "중랑구", x: 62, y: 128 }, + "1129000000": { loc1: "서울특별시", loc2: "성북구", x: 61, y: 127 }, + "1130500000": { loc1: "서울특별시", loc2: "강북구", x: 61, y: 128 }, + "1132000000": { loc1: "서울특별시", loc2: "도봉구", x: 61, y: 129 }, + "1135000000": { loc1: "서울특별시", loc2: "노원구", x: 61, y: 129 }, + "1138000000": { loc1: "서울특별시", loc2: "은평구", x: 59, y: 127 }, + "1141000000": { loc1: "서울특별시", loc2: "서대문구", x: 59, y: 127 }, + "1144000000": { loc1: "서울특별시", loc2: "마포구", x: 59, y: 127 }, + "1147000000": { loc1: "서울특별시", loc2: "양천구", x: 58, y: 126 }, + "1150000000": { loc1: "서울특별시", loc2: "강서구", x: 58, y: 126 }, + "1153000000": { loc1: "서울특별시", loc2: "구로구", x: 58, y: 125 }, + "1154500000": { loc1: "서울특별시", loc2: "금천구", x: 59, y: 124 }, + "1156000000": { loc1: "서울특별시", loc2: "영등포구", x: 58, y: 126 }, + "1159000000": { loc1: "서울특별시", loc2: "동작구", x: 59, y: 125 }, + "1162000000": { loc1: "서울특별시", loc2: "관악구", x: 59, y: 125 }, + "1165000000": { loc1: "서울특별시", loc2: "서초구", x: 61, y: 125 }, + "1168000000": { loc1: "서울특별시", loc2: "강남구", x: 61, y: 126 }, + "1171000000": { loc1: "서울특별시", loc2: "송파구", x: 62, y: 126 }, + "1174000000": { loc1: "서울특별시", loc2: "강동구", x: 62, y: 126 }, + "2611000000": { loc1: "부산광역시", loc2: "중구", x: 97, y: 74 }, + "2614000000": { loc1: "부산광역시", loc2: "서구", x: 97, y: 74 }, + "2617000000": { loc1: "부산광역시", loc2: "동구", x: 98, y: 75 }, + "2620000000": { loc1: "부산광역시", loc2: "영도구", x: 98, y: 74 }, + "2623000000": { loc1: "부산광역시", loc2: "부산진구", x: 97, y: 75 }, + "2626000000": { loc1: "부산광역시", loc2: "동래구", x: 98, y: 76 }, + "2629000000": { loc1: "부산광역시", loc2: "남구", x: 98, y: 75 }, + "2632000000": { loc1: "부산광역시", loc2: "북구", x: 96, y: 76 }, + "2635000000": { loc1: "부산광역시", loc2: "해운대구", x: 99, y: 75 }, + "2638000000": { loc1: "부산광역시", loc2: "사하구", x: 96, y: 74 }, + "2641000000": { loc1: "부산광역시", loc2: "금정구", x: 98, y: 77 }, + "2644000000": { loc1: "부산광역시", loc2: "강서구", x: 96, y: 76 }, + "2647000000": { loc1: "부산광역시", loc2: "연제구", x: 98, y: 76 }, + "2650000000": { loc1: "부산광역시", loc2: "수영구", x: 99, y: 75 }, + "2653000000": { loc1: "부산광역시", loc2: "사상구", x: 96, y: 75 }, + "2671000000": { loc1: "부산광역시", loc2: "기장군", x: 100, y: 77 }, + "2711000000": { loc1: "대구광역시", loc2: "중구", x: 89, y: 90 }, + "2714000000": { loc1: "대구광역시", loc2: "동구", x: 90, y: 91 }, + "2717000000": { loc1: "대구광역시", loc2: "서구", x: 88, y: 90 }, + "2720000000": { loc1: "대구광역시", loc2: "남구", x: 89, y: 90 }, + "2723000000": { loc1: "대구광역시", loc2: "북구", x: 89, y: 91 }, + "2726000000": { loc1: "대구광역시", loc2: "수성구", x: 89, y: 90 }, + "2729000000": { loc1: "대구광역시", loc2: "달서구", x: 88, y: 90 }, + "2771000000": { loc1: "대구광역시", loc2: "달성군", x: 86, y: 88 }, + "2811000000": { loc1: "인천광역시", loc2: "중구", x: 54, y: 125 }, + "2814000000": { loc1: "인천광역시", loc2: "동구", x: 54, y: 125 }, + "2817700000": { loc1: "인천광역시", loc2: "미추홀구", x: 54, y: 124 }, + "2818500000": { loc1: "인천광역시", loc2: "연수구", x: 55, y: 123 }, + "2820000000": { loc1: "인천광역시", loc2: "남동구", x: 56, y: 124 }, + "2823700000": { loc1: "인천광역시", loc2: "부평구", x: 55, y: 125 }, + "2824500000": { loc1: "인천광역시", loc2: "계양구", x: 56, y: 126 }, + "2826000000": { loc1: "인천광역시", loc2: "서구", x: 55, y: 126 }, + "2871000000": { loc1: "인천광역시", loc2: "강화군", x: 51, y: 130 }, + "2872000000": { loc1: "인천광역시", loc2: "옹진군", x: 54, y: 124 }, + "2911000000": { loc1: "광주광역시", loc2: "동구", x: 60, y: 74 }, + "2914000000": { loc1: "광주광역시", loc2: "서구", x: 59, y: 74 }, + "2915500000": { loc1: "광주광역시", loc2: "남구", x: 59, y: 73 }, + "2917000000": { loc1: "광주광역시", loc2: "북구", x: 59, y: 75 }, + "2920000000": { loc1: "광주광역시", loc2: "광산구", x: 57, y: 74 }, + "3011000000": { loc1: "대전광역시", loc2: "동구", x: 68, y: 100 }, + "3014000000": { loc1: "대전광역시", loc2: "중구", x: 68, y: 100 }, + "3017000000": { loc1: "대전광역시", loc2: "서구", x: 67, y: 100 }, + "3020000000": { loc1: "대전광역시", loc2: "유성구", x: 67, y: 101 }, + "3023000000": { loc1: "대전광역시", loc2: "대덕구", x: 68, y: 100 }, + "3111000000": { loc1: "울산광역시", loc2: "중구", x: 102, y: 84 }, + "3114000000": { loc1: "울산광역시", loc2: "남구", x: 102, y: 84 }, + "3117000000": { loc1: "울산광역시", loc2: "동구", x: 104, y: 83 }, + "3120000000": { loc1: "울산광역시", loc2: "북구", x: 103, y: 85 }, + "3171000000": { loc1: "울산광역시", loc2: "울주군", x: 101, y: 84 }, + "3611000000": { + loc1: "세종특별자치시", + loc2: "세종특별자치시", + x: 66, + y: 103, + }, + "4111100000": { loc1: "경기도", loc2: "수원시장안구", x: 60, y: 121 }, + "4111300000": { loc1: "경기도", loc2: "수원시권선구", x: 60, y: 120 }, + "4111500000": { loc1: "경기도", loc2: "수원시팔달구", x: 61, y: 121 }, + "4111700000": { loc1: "경기도", loc2: "수원시영통구", x: 61, y: 120 }, + "4113100000": { loc1: "경기도", loc2: "성남시수정구", x: 63, y: 124 }, + "4113300000": { loc1: "경기도", loc2: "성남시중원구", x: 63, y: 124 }, + "4113500000": { loc1: "경기도", loc2: "성남시분당구", x: 62, y: 123 }, + "4115000000": { loc1: "경기도", loc2: "의정부시", x: 61, y: 130 }, + "4117100000": { loc1: "경기도", loc2: "안양시만안구", x: 59, y: 123 }, + "4117300000": { loc1: "경기도", loc2: "안양시동안구", x: 59, y: 123 }, + "4119000000": { loc1: "경기도", loc2: "부천시", x: 56, y: 125 }, + "4121000000": { loc1: "경기도", loc2: "광명시", x: 58, y: 125 }, + "4122000000": { loc1: "경기도", loc2: "평택시", x: 62, y: 114 }, + "4125000000": { loc1: "경기도", loc2: "동두천시", x: 61, y: 134 }, + "4127100000": { loc1: "경기도", loc2: "안산시상록구", x: 58, y: 121 }, + "4127300000": { loc1: "경기도", loc2: "안산시단원구", x: 57, y: 121 }, + "4128100000": { loc1: "경기도", loc2: "고양시덕양구", x: 57, y: 128 }, + "4128500000": { loc1: "경기도", loc2: "고양시일산동구", x: 56, y: 129 }, + "4128700000": { loc1: "경기도", loc2: "고양시일산서구", x: 56, y: 129 }, + "4129000000": { loc1: "경기도", loc2: "과천시", x: 60, y: 124 }, + "4131000000": { loc1: "경기도", loc2: "구리시", x: 62, y: 127 }, + "4136000000": { loc1: "경기도", loc2: "남양주시", x: 64, y: 128 }, + "4137000000": { loc1: "경기도", loc2: "오산시", x: 62, y: 118 }, + "4139000000": { loc1: "경기도", loc2: "시흥시", x: 57, y: 123 }, + "4141000000": { loc1: "경기도", loc2: "군포시", x: 59, y: 122 }, + "4143000000": { loc1: "경기도", loc2: "의왕시", x: 60, y: 122 }, + "4145000000": { loc1: "경기도", loc2: "하남시", x: 64, y: 126 }, + "4146100000": { loc1: "경기도", loc2: "용인시처인구", x: 64, y: 119 }, + "4146300000": { loc1: "경기도", loc2: "용인시기흥구", x: 62, y: 120 }, + "4146500000": { loc1: "경기도", loc2: "용인시수지구", x: 62, y: 121 }, + "4148000000": { loc1: "경기도", loc2: "파주시", x: 56, y: 131 }, + "4150000000": { loc1: "경기도", loc2: "이천시", x: 68, y: 121 }, + "4155000000": { loc1: "경기도", loc2: "안성시", x: 65, y: 115 }, + "4157000000": { loc1: "경기도", loc2: "김포시", x: 55, y: 128 }, + "4159000000": { loc1: "경기도", loc2: "화성시", x: 57, y: 119 }, + "4161000000": { loc1: "경기도", loc2: "광주시", x: 65, y: 123 }, + "4163000000": { loc1: "경기도", loc2: "양주시", x: 61, y: 131 }, + "4165000000": { loc1: "경기도", loc2: "포천시", x: 64, y: 134 }, + "4167000000": { loc1: "경기도", loc2: "여주시", x: 71, y: 121 }, + "4180000000": { loc1: "경기도", loc2: "연천군", x: 61, y: 138 }, + "4182000000": { loc1: "경기도", loc2: "가평군", x: 69, y: 133 }, + "4183000000": { loc1: "경기도", loc2: "양평군", x: 69, y: 125 }, + "4311100000": { loc1: "충청북도", loc2: "청주시상당구", x: 69, y: 106 }, + "4311200000": { loc1: "충청북도", loc2: "청주시서원구", x: 69, y: 107 }, + "4311300000": { loc1: "충청북도", loc2: "청주시흥덕구", x: 67, y: 106 }, + "4311400000": { loc1: "충청북도", loc2: "청주시청원구", x: 69, y: 107 }, + "4313000000": { loc1: "충청북도", loc2: "충주시", x: 76, y: 114 }, + "4315000000": { loc1: "충청북도", loc2: "제천시", x: 81, y: 118 }, + "4372000000": { loc1: "충청북도", loc2: "보은군", x: 73, y: 103 }, + "4373000000": { loc1: "충청북도", loc2: "옥천군", x: 71, y: 99 }, + "4374000000": { loc1: "충청북도", loc2: "영동군", x: 74, y: 97 }, + "4374500000": { loc1: "충청북도", loc2: "증평군", x: 71, y: 110 }, + "4375000000": { loc1: "충청북도", loc2: "진천군", x: 68, y: 111 }, + "4376000000": { loc1: "충청북도", loc2: "괴산군", x: 74, y: 111 }, + "4377000000": { loc1: "충청북도", loc2: "음성군", x: 72, y: 113 }, + "4380000000": { loc1: "충청북도", loc2: "단양군", x: 84, y: 115 }, + "4413100000": { loc1: "충청남도", loc2: "천안시동남구", x: 63, y: 110 }, + "4413300000": { loc1: "충청남도", loc2: "천안시서북구", x: 63, y: 112 }, + "4415000000": { loc1: "충청남도", loc2: "공주시", x: 63, y: 102 }, + "4418000000": { loc1: "충청남도", loc2: "보령시", x: 54, y: 100 }, + "4420000000": { loc1: "충청남도", loc2: "아산시", x: 60, y: 110 }, + "4421000000": { loc1: "충청남도", loc2: "서산시", x: 51, y: 110 }, + "4423000000": { loc1: "충청남도", loc2: "논산시", x: 62, y: 97 }, + "4425000000": { loc1: "충청남도", loc2: "계룡시", x: 65, y: 99 }, + "4427000000": { loc1: "충청남도", loc2: "당진시", x: 54, y: 112 }, + "4471000000": { loc1: "충청남도", loc2: "금산군", x: 69, y: 95 }, + "4476000000": { loc1: "충청남도", loc2: "부여군", x: 59, y: 99 }, + "4477000000": { loc1: "충청남도", loc2: "서천군", x: 55, y: 94 }, + "4479000000": { loc1: "충청남도", loc2: "청양군", x: 57, y: 103 }, + "4480000000": { loc1: "충청남도", loc2: "홍성군", x: 55, y: 106 }, + "4481000000": { loc1: "충청남도", loc2: "예산군", x: 58, y: 107 }, + "4482500000": { loc1: "충청남도", loc2: "태안군", x: 48, y: 109 }, + "4511100000": { loc1: "전라북도", loc2: "전주시완산구", x: 63, y: 89 }, + "4511300000": { loc1: "전라북도", loc2: "전주시덕진구", x: 63, y: 89 }, + "4513000000": { loc1: "전라북도", loc2: "군산시", x: 56, y: 92 }, + "4514000000": { loc1: "전라북도", loc2: "익산시", x: 60, y: 91 }, + "4518000000": { loc1: "전라북도", loc2: "정읍시", x: 58, y: 83 }, + "4519000000": { loc1: "전라북도", loc2: "남원시", x: 68, y: 80 }, + "4521000000": { loc1: "전라북도", loc2: "김제시", x: 59, y: 88 }, + "4571000000": { loc1: "전라북도", loc2: "완주군", x: 63, y: 89 }, + "4572000000": { loc1: "전라북도", loc2: "진안군", x: 68, y: 88 }, + "4573000000": { loc1: "전라북도", loc2: "무주군", x: 72, y: 93 }, + "4574000000": { loc1: "전라북도", loc2: "장수군", x: 70, y: 85 }, + "4575000000": { loc1: "전라북도", loc2: "임실군", x: 66, y: 84 }, + "4577000000": { loc1: "전라북도", loc2: "순창군", x: 63, y: 79 }, + "4579000000": { loc1: "전라북도", loc2: "고창군", x: 56, y: 80 }, + "4580000000": { loc1: "전라북도", loc2: "부안군", x: 56, y: 87 }, + "4611000000": { loc1: "전라남도", loc2: "목포시", x: 50, y: 67 }, + "4613000000": { loc1: "전라남도", loc2: "여수시", x: 73, y: 66 }, + "4615000000": { loc1: "전라남도", loc2: "순천시", x: 70, y: 70 }, + "4617000000": { loc1: "전라남도", loc2: "나주시", x: 56, y: 71 }, + "4623000000": { loc1: "전라남도", loc2: "광양시", x: 73, y: 70 }, + "4671000000": { loc1: "전라남도", loc2: "담양군", x: 61, y: 78 }, + "4672000000": { loc1: "전라남도", loc2: "곡성군", x: 66, y: 77 }, + "4673000000": { loc1: "전라남도", loc2: "구례군", x: 69, y: 75 }, + "4677000000": { loc1: "전라남도", loc2: "고흥군", x: 66, y: 62 }, + "4678000000": { loc1: "전라남도", loc2: "보성군", x: 62, y: 66 }, + "4679000000": { loc1: "전라남도", loc2: "화순군", x: 61, y: 72 }, + "4680000000": { loc1: "전라남도", loc2: "장흥군", x: 59, y: 64 }, + "4681000000": { loc1: "전라남도", loc2: "강진군", x: 57, y: 63 }, + "4682000000": { loc1: "전라남도", loc2: "해남군", x: 54, y: 61 }, + "4683000000": { loc1: "전라남도", loc2: "영암군", x: 56, y: 66 }, + "4684000000": { loc1: "전라남도", loc2: "무안군", x: 52, y: 71 }, + "4686000000": { loc1: "전라남도", loc2: "함평군", x: 52, y: 72 }, + "4687000000": { loc1: "전라남도", loc2: "영광군", x: 52, y: 77 }, + "4688000000": { loc1: "전라남도", loc2: "장성군", x: 57, y: 77 }, + "4689000000": { loc1: "전라남도", loc2: "완도군", x: 57, y: 56 }, + "4690000000": { loc1: "전라남도", loc2: "진도군", x: 48, y: 59 }, + "4691000000": { loc1: "전라남도", loc2: "신안군", x: 50, y: 66 }, + "4711100000": { loc1: "경상북도", loc2: "포항시남구", x: 102, y: 94 }, + "4711300000": { loc1: "경상북도", loc2: "포항시북구", x: 102, y: 95 }, + "4713000000": { loc1: "경상북도", loc2: "경주시", x: 100, y: 91 }, + "4715000000": { loc1: "경상북도", loc2: "김천시", x: 80, y: 96 }, + "4717000000": { loc1: "경상북도", loc2: "안동시", x: 91, y: 106 }, + "4719000000": { loc1: "경상북도", loc2: "구미시", x: 84, y: 96 }, + "4721000000": { loc1: "경상북도", loc2: "영주시", x: 89, y: 111 }, + "4723000000": { loc1: "경상북도", loc2: "영천시", x: 95, y: 93 }, + "4725000000": { loc1: "경상북도", loc2: "상주시", x: 81, y: 102 }, + "4728000000": { loc1: "경상북도", loc2: "문경시", x: 81, y: 106 }, + "4729000000": { loc1: "경상북도", loc2: "경산시", x: 91, y: 90 }, + "4772000000": { loc1: "경상북도", loc2: "군위군", x: 88, y: 99 }, + "4773000000": { loc1: "경상북도", loc2: "의성군", x: 90, y: 101 }, + "4775000000": { loc1: "경상북도", loc2: "청송군", x: 96, y: 103 }, + "4776000000": { loc1: "경상북도", loc2: "영양군", x: 97, y: 108 }, + "4777000000": { loc1: "경상북도", loc2: "영덕군", x: 102, y: 103 }, + "4782000000": { loc1: "경상북도", loc2: "청도군", x: 91, y: 86 }, + "4783000000": { loc1: "경상북도", loc2: "고령군", x: 83, y: 87 }, + "4784000000": { loc1: "경상북도", loc2: "성주군", x: 83, y: 91 }, + "4785000000": { loc1: "경상북도", loc2: "칠곡군", x: 85, y: 93 }, + "4790000000": { loc1: "경상북도", loc2: "예천군", x: 86, y: 107 }, + "4792000000": { loc1: "경상북도", loc2: "봉화군", x: 90, y: 113 }, + "4793000000": { loc1: "경상북도", loc2: "울진군", x: 102, y: 115 }, + "4794000000": { loc1: "경상북도", loc2: "울릉군", x: 127, y: 127 }, + "4812100000": { loc1: "경상남도", loc2: "창원시의창구", x: 90, y: 77 }, + "4812300000": { loc1: "경상남도", loc2: "창원시성산구", x: 91, y: 76 }, + "4812500000": { loc1: "경상남도", loc2: "창원시마산합포구", x: 89, y: 76 }, + "4812700000": { loc1: "경상남도", loc2: "창원시마산회원구", x: 89, y: 76 }, + "4812900000": { loc1: "경상남도", loc2: "창원시진해구", x: 91, y: 75 }, + "4817000000": { loc1: "경상남도", loc2: "진주시", x: 81, y: 75 }, + "4822000000": { loc1: "경상남도", loc2: "통영시", x: 87, y: 68 }, + "4824000000": { loc1: "경상남도", loc2: "사천시", x: 80, y: 71 }, + "4825000000": { loc1: "경상남도", loc2: "김해시", x: 95, y: 77 }, + "4827000000": { loc1: "경상남도", loc2: "밀양시", x: 92, y: 83 }, + "4831000000": { loc1: "경상남도", loc2: "거제시", x: 90, y: 69 }, + "4833000000": { loc1: "경상남도", loc2: "양산시", x: 97, y: 79 }, + "4872000000": { loc1: "경상남도", loc2: "의령군", x: 83, y: 78 }, + "4873000000": { loc1: "경상남도", loc2: "함안군", x: 86, y: 77 }, + "4874000000": { loc1: "경상남도", loc2: "창녕군", x: 87, y: 83 }, + "4882000000": { loc1: "경상남도", loc2: "고성군", x: 85, y: 71 }, + "4884000000": { loc1: "경상남도", loc2: "남해군", x: 77, y: 68 }, + "4885000000": { loc1: "경상남도", loc2: "하동군", x: 74, y: 73 }, + "4886000000": { loc1: "경상남도", loc2: "산청군", x: 76, y: 80 }, + "4887000000": { loc1: "경상남도", loc2: "함양군", x: 74, y: 82 }, + "4888000000": { loc1: "경상남도", loc2: "거창군", x: 77, y: 86 }, + "4889000000": { loc1: "경상남도", loc2: "합천군", x: 81, y: 84 }, + "5011000000": { loc1: "제주특별자치도", loc2: "제주시", x: 53, y: 38 }, + "5013000000": { loc1: "제주특별자치도", loc2: "서귀포시", x: 52, y: 33 }, + "5111000000": { loc1: "강원특별자치도", loc2: "춘천시", x: 73, y: 134 }, + "5113000000": { loc1: "강원특별자치도", loc2: "원주시", x: 76, y: 122 }, + "5115000000": { loc1: "강원특별자치도", loc2: "강릉시", x: 92, y: 131 }, + "5117000000": { loc1: "강원특별자치도", loc2: "동해시", x: 97, y: 127 }, + "5119000000": { loc1: "강원특별자치도", loc2: "태백시", x: 95, y: 119 }, + "5121000000": { loc1: "강원특별자치도", loc2: "속초시", x: 87, y: 141 }, + "5123000000": { loc1: "강원특별자치도", loc2: "삼척시", x: 98, y: 125 }, + "5172000000": { loc1: "강원특별자치도", loc2: "홍천군", x: 75, y: 130 }, + "5173000000": { loc1: "강원특별자치도", loc2: "횡성군", x: 77, y: 125 }, + "5175000000": { loc1: "강원특별자치도", loc2: "영월군", x: 86, y: 119 }, + "5176000000": { loc1: "강원특별자치도", loc2: "평창군", x: 84, y: 123 }, + "5177000000": { loc1: "강원특별자치도", loc2: "정선군", x: 89, y: 123 }, + "5178000000": { loc1: "강원특별자치도", loc2: "철원군", x: 65, y: 139 }, + "5179000000": { loc1: "강원특별자치도", loc2: "화천군", x: 72, y: 139 }, + "5180000000": { loc1: "강원특별자치도", loc2: "양구군", x: 77, y: 139 }, + "5181000000": { loc1: "강원특별자치도", loc2: "인제군", x: 80, y: 138 }, + "5182000000": { loc1: "강원특별자치도", loc2: "고성군", x: 85, y: 145 }, + "5183000000": { loc1: "강원특별자치도", loc2: "양양군", x: 88, y: 138 }, +}; diff --git a/src/create/WeatherBox/helper.ts b/src/create/WeatherBox/helper.ts new file mode 100644 index 00000000..1388e600 --- /dev/null +++ b/src/create/WeatherBox/helper.ts @@ -0,0 +1,72 @@ +import { BASE_TIMES, LOCATION_OBJECT } from "./const"; + +/** + * @description loc1 배열을 반환 + */ +export const getLoc1Arrays = () => { + return Object.values(LOCATION_OBJECT).reduce((prev, curr) => { + if (!prev.includes(curr.loc1)) return [...prev, curr.loc1]; + return prev; + }, []); +}; + +/** + * @description loc1에 해당하는 loc2 배열을 반환 + */ +export const getLoc2Arrays = (loc1: string) => { + return Object.values(LOCATION_OBJECT).reduce((prev, curr) => { + if (curr.loc1 === loc1 && !prev.includes(curr.loc2)) + return [...prev, curr.loc2]; + return prev; + }, []); +}; + +/** + * @description loc1, loc2에 해당하는 locationCode를 반환 + */ +export const getLocationCode = (loc1: string, loc2: string) => { + if (loc1 === "" || loc2 === "") return ""; + const selectedLoc = Object.entries(LOCATION_OBJECT).find( + ([_, value]) => value.loc1 === loc1 && value.loc2 === loc2, + ); + return selectedLoc?.[0] ?? ""; +}; + +/** + * @description Date 데이터를 YYYYMMDD 형식으로 반환 + */ +export const formatDate = (dateString?: string | number) => { + const date = new Date(dateString ?? Date.now()); + const year = date.getFullYear(); + const month = (date.getMonth() + 1).toString().padStart(2, "0"); + const day = date.getDate().toString().padStart(2, "0"); + return `${year}${month}${day}`; +}; + +/** + * @description 현재 시간에 맞는 base_date, base_time을 반환 + */ +export const getCorrectBaseTime = () => { + const today = new Date(); + const currentHour = today.getHours(); + const currentMinute = today.getMinutes(); + + if (currentHour < 2 || (currentHour === 2 && currentMinute < 10)) + return { + base_date: formatDate(today.setDate(today.getDate() - 1)), + base_time: "2300", + }; + + for (let i = 1; i < BASE_TIMES.length; i++) { + const baseTime = BASE_TIMES[i - 1]; + if ( + currentHour < i * 3 + 2 || + (currentHour === i * 3 + 2 && currentMinute < 10) + ) { + return { + base_date: formatDate(), + base_time: baseTime, + }; + } + } +}; diff --git a/src/create/WeatherBox/index.tsx b/src/create/WeatherBox/index.tsx new file mode 100644 index 00000000..9af86676 --- /dev/null +++ b/src/create/WeatherBox/index.tsx @@ -0,0 +1,68 @@ +import axios from "axios"; +import Image from "next/image"; +import { useEffect, useState } from "react"; +import { LOCATION_OBJECT } from "./const"; +import { WeatherBoxProps, WeatherObject, WeatherResponse } from "./interfaces"; +import Sunny from "/public/assets/weather/sunny.png"; + +const WeatherBox = (props: WeatherBoxProps) => { + const locObj = LOCATION_OBJECT[props.locationCode]; + const [weatherObject, setWeatherObject] = useState(); + + useEffect(() => { + axios + .get("/api/weather", { params: props }) + .then((res) => { + const rawDate = props.date.replace(/-/g, ""); + if (res.data[rawDate]) { + console.log(res.data[rawDate]); + setWeatherObject(res.data[rawDate]); + } + return; + }) + .catch((err) => {}); + }, [props.locationCode]); + + const getWeatherText = () => { + return ""; + }; + + return ( +
+
+
+
+ {locObj?.loc1} +
+
+ {locObj?.loc2} +
+
+ {getWeatherText()} + {/* TODO: 하늘상태, 강수상태에 따른 텍스트 변경 기능 추가 */} +
+
+
+ {weatherObject?.TMX && weatherObject?.TMN ? ( + <> +
+ + {weatherObject?.TMN} / {weatherObject?.TMX} + + °C +
+
+ + {/* TODO: 하늘상태, 강수상태에 따른 아이콘 변경 기능 추가 */} +
+ + ) : ( +
예상 날씨를 알 수 없어요
+ )} +
+
+
+ ); +}; + +export default WeatherBox; diff --git a/src/create/WeatherBox/interfaces.ts b/src/create/WeatherBox/interfaces.ts new file mode 100644 index 00000000..9b60d029 --- /dev/null +++ b/src/create/WeatherBox/interfaces.ts @@ -0,0 +1,46 @@ +export interface WeatherBoxProps { + date: string; + locationCode: string; +} +export interface WeatherItem { + baseDate: string; + baseTime: string; + category: WCategory; + fcstDate: string; + fcstTime: string; + fcstValue: string; + nx: number; + ny: number; +} +export interface LocationProps { + loc1: string; + loc2: string; + x: number; + y: number; +} +export type WCategory = + | "POP" + | "PTY" + | "PCP" + | "REH" + | "SNO" + | "SKY" + | "TMP" + | "TMN" + | "TMX" + | "UUU" + | "VVV" + | "WAV" + | "VEC" + | "WSD"; + +export interface WeatherObject { + TMP: number[]; + SKY: number[]; + PTY: number[]; + TMN?: number; + TMX?: number; +} +export interface WeatherResponse { + [key: string]: WeatherObject; +} diff --git a/src/shared/components/SelectBox.tsx b/src/shared/components/SelectBox.tsx new file mode 100644 index 00000000..dd438188 --- /dev/null +++ b/src/shared/components/SelectBox.tsx @@ -0,0 +1,26 @@ +interface SelectBoxProps extends React.HTMLAttributes { + options: string[]; + defaultLabel?: string; +} +/** + * @param options + * @returns SelectBox + * @description 셀렉트 박스 + */ +const SelectBox = (props: SelectBoxProps) => { + return ( + + ); +}; + +export default SelectBox; diff --git a/tailwind.config.js b/tailwind.config.js index 738d1256..3aff6dce 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -6,6 +6,19 @@ module.exports = { ], theme: { extend: { + colors: { + "c-accept": "#00D179", // green. 확인용 색상 + "c-accept-disabled": "#00D17975", // green-disabled + "c-warn": "#FACD49", // yellow. 경고용 색상 + "c-warn-disabled": "#FACD4975", // yellow-disabled + "c-danger": "#FF2330", // red. 에러용 색상 + "c-danger-disabled": "#FFA4A475", // red-disabled + "c-pink": "#F864A1", + "c-orange": "#F5A200", + "c-purple": "#A564F8", + "c-gray": "#BABABA", + "c-black": "#222222", + }, backgroundImage: { stayLoggedIn: "url(/images/samples/StayLoggedIn.svg)", idLabel: "url(/images/samples/IdLabel.svg)",