Showing
45 changed files
with
1712 additions
and
18 deletions
package-lock.json
0 → 100644
This diff is collapsed. Click to expand it.
weather_briefing/bash.exe.stackdump
0 → 100644
1 | +Stack trace: | ||
2 | +Frame Function Args | ||
3 | +000005FF340 0018006286E (001802901B2, 0018026DE3E, 0000000005E, 000005FAEA0) | ||
4 | +000005FF340 0018004846A (00000000000, 00000000000, 7FFE00000000, 00000001000) | ||
5 | +000005FF340 001800484A2 (00000000000, 0000000005A, 0000000005E, 00000000000) | ||
6 | +000005FF340 001800D3E58 (00000000000, 00100000000, 0018026D9F2, 000005FBFEC) | ||
7 | +000005FF340 0018012C857 (00000000000, 00180223E20, 00180223E10, 000005FDDE0) | ||
8 | +000005FF340 001800488B4 (0018030F940, 000005FDDE0, 00000000000, 00000000000) | ||
9 | +000005FF340 0018004A01F (0007FFE0384, 00000000000, 00000000000, 00000000000) | ||
10 | +000005FF340 001800D4E98 (00000000000, 00000000000, 00000000000, 00000000000) | ||
11 | +000005FF5E0 7FFE062E9A1D (00180040000, 00000000001, 00000000000, 000005FF528) | ||
12 | +000005FF5E0 7FFE0633C1E7 (7FFE0630DB00, 000007F3901, 7FFE00000001, 00000000001) | ||
13 | +000005FF5E0 7FFE0633BF7A (000007F3900, 000005FF5E0, 000007F4270, 00000070000) | ||
14 | +000005FF5E0 7FFE0633C000 (00000000010, 00000000000, 7FFE06401A90, 000005FF678) | ||
15 | +00000000000 7FFE063A3C2A (00000000000, 00000000000, 00000000001, 00000000000) | ||
16 | +00000000000 7FFE06344CDB (7FFE062D0000, 00000000000, 00000347000, 00000000000) | ||
17 | +00000000000 7FFE06344B63 (00000000000, 00000000000, 00000000000, 00000000000) | ||
18 | +00000000000 7FFE06344B0E (00000000000, 00000000000, 00000000000, 00000000000) | ||
19 | +End of stack trace |
This diff could not be displayed because it is too large.
... | @@ -6,6 +6,7 @@ | ... | @@ -6,6 +6,7 @@ |
6 | "@testing-library/jest-dom": "^5.16.4", | 6 | "@testing-library/jest-dom": "^5.16.4", |
7 | "@testing-library/react": "^13.2.0", | 7 | "@testing-library/react": "^13.2.0", |
8 | "@testing-library/user-event": "^13.5.0", | 8 | "@testing-library/user-event": "^13.5.0", |
9 | + "axios": "^0.27.2", | ||
9 | "cors": "^2.8.5", | 10 | "cors": "^2.8.5", |
10 | "express": "^4.18.1", | 11 | "express": "^4.18.1", |
11 | "http-proxy-middleware": "^2.0.6", | 12 | "http-proxy-middleware": "^2.0.6", |
... | @@ -13,7 +14,12 @@ | ... | @@ -13,7 +14,12 @@ |
13 | "nodemon": "^2.0.16", | 14 | "nodemon": "^2.0.16", |
14 | "react": "^18.1.0", | 15 | "react": "^18.1.0", |
15 | "react-dom": "^18.1.0", | 16 | "react-dom": "^18.1.0", |
17 | + "react-redux": "^8.0.2", | ||
18 | + "react-router-dom": "^6.3.0", | ||
16 | "react-scripts": "5.0.1", | 19 | "react-scripts": "5.0.1", |
20 | + "redux": "^4.1.2", | ||
21 | + "redux-promise-middleware": "^6.1.2", | ||
22 | + "redux-thunk": "^2.4.1", | ||
17 | "web-vitals": "^2.1.4" | 23 | "web-vitals": "^2.1.4" |
18 | }, | 24 | }, |
19 | "scripts": { | 25 | "scripts": { |
... | @@ -39,5 +45,8 @@ | ... | @@ -39,5 +45,8 @@ |
39 | "last 1 firefox version", | 45 | "last 1 firefox version", |
40 | "last 1 safari version" | 46 | "last 1 safari version" |
41 | ] | 47 | ] |
48 | + }, | ||
49 | + "devDependencies": { | ||
50 | + "redux-devtools-extension": "^2.13.9" | ||
42 | } | 51 | } |
43 | } | 52 | } | ... | ... |
weather_briefing/public/img/가디건.jpg
0 → 100644
15.1 KB
weather_briefing/public/img/가죽자켓.jpg
0 → 100644
19.4 KB
weather_briefing/public/img/기모옷.jpg
0 → 100644
4.94 KB
weather_briefing/public/img/니트.jpg
0 → 100644
1.4 KB
weather_briefing/public/img/롱스커트.jpg
0 → 100644
31 KB
weather_briefing/public/img/린넨셔츠.jpg
0 → 100644
37.4 KB
weather_briefing/public/img/맨투맨.jpg
0 → 100644
844 KB
weather_briefing/public/img/면바지.jpg
0 → 100644
7.47 KB
weather_briefing/public/img/민소매.jpg
0 → 100644
24.8 KB
weather_briefing/public/img/반바지.jpg
0 → 100644
14.3 KB
weather_briefing/public/img/반팔.jpg
0 → 100644
19.4 KB
weather_briefing/public/img/블라우스.jpg
0 → 100644
27.4 KB
weather_briefing/public/img/스타킹.jpg
0 → 100644
25.5 KB
weather_briefing/public/img/슬랙스.jpg
0 → 100644
6.17 KB
weather_briefing/public/img/울코트.jpg
0 → 100644
5.12 KB
weather_briefing/public/img/자켓.jpg
0 → 100644
22 KB
weather_briefing/public/img/조거팬츠.jpg
0 → 100644
3.82 KB
weather_briefing/public/img/청바지.jpg
0 → 100644
39.2 KB
weather_briefing/public/img/청자켓.jpg
0 → 100644
40.8 KB
weather_briefing/public/img/치마.jpg
0 → 100644
10.2 KB
weather_briefing/public/img/트렌치코트.jpg
0 → 100644
61.7 KB
weather_briefing/public/img/패딩.jpg
0 → 100644
5.42 KB
weather_briefing/public/img/핫팬츠.jpg
0 → 100644
14.9 KB
weather_briefing/public/img/후드티.jpg
0 → 100644
44.1 KB
1 | -import logo from './logo.svg'; | ||
2 | import './App.css'; | 1 | import './App.css'; |
2 | +import RegisterPage from './component/views/RegisterPage/RegisterPage'; | ||
3 | +import LoginPage from './component/views/LoginPage/LoginPage'; | ||
4 | +import MainPage from './component/views/MainPage/MainPage'; | ||
5 | +import RecommandPage from './component/views/RecommandPage/RecommandPage'; | ||
6 | +import { Route, Routes } from 'react-router-dom'; | ||
7 | +import WeatherPage from './component/views/WeatherPage/WeatherPage'; | ||
3 | 8 | ||
4 | function App() { | 9 | function App() { |
5 | return ( | 10 | return ( |
6 | - <div className="App"> | 11 | + <div> |
7 | - <header className="App-header"> | 12 | + <Routes> |
8 | - <img src={logo} className="App-logo" alt="logo" /> | 13 | + <Route exact path = "/login" element = {<LoginPage/>}/> |
9 | - <p> | 14 | + <Route exact path = "/" element = {<RegisterPage/>}/> |
10 | - Edit <code>src/App.js</code> and save to reload. | 15 | + <Route exact path = "/main" element = {<MainPage/>}/> |
11 | - </p> | 16 | + <Route exact path = "/weather" element = {<WeatherPage/>}/> |
12 | - <a | 17 | + <Route exact path = "/recommand" element = {<RecommandPage/>}/> |
13 | - className="App-link" | 18 | + </Routes> |
14 | - href="https://reactjs.org" | ||
15 | - target="_blank" | ||
16 | - rel="noopener noreferrer" | ||
17 | - > | ||
18 | - Learn React | ||
19 | - </a> | ||
20 | - </header> | ||
21 | </div> | 19 | </div> |
22 | ); | 20 | ); |
23 | } | 21 | } | ... | ... |
1 | +import React, { useCallback, useEffect, useState } from "react"; | ||
2 | +import { useDispatch, useSelector } from "react-redux"; | ||
3 | +import { useNavigate } from "react-router-dom"; | ||
4 | +import { login } from "../../../modules/user"; | ||
5 | +import { address } from "../../../modules/weather"; | ||
6 | +import "../style/LoginPage.scss" | ||
7 | + | ||
8 | +function LoginPage(props) { | ||
9 | + const dispatch = useDispatch(); | ||
10 | + const navigate = useNavigate(); | ||
11 | + | ||
12 | + const loginResult = useSelector((state) => state.user.loginData); | ||
13 | + | ||
14 | + const [Id, setId] = useState(""); | ||
15 | + const [Password, setPassword] = useState(""); | ||
16 | + | ||
17 | + const [checkLogin, setCheckLogin] = useState(false); | ||
18 | + const [checkIdError, setCheckIdError] = useState(false); | ||
19 | + const [checkPasswordError, setCheckPasswordError] = useState(false); | ||
20 | + const [checkLoginError, setCheckLoginError] = useState(false); | ||
21 | + | ||
22 | + const idRegex = /^(?=.*[a-zA-Z])(?=.*[0-9]).{6,14}$/; | ||
23 | + const passwordRegex = /^(?=.*[a-zA-Z])(?=.*[!@#$%^*+=-?])(?=.*[0-9]).{8,25}$/; | ||
24 | + | ||
25 | + useEffect(() => { | ||
26 | + if (checkLogin === true) { | ||
27 | + loginResult.then((result) => { | ||
28 | + if (result.loginSuccess === true) { | ||
29 | + alert('로그인에 성공하였습니다.'); | ||
30 | + navigate('/main'); | ||
31 | + } | ||
32 | + else { | ||
33 | + alert('로그인에 실패하였습니다.'); | ||
34 | + } | ||
35 | + }) | ||
36 | + } | ||
37 | + }, [loginResult]) | ||
38 | + | ||
39 | + const onIdHandler = useCallback((event) => { | ||
40 | + setId(event.currentTarget.value); | ||
41 | + | ||
42 | + // 아이디 유효성 검사 | ||
43 | + if (!idRegex.test(event.currentTarget.value)) { | ||
44 | + setCheckIdError(true); | ||
45 | + } | ||
46 | + else { | ||
47 | + setCheckIdError(false); | ||
48 | + } | ||
49 | + | ||
50 | + }, [checkIdError]); | ||
51 | + | ||
52 | + const onPasswordHandler = useCallback((event) => { | ||
53 | + setPassword(event.currentTarget.value); | ||
54 | + | ||
55 | + // 비밀번호 유효성 검사 | ||
56 | + if (!passwordRegex.test(event.currentTarget.value)) { | ||
57 | + setCheckPasswordError(true); | ||
58 | + } | ||
59 | + else { | ||
60 | + setCheckPasswordError(false); | ||
61 | + } | ||
62 | + }, [checkPasswordError]); | ||
63 | + | ||
64 | + const onSubmitHandler = useCallback((event) => { | ||
65 | + event.preventDefault(); | ||
66 | + | ||
67 | + if (checkIdError || Id === "") { | ||
68 | + setCheckLoginError(true); | ||
69 | + } | ||
70 | + else if (checkPasswordError || Password === "") { | ||
71 | + setCheckLoginError(true); | ||
72 | + } | ||
73 | + else { | ||
74 | + setCheckLoginError(false); | ||
75 | + } | ||
76 | + | ||
77 | + // login | ||
78 | + if (!checkLoginError) { | ||
79 | + const UserData = { | ||
80 | + id: Id, | ||
81 | + password: Password | ||
82 | + }; | ||
83 | + | ||
84 | + dispatch(login(UserData)); | ||
85 | + dispatch(address()); | ||
86 | + setCheckLogin(true); | ||
87 | + | ||
88 | + } | ||
89 | + | ||
90 | + }, [checkIdError, checkPasswordError, Password, dispatch, loginResult]); | ||
91 | + | ||
92 | + return ( | ||
93 | + <div id = "body"> | ||
94 | + <div className="login-box"> | ||
95 | + <h2>로그인</h2> | ||
96 | + <div className="input-area"> | ||
97 | + <input | ||
98 | + placeholder="아이디" | ||
99 | + type="text" | ||
100 | + value={Id} | ||
101 | + onChange={onIdHandler} | ||
102 | + /> | ||
103 | + </div> | ||
104 | + <div className="check-variable"> | ||
105 | + {checkIdError && <div style={{color : 'red'}}>아이디는 6자리 이상 14자리 이하 소문자와 숫자로 입력해주세요.</div>} | ||
106 | + </div> | ||
107 | + <div className="input-area"> | ||
108 | + <input | ||
109 | + placeholder="비밀번호" | ||
110 | + type="text" | ||
111 | + value={Password} | ||
112 | + onChange={onPasswordHandler} | ||
113 | + /> | ||
114 | + </div> | ||
115 | + <div className="check-variable"> | ||
116 | + {checkPasswordError && <div style={{color : 'red'}}>알파벳과 숫자, 특수문자를 포함하여 8자리 이상 입력해주세요.</div>} | ||
117 | + </div> | ||
118 | + <div className="btn-area" onClick={onSubmitHandler}> | ||
119 | + <button | ||
120 | + className="login-btn" | ||
121 | + > | ||
122 | + 로그인 | ||
123 | + </button> | ||
124 | + </div> | ||
125 | + <div className="check-variable"> | ||
126 | + {checkLoginError && <div style={{color : 'red'}}>정보를 제대로 입력해주세요.</div>} | ||
127 | + </div> | ||
128 | + </div> | ||
129 | + </div> | ||
130 | + ); | ||
131 | + | ||
132 | +} | ||
133 | + | ||
134 | +export default LoginPage; | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | +import React, { useCallback, useEffect, useState } from "react"; | ||
2 | +import { useDispatch, useSelector } from "react-redux"; | ||
3 | +import { useNavigate } from "react-router-dom"; | ||
4 | +import { logout } from "../../../modules/user"; | ||
5 | +import { todayInformation, tommorrowInformation } from "../../../modules/weather"; | ||
6 | +import "../style/MainPage.scss" | ||
7 | + | ||
8 | +function MainPage(props) { | ||
9 | + | ||
10 | + const dispatch = useDispatch(); | ||
11 | + const navigate = useNavigate(); | ||
12 | + | ||
13 | + const addressResult = useSelector((state) => state.weather.address); | ||
14 | + const user = useSelector((state) => state.user.loginData); | ||
15 | + | ||
16 | + //이름, 성별, 시구동주소 | ||
17 | + const [Name, setName] = useState(""); | ||
18 | + const [Sex, setSex] = useState(""); | ||
19 | + const [CityAdd, setCityAdd] = useState(""); | ||
20 | + const [GuAdd, setGuAdd] = useState(""); | ||
21 | + const [DongAdd, setDongAdd] = useState(""); | ||
22 | + | ||
23 | + // const [checkNameError, setCheckNameError] = useState(false); | ||
24 | + // const [checkSexError, setCheckSexError] = useState(true); | ||
25 | + const [checkCityAddError, setCheckCityAddError] = useState(true); | ||
26 | + const [checkGuAddError, setCheckGuAddError] = useState(true); | ||
27 | + const [checkDongAddError, setCheckDongAddError] = useState(true); | ||
28 | + const [checkSubmitError, setCheckSubmitError] = useState(false); | ||
29 | + | ||
30 | + const CityAddSelectList = ["시/도 선택", "강원도", "경기도", "경상북도", "경상남도", "광주광역시", "대구광역시", "대전광역시", "부산광역시", "서울특별시", "울산광역시", "인천광역시", "전라북도", "전라남도", "제주특별자치도", "충청북도", "충청남도"]; | ||
31 | + | ||
32 | + const [GuAddSelectList, setGuAddselectList] = useState(["시/군/구 선택"]); | ||
33 | + const [DongAddSelectList, setDongAddselectList] = useState(["읍/면/동 선택"]); | ||
34 | + | ||
35 | + const [Time, setTime] = useState("00:00:00"); | ||
36 | + | ||
37 | + const currentTime = () => { | ||
38 | + const date = new Date(); | ||
39 | + const hours = String(date.getHours()).padStart(2, "0"); | ||
40 | + const minutes = String(date.getMinutes()).padStart(2, "0"); | ||
41 | + const seconds = String(date.getSeconds()).padStart(2, "0"); | ||
42 | + setTime(hours+" : "+minutes+" : "+seconds); | ||
43 | + } | ||
44 | + | ||
45 | + const startTimer = () => { | ||
46 | + setInterval(currentTime, 1000) | ||
47 | + } | ||
48 | + | ||
49 | + startTimer() | ||
50 | + | ||
51 | + useEffect(() => { | ||
52 | + user.then((result) => { | ||
53 | + setName(result.logData.name); | ||
54 | + setSex(result.logData.gender); | ||
55 | + }) | ||
56 | + }, [user]) | ||
57 | + | ||
58 | + // 시/군/구 주소 | ||
59 | + useEffect(() => { | ||
60 | + const tempList = []; | ||
61 | + | ||
62 | + addressResult.then((result) => { | ||
63 | + | ||
64 | + for (let i = 0; i < result.length; i++) { | ||
65 | + if (result[i].address1 === CityAdd) { | ||
66 | + if (tempList[tempList.length - 1] !== result[i].address2){ | ||
67 | + tempList.push(result[i].address2); | ||
68 | + } | ||
69 | + } | ||
70 | + } | ||
71 | + tempList[0] = "시/군/구 선택"; | ||
72 | + setGuAddselectList(tempList); | ||
73 | + setDongAddselectList(["읍/면/동 선택"]); | ||
74 | + }); | ||
75 | + }, [CityAdd]); | ||
76 | + | ||
77 | + // 읍/면/동 주소 | ||
78 | + useEffect(() => { | ||
79 | + const tempList = []; | ||
80 | + | ||
81 | + addressResult.then((result) => { | ||
82 | + | ||
83 | + for (let i = 0; i < result.length; i++) { | ||
84 | + if (result[i].address2 === GuAdd) { | ||
85 | + if ((tempList[tempList.length - 1] !== result[i].address3) && tempList[0] !== result[i].address3){ | ||
86 | + tempList.push(result[i].address3); | ||
87 | + } | ||
88 | + } | ||
89 | + } | ||
90 | + tempList[0] = "읍/면/동 선택"; | ||
91 | + setDongAddselectList(tempList); | ||
92 | + }); | ||
93 | + }, [GuAdd]); | ||
94 | + | ||
95 | + const onCityAddhandler = useCallback((event) => { | ||
96 | + setCityAdd(event.currentTarget.value); | ||
97 | + | ||
98 | + if (event.currentTarget.value === "시/도 선택") { | ||
99 | + setCheckCityAddError(true); | ||
100 | + } | ||
101 | + else { | ||
102 | + setCheckCityAddError(false); | ||
103 | + } | ||
104 | + }, [checkCityAddError]); | ||
105 | + | ||
106 | + const onGuAddhandler = useCallback((event) => { | ||
107 | + setGuAdd(event.currentTarget.value); | ||
108 | + | ||
109 | + if (event.currentTarget.value === "시/군/구 선택") { | ||
110 | + setCheckGuAddError(true); | ||
111 | + } | ||
112 | + else { | ||
113 | + setCheckGuAddError(false); | ||
114 | + } | ||
115 | + | ||
116 | + }, [checkGuAddError]); | ||
117 | + | ||
118 | + const onDongAddhandler = useCallback((event) => { | ||
119 | + setDongAdd(event.currentTarget.value); | ||
120 | + | ||
121 | + if (event.currentTarget.value === "읍/면/동 선택") { | ||
122 | + setCheckDongAddError(true); | ||
123 | + } | ||
124 | + else { | ||
125 | + setCheckDongAddError(false); | ||
126 | + } | ||
127 | + }, [checkDongAddError]); | ||
128 | + | ||
129 | + const onClickTitle = useCallback((event) => { | ||
130 | + navigate('/main') | ||
131 | + }) | ||
132 | + | ||
133 | + const onClickLogout = useCallback((event) => { | ||
134 | + dispatch(logout()); | ||
135 | + navigate('/login'); | ||
136 | + }) | ||
137 | + | ||
138 | + const onClickRegister = useCallback((event) => { | ||
139 | + navigate('/'); | ||
140 | + }) | ||
141 | + | ||
142 | + const onSubmitHandler = useCallback((event) => { //제출 전 오류 확인 함수 | ||
143 | + event.preventDefault(); //체크박스 미리 클릭 방지 | ||
144 | + | ||
145 | + if (checkCityAddError || CityAdd === "") { | ||
146 | + setCheckSubmitError(true); | ||
147 | + } | ||
148 | + else if (checkGuAddError || GuAdd === "") { | ||
149 | + setCheckSubmitError(true); | ||
150 | + } | ||
151 | + else if (checkDongAddError || DongAdd === "") { | ||
152 | + setCheckSubmitError(true); | ||
153 | + } | ||
154 | + else { | ||
155 | + setCheckSubmitError(false); | ||
156 | + } | ||
157 | + | ||
158 | + | ||
159 | + if (!checkSubmitError) { | ||
160 | + | ||
161 | + addressResult.then((result) => { | ||
162 | + for (let i = 0; i<result.length; i++) { | ||
163 | + | ||
164 | + if (result[i].address1 === CityAdd && result[i].address2 === GuAdd && result[i].address3 === DongAdd) { | ||
165 | + | ||
166 | + const dotData = { | ||
167 | + address1 : CityAdd, | ||
168 | + address2 : GuAdd, | ||
169 | + address3 : DongAdd, | ||
170 | + dotX : result[i].dotX, | ||
171 | + dotY : result[i].dotY, | ||
172 | + } | ||
173 | + | ||
174 | + dispatch(todayInformation(dotData)); | ||
175 | + dispatch(tommorrowInformation(dotData)); | ||
176 | + | ||
177 | + navigate('/weather'); | ||
178 | + break; | ||
179 | + } | ||
180 | + } | ||
181 | + }) | ||
182 | + } | ||
183 | + | ||
184 | + }, [checkCityAddError, checkDongAddError, checkGuAddError, checkSubmitError, Name, Sex, CityAdd, GuAdd, DongAdd]); | ||
185 | + | ||
186 | + return ( | ||
187 | + <> | ||
188 | + <dir id = "header"> | ||
189 | + <dir className="header_title" onClick = {onClickTitle}> | ||
190 | + <h1>Weather_Briefing</h1> | ||
191 | + </dir> | ||
192 | + <dir className="header_choice_box"> | ||
193 | + <button type="button" onClick = {onClickLogout}>Logout</button> | ||
194 | + <button type="button" onClick = {onClickRegister}>Register</button> | ||
195 | + </dir> | ||
196 | + </dir> | ||
197 | + | ||
198 | + <div id = "body"> | ||
199 | + <div className="info-box"> | ||
200 | + <p className="info">정보를 입력해주세요.</p> | ||
201 | + <div className="main-input-area" readOnly> | ||
202 | + <li>이름</li> | ||
203 | + <input | ||
204 | + placeholder={Name} | ||
205 | + type="text" | ||
206 | + value={Name} | ||
207 | + /> | ||
208 | + </div> | ||
209 | + <hr/> | ||
210 | + <div className="main-input-area" readOnly> | ||
211 | + <li>성별</li> | ||
212 | + <p>남자</p> | ||
213 | + <input | ||
214 | + type="radio" //라디오 버튼 타입 | ||
215 | + value = "0" | ||
216 | + checked = {Sex === "0"} | ||
217 | + /> | ||
218 | + <p>여자</p> | ||
219 | + <input | ||
220 | + type="radio" | ||
221 | + value = "1" | ||
222 | + checked = {Sex === "1"} | ||
223 | + /> | ||
224 | + </div> | ||
225 | + <hr/> | ||
226 | + <div className="main-input-area"> | ||
227 | + <li>지역</li> | ||
228 | + <div className="CityAddSelect"> | ||
229 | + <select onChange={onCityAddhandler} value={CityAdd}> | ||
230 | + {CityAddSelectList.map((item) => ( | ||
231 | + <option value={item} key={item}> | ||
232 | + {item} | ||
233 | + </option> | ||
234 | + ))} | ||
235 | + </select> | ||
236 | + </div> | ||
237 | + <div className="GuAddSelect"> | ||
238 | + <select onChange={onGuAddhandler} value={GuAdd}> | ||
239 | + {GuAddSelectList.map((item) => ( | ||
240 | + <option value={item} key={item}> | ||
241 | + {item} | ||
242 | + </option> | ||
243 | + ))} | ||
244 | + </select> | ||
245 | + </div> | ||
246 | + <div className="DongAddSelect"> | ||
247 | + <select onChange={onDongAddhandler} value={DongAdd}> | ||
248 | + {DongAddSelectList.map((item) => ( | ||
249 | + <option value={item} key={CityAdd+GuAdd+item}> | ||
250 | + {item} | ||
251 | + </option> | ||
252 | + ))} | ||
253 | + </select> | ||
254 | + </div> | ||
255 | + </div> | ||
256 | + <hr/> | ||
257 | + <div className="main-btn-area" onClick={onSubmitHandler}> | ||
258 | + <button className="submit-btn"> | ||
259 | + 날씨 정보 | ||
260 | + </button> | ||
261 | + </div> | ||
262 | + <div className="main-check-variable"> | ||
263 | + {checkSubmitError && <div style={{color : 'red'}}>정보를 제대로 입력해주세요.</div>} | ||
264 | + </div> | ||
265 | + </div> | ||
266 | + </div> | ||
267 | + </> | ||
268 | + ); | ||
269 | +} | ||
270 | + | ||
271 | +export default MainPage; | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | +import React, { useCallback, useEffect, useState } from "react"; | ||
2 | +import { useDispatch, useSelector } from "react-redux"; | ||
3 | +import { useNavigate } from "react-router-dom"; | ||
4 | +import { logout } from "../../../modules/user"; | ||
5 | +import "../style/RecommandPage.scss" | ||
6 | + | ||
7 | +function RecommandPage(props) { | ||
8 | + | ||
9 | + const clothesResult = useSelector((state) => state.clothes.clothesRecommend); | ||
10 | + | ||
11 | + const [IsRain, setIsRain] = useState(""); | ||
12 | + const [TopPath, setTopPath] = useState(''); | ||
13 | + const [BottomPath, setBottomPath] = useState(''); | ||
14 | + | ||
15 | + const dispatch = useDispatch(); | ||
16 | + | ||
17 | + useEffect(() => { | ||
18 | + clothesResult.then((result) => { | ||
19 | + | ||
20 | + if (result.umbrella == 1) { | ||
21 | + setIsRain("비 예보가 있습니다. 우산을 꼭 챙겨주세요!"); | ||
22 | + } | ||
23 | + else { | ||
24 | + setIsRain("비 예보가 없습니다!"); | ||
25 | + } | ||
26 | + | ||
27 | + setTopPath(result.top); | ||
28 | + setBottomPath(result.bottom); | ||
29 | + }) | ||
30 | + }, [clothesResult]) | ||
31 | + | ||
32 | + const navigate = useNavigate(); | ||
33 | + | ||
34 | + const onClickLogout = useCallback((event) => { | ||
35 | + dispatch(logout()); | ||
36 | + navigate('/login'); | ||
37 | + }) | ||
38 | + | ||
39 | + const onClickRegister = useCallback((event) => { | ||
40 | + navigate('/'); | ||
41 | + }) | ||
42 | + | ||
43 | + const onClickTitle = useCallback((event) => { | ||
44 | + navigate('/main') | ||
45 | + }) | ||
46 | + | ||
47 | + return ( | ||
48 | + <> | ||
49 | + <dir id = "header"> | ||
50 | + <dir className="header_title" onClick = {onClickTitle}> | ||
51 | + <h1>Weather_Briefing</h1> | ||
52 | + </dir> | ||
53 | + <dir className="header_choice_box"> | ||
54 | + <button type="button" onClick={onClickLogout}>Logout</button> | ||
55 | + <button type="button" onClick={onClickRegister}>Register</button> | ||
56 | + </dir> | ||
57 | + </dir> | ||
58 | + | ||
59 | + <div id = "recommand_body"> | ||
60 | + <dir className="fashion_recommand"> | ||
61 | + <dir className="rainOrnot">{IsRain}</dir> | ||
62 | + <dir className="clothes"> | ||
63 | + <dir className="Top"> | ||
64 | + <h1>TOP</h1> | ||
65 | + <img src={TopPath} className='Top_Image' /> | ||
66 | + </dir> | ||
67 | + <dir className="Bottom"> | ||
68 | + <h1>BOTTOM</h1> | ||
69 | + <img src={BottomPath} className='Bottom_Image' /> | ||
70 | + </dir> | ||
71 | + </dir> | ||
72 | + </dir> | ||
73 | + </div> | ||
74 | + </> | ||
75 | + ); | ||
76 | +}; | ||
77 | + | ||
78 | +export default RecommandPage; | ||
79 | + |
1 | +import React, { useCallback, useEffect, useState } from "react"; | ||
2 | +import { register } from "../../../modules/user.js"; | ||
3 | +import "../style/RegisterPage.scss"; | ||
4 | +import { useDispatch, useSelector } from "react-redux"; | ||
5 | +import { useNavigate } from "react-router-dom"; | ||
6 | + | ||
7 | +function RegisterPage(props) { | ||
8 | + const dispatch = useDispatch(); | ||
9 | + const navigate = useNavigate(); | ||
10 | + | ||
11 | + const registerResult = useSelector((state) => state.user.registerSuccess); | ||
12 | + | ||
13 | + const [Name, setName] = useState(""); | ||
14 | + const [Sex, setSex] = useState(""); | ||
15 | + const [Id, setId] = useState(""); | ||
16 | + const [Password, setPassword] = useState(""); | ||
17 | + const [PasswordCheck, setPasswordCheck] = useState(""); | ||
18 | + const [PasswordError, setPasswordError] = useState(false); | ||
19 | + | ||
20 | + const [checkRegister, setCheckRegister] = useState(false); | ||
21 | + const [checkNameError, setCheckNameError] = useState(false); | ||
22 | + const [checkSexError, setCheckSexError] = useState(true); | ||
23 | + const [checkIdError, setCheckIdError] = useState(false); | ||
24 | + const [checkPasswordError, setCheckPasswordError] = useState(false); | ||
25 | + const [checkRegisterError, setCheckRegisterError] = useState(false); | ||
26 | + | ||
27 | + const idRegex = /^(?=.*[a-zA-Z])(?=.*[0-9]).{6,14}$/; | ||
28 | + const passwordRegex = /^(?=.*[a-zA-Z])(?=.*[!@#$%^*+=-?])(?=.*[0-9]).{8,25}$/; | ||
29 | + | ||
30 | + useEffect(() => { | ||
31 | + if (checkRegister === true) { | ||
32 | + registerResult.then((result) => { | ||
33 | + if (result.registerSuccess === '1') { | ||
34 | + alert('회원 가입에 성공하였습니다.'); | ||
35 | + navigate('/login'); | ||
36 | + } | ||
37 | + else if (result.registerSuccess === '0') { | ||
38 | + alert('중복된 아이디가 존재합니다.'); | ||
39 | + } | ||
40 | + else { | ||
41 | + alert('회원 가입에 실패하였습니다.'); | ||
42 | + } | ||
43 | + }) | ||
44 | + } | ||
45 | + }, [registerResult]) | ||
46 | + | ||
47 | + const onIdHandler = useCallback((event) => { | ||
48 | + setId(event.currentTarget.value); | ||
49 | + | ||
50 | + // 아이디 유효성 검사 | ||
51 | + if (!idRegex.test(event.currentTarget.value)) { | ||
52 | + setCheckIdError(true); | ||
53 | + } | ||
54 | + else { | ||
55 | + setCheckIdError(false); | ||
56 | + } | ||
57 | + | ||
58 | + }, [checkIdError]); | ||
59 | + | ||
60 | + const onNameHandler = useCallback((event) => { | ||
61 | + setName(event.currentTarget.value); | ||
62 | + | ||
63 | + // 이름 유효성 검사 | ||
64 | + if (event.currentTarget.value.length < 2) { | ||
65 | + setCheckNameError(true); | ||
66 | + } | ||
67 | + else { | ||
68 | + setCheckNameError(false); | ||
69 | + } | ||
70 | + }, [checkNameError]); | ||
71 | + | ||
72 | + const onSexHandler = useCallback((event) => { | ||
73 | + setSex(event.currentTarget.value); | ||
74 | + setCheckSexError(false); | ||
75 | + }, [checkSexError]); | ||
76 | + | ||
77 | + const onPasswordHandler = useCallback((event) => { | ||
78 | + setPassword(event.currentTarget.value); | ||
79 | + | ||
80 | + // 비밀번호 유효성 검사 | ||
81 | + if (!passwordRegex.test(event.currentTarget.value)) { | ||
82 | + setCheckPasswordError(true); | ||
83 | + } | ||
84 | + else { | ||
85 | + setCheckPasswordError(false); | ||
86 | + } | ||
87 | + }, [checkPasswordError]); | ||
88 | + | ||
89 | + const onClickLogIn = useCallback((event) => { | ||
90 | + navigate('../login'); | ||
91 | + }) | ||
92 | + | ||
93 | + const onPasswordCheckHandler = useCallback((event) => { | ||
94 | + //비밀번호를 입력할때마다 password 를 검증하는 함수 | ||
95 | + setPasswordError(event.currentTarget.value !== Password); | ||
96 | + setPasswordCheck(event.currentTarget.value); | ||
97 | + }, [PasswordError]); | ||
98 | + | ||
99 | + const onSubmitHandler = useCallback((event) => { | ||
100 | + event.preventDefault(); | ||
101 | + | ||
102 | + if (checkIdError || Id === "") { | ||
103 | + setCheckRegisterError(true); | ||
104 | + } | ||
105 | + else if (checkNameError || Name === "") { | ||
106 | + setCheckRegisterError(true); | ||
107 | + } | ||
108 | + else if (checkSexError || Sex === "") { | ||
109 | + setCheckRegisterError(true); | ||
110 | + } | ||
111 | + else if (checkPasswordError || Password === "") { | ||
112 | + setCheckRegisterError(true); | ||
113 | + } | ||
114 | + else if (Password !== PasswordCheck) { | ||
115 | + setCheckRegisterError(true); | ||
116 | + } | ||
117 | + else { | ||
118 | + setCheckRegisterError(false); | ||
119 | + } | ||
120 | + | ||
121 | + if (!checkRegisterError) { | ||
122 | + const UserData = { | ||
123 | + name: Name, | ||
124 | + id: Id, | ||
125 | + password: Password, | ||
126 | + gender: Sex, | ||
127 | + }; | ||
128 | + | ||
129 | + // 액션생성함수 | ||
130 | + dispatch(register(UserData)); | ||
131 | + setCheckRegister(true); | ||
132 | + | ||
133 | + }; | ||
134 | + | ||
135 | + }, [checkIdError, checkNameError, checkPasswordError, checkRegisterError, checkSexError, Password, PasswordCheck, Sex, dispatch, registerResult, checkRegister]); | ||
136 | + | ||
137 | + return ( | ||
138 | + <> | ||
139 | + <div id="body"> | ||
140 | + <div className="register-box"> | ||
141 | + <h2>회원가입</h2> | ||
142 | + <div className="input-area"> | ||
143 | + <input | ||
144 | + placeholder="이름" | ||
145 | + type="text" | ||
146 | + value={Name} | ||
147 | + onChange={onNameHandler} | ||
148 | + /> | ||
149 | + </div> | ||
150 | + <div className="check-variable"> | ||
151 | + {checkNameError && <div style={{ color: 'red' }}>이름을 두글자 이상 입력해 주세요.</div>} | ||
152 | + </div> | ||
153 | + <div className="input-area"> | ||
154 | + <input | ||
155 | + placeholder="아이디" | ||
156 | + type="text" | ||
157 | + value={Id} | ||
158 | + onChange={onIdHandler} | ||
159 | + /> | ||
160 | + </div> | ||
161 | + <div className="check-variable"> | ||
162 | + {checkIdError && <div style={{ color: 'red' }}>아이디는 6자리 이상 14자리 이하 소문자와 숫자로 입력해주세요.</div>} | ||
163 | + </div> | ||
164 | + <div className="input-area"> | ||
165 | + <input | ||
166 | + placeholder="비밀번호" | ||
167 | + type="text" | ||
168 | + value={Password} | ||
169 | + onChange={onPasswordHandler} | ||
170 | + /> | ||
171 | + </div> | ||
172 | + <div className="check-variable"> | ||
173 | + {checkPasswordError && <div style={{ color: 'red' }}>알파벳과 숫자, 특수문자를 포함하여 8자리 이상 입력해주세요.</div>} | ||
174 | + </div> | ||
175 | + <div className="input-area"> | ||
176 | + <input | ||
177 | + placeholder="비밀번호 재입력" | ||
178 | + type="text" | ||
179 | + value={PasswordCheck} | ||
180 | + onChange={onPasswordCheckHandler} | ||
181 | + /> | ||
182 | + </div> | ||
183 | + <div className="check-variable"> | ||
184 | + {PasswordError && <div style={{ color: 'red' }}>비밀번호가 일치하지 않습니다.</div>} | ||
185 | + </div> | ||
186 | + <div className="input-area"> | ||
187 | + <input | ||
188 | + type="radio" | ||
189 | + value="0" | ||
190 | + checked={Sex === "0"} | ||
191 | + onChange={onSexHandler} | ||
192 | + />남 | ||
193 | + <input | ||
194 | + type="radio" | ||
195 | + value="1" | ||
196 | + checked={Sex === "1"} | ||
197 | + onChange={onSexHandler} | ||
198 | + />여 | ||
199 | + </div> | ||
200 | + <div className="btn-area" onClick={onSubmitHandler}> | ||
201 | + <button | ||
202 | + className="register-btn" | ||
203 | + > | ||
204 | + 가입하기 | ||
205 | + </button> | ||
206 | + </div> | ||
207 | + </div> | ||
208 | + {checkRegisterError && <div style={{ color: 'red' }}>정보를 제대로 입력해주세요.</div>} | ||
209 | + </div> | ||
210 | + </> | ||
211 | + ); | ||
212 | + | ||
213 | +} | ||
214 | + | ||
215 | +export default RegisterPage; | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | +import React, { useCallback, useEffect, useState } from "react"; | ||
2 | +import { useDispatch, useSelector } from "react-redux"; | ||
3 | +import { useNavigate } from "react-router-dom"; | ||
4 | +import { recommend } from "../../../modules/clothes"; | ||
5 | +import { logout } from "../../../modules/user"; | ||
6 | +import "../style/WeatherPage.scss" | ||
7 | + | ||
8 | +function WeatherPage(props) { | ||
9 | + const dispatch = useDispatch(); | ||
10 | + const navigate = useNavigate(); | ||
11 | + const user = useSelector((state) => state.user.loginData); | ||
12 | + const todayWeatherResult = useSelector((state) => state.weather.todayInformation); | ||
13 | + const tommorrowWeatherResult = useSelector((state) => state.weather.tommorrowInformation); | ||
14 | + const today = new Date(); | ||
15 | + const detailWeather = []; | ||
16 | + let currentHour; | ||
17 | + | ||
18 | + const today_year = today.getFullYear(); | ||
19 | + const today_month = today.getMonth(); | ||
20 | + const today_date = today.getDate(); | ||
21 | + const [todayHighTemperature, setTodayHighTemperature] = useState(-100); | ||
22 | + const [todayLowTemperature, setTodayLowTemperature] = useState(100); | ||
23 | + const [todayWeatherSymbol, setTodayWeatherSymbol] = useState('☀️'); | ||
24 | + const [nowWeatherSymbol, setNowWeatherSymbol] = useState(''); | ||
25 | + const [nowTemperature, setNowTemperature] = useState(""); | ||
26 | + const [tommorrowHighTemperature, setTommorrowHighTemperature] = useState(-100); | ||
27 | + const [tommorrowLowTemperature, setTommorrowLowTemperature] = useState(100); | ||
28 | + const [tommorrowWeatherSymbol, setTommorrowWeatherSymbol] = useState(''); | ||
29 | + | ||
30 | + const [cityAdd, setCityAdd] = useState(''); | ||
31 | + const [guAdd, setGuAdd] = useState(''); | ||
32 | + const [dongAdd, setDongAdd] = useState(''); | ||
33 | + const [Time, setTime] = useState("00:00:00"); | ||
34 | + | ||
35 | + let todayWeatherLevel = 0; | ||
36 | + let userGender; | ||
37 | + | ||
38 | + const currentTime = () => { | ||
39 | + const date = new Date(); | ||
40 | + const hours = String(date.getHours()).padStart(2, "0"); | ||
41 | + const minutes = String(date.getMinutes()).padStart(2, "0"); | ||
42 | + const seconds = String(date.getSeconds()).padStart(2, "0"); | ||
43 | + setTime(hours+" : "+minutes+" : "+seconds); | ||
44 | + } | ||
45 | + | ||
46 | + const startTimer = () => { | ||
47 | + setInterval(currentTime, 1000) | ||
48 | + } | ||
49 | + | ||
50 | + startTimer() | ||
51 | + | ||
52 | + useEffect(() => { | ||
53 | + todayWeatherResult.then((result) => { | ||
54 | + let highTemperature = -100; | ||
55 | + let lowTemperature = 100; | ||
56 | + let symbol = ''; | ||
57 | + | ||
58 | + currentHour = Time[0] + Time[1]; | ||
59 | + | ||
60 | + // 주소 설정 | ||
61 | + setCityAdd(result[24].address1); | ||
62 | + setGuAdd(result[24].address2); | ||
63 | + setDongAdd(result[24].address3); | ||
64 | + | ||
65 | + for (let i = 0; i<24; i++) { | ||
66 | + if (i === 13) { | ||
67 | + if (result[i].weather === 0) { | ||
68 | + todayWeatherLevel = 0; | ||
69 | + } | ||
70 | + else if (result[i].weather === 1) { | ||
71 | + todayWeatherLevel = 1; | ||
72 | + } | ||
73 | + else if (result[i].weather === 2) { | ||
74 | + todayWeatherLevel = 2; | ||
75 | + } | ||
76 | + else if (result[i].weather === 3) { | ||
77 | + todayWeatherLevel = 3; | ||
78 | + } | ||
79 | + else if (result[i].weather === 4) { | ||
80 | + todayWeatherLevel = 4; | ||
81 | + } | ||
82 | + | ||
83 | + } | ||
84 | + // 세부 시간 정보 | ||
85 | + if (i > Number(currentHour)) { | ||
86 | + if (result[i].rainPer >= 50) { | ||
87 | + symbol = '🌧️'; | ||
88 | + setTodayWeatherSymbol('🌧️'); | ||
89 | + } | ||
90 | + else if (i > 18 || i < 6) { | ||
91 | + symbol = '🌙'; | ||
92 | + } | ||
93 | + else { | ||
94 | + symbol = '☀️'; | ||
95 | + } | ||
96 | + const tempData = { | ||
97 | + time : result[i].time, | ||
98 | + temperature : result[i].temperature, | ||
99 | + symbol : symbol, | ||
100 | + } | ||
101 | + detailWeather.push(tempData); | ||
102 | + } | ||
103 | + // 현재 시간 정보 다루는 부분 | ||
104 | + if (i === Number(currentHour)) { | ||
105 | + if (result[i].rainPer >= 50) { | ||
106 | + setNowWeatherSymbol('🌧️'); | ||
107 | + } | ||
108 | + else if (i >= 18 || i < 6) { | ||
109 | + setNowWeatherSymbol('🌙'); | ||
110 | + } | ||
111 | + else { | ||
112 | + setNowWeatherSymbol('☀️'); | ||
113 | + } | ||
114 | + | ||
115 | + setNowTemperature(result[i].temperature); | ||
116 | + } | ||
117 | + // 하루 온도 정보 다루는 부분 | ||
118 | + if (result[i].temperature < lowTemperature) { | ||
119 | + lowTemperature = result[i].temperature; | ||
120 | + } | ||
121 | + if (result[i].temperature > highTemperature) { | ||
122 | + highTemperature = result[i].temperature; | ||
123 | + } | ||
124 | + } | ||
125 | + | ||
126 | + setTodayHighTemperature(highTemperature); | ||
127 | + setTodayLowTemperature(lowTemperature); | ||
128 | + }) | ||
129 | + }, [todayWeatherResult, Time]) | ||
130 | + | ||
131 | + // 내일의 날씨 | ||
132 | + useEffect(() => { | ||
133 | + tommorrowWeatherResult.then((result) => { | ||
134 | + | ||
135 | + let highTemperature = -100; | ||
136 | + let lowTemperature = 100; | ||
137 | + let symbol = '☀️'; | ||
138 | + | ||
139 | + for (let i = 0; i < 24; i++) { | ||
140 | + // symbol 설정 | ||
141 | + if (result[i].rainPer >= 50) { | ||
142 | + symbol = '🌧️'; | ||
143 | + } | ||
144 | + // 내일 온도 정보 다루는 부분 | ||
145 | + if (result[i].temperature < lowTemperature) { | ||
146 | + lowTemperature = result[i].temperature; | ||
147 | + } | ||
148 | + if (result[i].temperature > highTemperature) { | ||
149 | + highTemperature = result[i].temperature; | ||
150 | + } | ||
151 | + setTommorrowHighTemperature(highTemperature); | ||
152 | + setTommorrowLowTemperature(lowTemperature); | ||
153 | + setTommorrowWeatherSymbol(symbol); | ||
154 | + } | ||
155 | + }) | ||
156 | + }, [tommorrowWeatherResult]) | ||
157 | + | ||
158 | + // 유저 성별 정보 | ||
159 | + useEffect(() => { | ||
160 | + | ||
161 | + user.then((result) => { | ||
162 | + | ||
163 | + if (result.logData.gender === '0') { | ||
164 | + userGender = 0; | ||
165 | + } | ||
166 | + else { | ||
167 | + userGender = 1; | ||
168 | + } | ||
169 | + | ||
170 | + }); | ||
171 | + }, [user]) | ||
172 | + | ||
173 | + const onClickLogout = useCallback((event) => { | ||
174 | + dispatch(logout()); | ||
175 | + navigate('/login'); | ||
176 | + }) | ||
177 | + | ||
178 | + const onClickRegister = useCallback((event) => { | ||
179 | + navigate('/'); | ||
180 | + }) | ||
181 | + | ||
182 | + const onClickTitle = useCallback((event) => { | ||
183 | + navigate('/main') | ||
184 | + }) | ||
185 | + | ||
186 | + const onSubmitHandler = useCallback((event) => { | ||
187 | + event.preventDefault(); //체크박스 미리 클릭 방지 | ||
188 | + | ||
189 | + let isRain = 0; | ||
190 | + | ||
191 | + if (todayWeatherSymbol === '🌧️') { | ||
192 | + isRain = 1; | ||
193 | + } | ||
194 | + | ||
195 | + const sendData = { | ||
196 | + gender : userGender, | ||
197 | + weather : todayWeatherLevel, | ||
198 | + rain : isRain | ||
199 | + } | ||
200 | + | ||
201 | + dispatch(recommend(sendData)); | ||
202 | + navigate('/recommand'); | ||
203 | + | ||
204 | + }, [todayWeatherResult, user]); | ||
205 | + | ||
206 | + return ( | ||
207 | + <> | ||
208 | + <dir id = "header"> | ||
209 | + <dir className="header_title" onClick = {onClickTitle}> | ||
210 | + <h1>Weather_Briefing</h1> | ||
211 | + </dir> | ||
212 | + <dir className="header_choice_box"> | ||
213 | + <button type="button" onClick = {onClickLogout}>Logout</button> | ||
214 | + <button type="button" onClick = {onClickRegister}>Register</button> | ||
215 | + </dir> | ||
216 | + </dir> | ||
217 | + <div id = "body"> | ||
218 | + <div className="address"> | ||
219 | + <p>{cityAdd} {guAdd} {dongAdd}</p> | ||
220 | + </div> | ||
221 | + <div className="today_weather"> | ||
222 | + <div className="days"> | ||
223 | + <h1>오늘의 날씨</h1> | ||
224 | + <h2 id="day">{today_year}년 {today_month + 1}월 {today_date}일</h2> | ||
225 | + </div> | ||
226 | + <div className="today_now_weather_info"> | ||
227 | + <h2>현재 온도</h2> | ||
228 | + <h1 id="present_do">{nowWeatherSymbol} {nowTemperature}도</h1> | ||
229 | + </div> | ||
230 | + <div className="today_weather_info"> | ||
231 | + <h2>전체 날씨</h2> | ||
232 | + <div className="today_whole_weather"> | ||
233 | + <h1>{todayWeatherSymbol}</h1> | ||
234 | + <div className="today_whole_weather_temperature"> | ||
235 | + <p>최고: {todayHighTemperature}도</p> | ||
236 | + <p>최저: {todayLowTemperature}도</p> | ||
237 | + </div> | ||
238 | + </div> | ||
239 | + </div> | ||
240 | + </div> | ||
241 | + <div className="tommorrow_weather"> | ||
242 | + <div className="days"> | ||
243 | + <h1>내일의 날씨</h1> | ||
244 | + <h2 id="day">{today_year}년 {today_month + 1}월 {today_date+1}일</h2> | ||
245 | + </div> | ||
246 | + <div className="tommorrow_weather_info"> | ||
247 | + <h2>날씨 정보</h2> | ||
248 | + <div className="tommorrow_whole_weather"> | ||
249 | + <h1>{tommorrowWeatherSymbol}</h1> | ||
250 | + <div className="tommorrow_temperator"> | ||
251 | + <p>최고: {tommorrowHighTemperature}도</p> | ||
252 | + <p>최저: {tommorrowLowTemperature}도</p> | ||
253 | + </div> | ||
254 | + </div> | ||
255 | + | ||
256 | + </div> | ||
257 | + </div> | ||
258 | + <div className="weather-btn-area" onClick={onSubmitHandler}> | ||
259 | + <button className="submit-btn"> | ||
260 | + 옷 추천 | ||
261 | + </button> | ||
262 | + </div> | ||
263 | + </div> | ||
264 | + </> | ||
265 | + ); | ||
266 | +} | ||
267 | +export default WeatherPage; | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | +* { | ||
2 | + margin: 0; | ||
3 | + padding: 0; | ||
4 | + box-sizing: border-box; | ||
5 | + background-color: rgb(245, 235, 223); | ||
6 | +} | ||
7 | +#body { | ||
8 | + display: flex; | ||
9 | + justify-content: center; | ||
10 | + align-items: center; | ||
11 | + border-top: 2px solid; | ||
12 | + border-bottom: 2px solid; | ||
13 | + | ||
14 | + .login-box { | ||
15 | + border: 2px solid; | ||
16 | + width: 35%; | ||
17 | + height: 60%; | ||
18 | + margin-top: 30px; | ||
19 | + margin-bottom: 30px; | ||
20 | + h2 { | ||
21 | + text-align: center; | ||
22 | + margin-top: 20px; | ||
23 | + margin-bottom: 20px; | ||
24 | + } | ||
25 | + } | ||
26 | + .input-area { | ||
27 | + display: flex; | ||
28 | + justify-content: center; | ||
29 | + align-items: center; | ||
30 | + margin-bottom: 5px; | ||
31 | + | ||
32 | + input { | ||
33 | + padding: 10px 0.1rem; | ||
34 | + background-color: rgb(255, 255, 255); | ||
35 | + } | ||
36 | + } | ||
37 | + .check-variable { | ||
38 | + display: flex; | ||
39 | + justify-content: center; | ||
40 | + align-items: center; | ||
41 | + margin-bottom: 5px; | ||
42 | + } | ||
43 | + .btn-area { | ||
44 | + display: flex; | ||
45 | + justify-content: center; | ||
46 | + margin-top: 30px; | ||
47 | + margin-bottom: 35px; | ||
48 | + | ||
49 | + button { | ||
50 | + width: 120px; | ||
51 | + height: 40px; | ||
52 | + font-size: large; | ||
53 | + font-weight: bold; | ||
54 | + background-color:rgb(255, 253, 238); | ||
55 | + cursor: pointer; | ||
56 | + } | ||
57 | + } | ||
58 | +} |
1 | +* { | ||
2 | + margin: 0; | ||
3 | + padding: 0; | ||
4 | + box-sizing: border-box; | ||
5 | + background-color: rgb(245, 235, 223); | ||
6 | + } | ||
7 | + #header { | ||
8 | + display: flex; | ||
9 | + position: fixed; | ||
10 | + justify-content: center; | ||
11 | + align-items: center; | ||
12 | + height: 15%; | ||
13 | + width: 100%; | ||
14 | + border-top: 2px solid; | ||
15 | + border-bottom: 2px solid; | ||
16 | + | ||
17 | + .header_clock { | ||
18 | + justify-content: left; | ||
19 | + align-items: left; | ||
20 | + width: 10%; | ||
21 | + height: 10%; | ||
22 | + h1{ | ||
23 | + color:rgb(0, 0, 0); | ||
24 | + font-size: 15px; | ||
25 | + } | ||
26 | + } | ||
27 | + | ||
28 | + .header_title { | ||
29 | + display: flex; | ||
30 | + justify-content: center; | ||
31 | + align-items: center; | ||
32 | + margin-left: 300px; | ||
33 | + margin-right: 300px; | ||
34 | + h1 { | ||
35 | + font-size: 50px; | ||
36 | + font-family: 'Times New Roman', Times, serif; | ||
37 | + color: rgb(0, 0, 0); | ||
38 | + } | ||
39 | + } | ||
40 | + .header_choice_box { | ||
41 | + display: flex; | ||
42 | + justify-content: right; | ||
43 | + align-items: right; | ||
44 | + margin-right: 10x; | ||
45 | + } | ||
46 | + button { | ||
47 | + width: 70px; | ||
48 | + height: 25px; | ||
49 | + font-size: 15px; | ||
50 | + font-weight: bold; | ||
51 | + cursor: pointer; | ||
52 | + } | ||
53 | + } | ||
54 | + | ||
55 | + #body { | ||
56 | + display: flex; | ||
57 | + justify-content: center; | ||
58 | + align-items: center; | ||
59 | + border-top: 2px solid; | ||
60 | + border-bottom: 2px solid; | ||
61 | + | ||
62 | + .info-box { | ||
63 | + border: 2px solid; | ||
64 | + width: 55%; | ||
65 | + height: 100%; | ||
66 | + margin-top: 150px; | ||
67 | + margin-bottom: 30px; | ||
68 | + } | ||
69 | + hr { | ||
70 | + display: flex; | ||
71 | + justify-content: center; | ||
72 | + align-items: center; | ||
73 | + margin-top: 20px; | ||
74 | + margin-left: 100px; | ||
75 | + margin-right: 100px; | ||
76 | + } | ||
77 | + .info{ | ||
78 | + display:flex; | ||
79 | + font-size: 30px; | ||
80 | + border: 2px solid rgb(225, 208, 134); | ||
81 | + background-color: rgb(242, 235, 130); | ||
82 | + color:rgb(255, 255, 255); | ||
83 | + justify-content: center; | ||
84 | + align-items: center; | ||
85 | + margin-top: 50px; | ||
86 | + margin-bottom: 50px; | ||
87 | + margin-left: 30%; | ||
88 | + margin-right: 30%; | ||
89 | + } | ||
90 | + .main-input-area { | ||
91 | + display: flex; | ||
92 | + justify-content: left; | ||
93 | + align-items: left; | ||
94 | + margin-top: 20px; | ||
95 | + margin-bottom: 15px; | ||
96 | + li{ | ||
97 | + display:flex; | ||
98 | + font-size: 15px; | ||
99 | + color: gray; | ||
100 | + margin-left: 15%; | ||
101 | + margin-right: 10%; | ||
102 | + } | ||
103 | + p{ | ||
104 | + display:flex; | ||
105 | + font-size: 15px; | ||
106 | + border: 2px dotted gray; | ||
107 | + margin-bottom: 5px; | ||
108 | + margin-left: 5%; | ||
109 | + } | ||
110 | + input { | ||
111 | + padding: 10px 2rem; | ||
112 | + background-color: rgb(255, 255, 255); | ||
113 | + margin-left: 50px; | ||
114 | + } | ||
115 | + | ||
116 | + select { | ||
117 | + padding: 10px 1.5rem; | ||
118 | + margin-right: 5px; | ||
119 | + background-color: rgb(255, 255, 255); | ||
120 | + } | ||
121 | + } | ||
122 | + .main-check-variable { | ||
123 | + display: flex; | ||
124 | + justify-content: center; | ||
125 | + align-items: center; | ||
126 | + margin-bottom: 5px; | ||
127 | + } | ||
128 | + .main-btn-area { | ||
129 | + display: flex; | ||
130 | + justify-content: center; | ||
131 | + margin-top: 60px; | ||
132 | + margin-bottom: 10px; | ||
133 | + | ||
134 | + button { | ||
135 | + width: 150px; | ||
136 | + height: 60px; | ||
137 | + font-size: 15px; | ||
138 | + font-weight: bold; | ||
139 | + background-color:rgb(255, 253, 238); | ||
140 | + cursor: pointer; | ||
141 | + } | ||
142 | + } | ||
143 | + } | ||
144 | + | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | +* { | ||
2 | + margin: 0; | ||
3 | + padding: 0; | ||
4 | + box-sizing: border-box; | ||
5 | + background-color: rgb(245, 235, 223); | ||
6 | + } | ||
7 | + img { | ||
8 | + width: 300px; | ||
9 | + height: 300px; | ||
10 | + object-fit: cover; | ||
11 | + } | ||
12 | + | ||
13 | + #header { | ||
14 | + display: flex; | ||
15 | + position: fixed; | ||
16 | + justify-content: center; | ||
17 | + align-items: center; | ||
18 | + height: 15%; | ||
19 | + width: 100%; | ||
20 | + border-top: 2px solid; | ||
21 | + border-bottom: 2px solid; | ||
22 | + | ||
23 | + .header_title { | ||
24 | + display: flex; | ||
25 | + justify-content: center; | ||
26 | + align-items: center; | ||
27 | + margin-left: 300px; | ||
28 | + margin-right: 300px; | ||
29 | + h1 { | ||
30 | + font-size: 50px; | ||
31 | + font-family: 'Times New Roman', Times, serif; | ||
32 | + color: rgb(0, 0, 0); | ||
33 | + } | ||
34 | + } | ||
35 | + .header_choice_box { | ||
36 | + display: flex; | ||
37 | + justify-content: right; | ||
38 | + align-items: right; | ||
39 | + margin-right: 10x; | ||
40 | + } | ||
41 | + button { | ||
42 | + width: 70px; | ||
43 | + height: 25px; | ||
44 | + font-size: 15px; | ||
45 | + font-weight: bold; | ||
46 | + cursor: pointer; | ||
47 | + } | ||
48 | + } | ||
49 | + | ||
50 | + #recommand_body { | ||
51 | + display: flex; | ||
52 | + justify-content: center; | ||
53 | + align-items: center; | ||
54 | + border-top: 2px solid; | ||
55 | + border-bottom: 2px solid; | ||
56 | + | ||
57 | + .fashion_recommand { | ||
58 | + border: 2px solid; | ||
59 | + width: 50%; | ||
60 | + height: 200%; | ||
61 | + margin-top: 150px; | ||
62 | + margin-bottom: 30px; | ||
63 | + | ||
64 | + .rainOrnot { | ||
65 | + display: flex; | ||
66 | + justify-content: center; | ||
67 | + align-items: center; | ||
68 | + margin-top: 20px; | ||
69 | + margin-left: 100px; | ||
70 | + margin-right: 100px; | ||
71 | + font-size :30px; | ||
72 | + font-weight: bold; | ||
73 | + } | ||
74 | + .clothes{ | ||
75 | + display:flex; | ||
76 | + justify-content: space-between; | ||
77 | + align-items: space-between; | ||
78 | + | ||
79 | + .Top{ | ||
80 | + display:flex; | ||
81 | + flex-wrap: wrap; | ||
82 | + flex-direction: column; | ||
83 | + font-size: 30px; | ||
84 | + border: 2px solid; | ||
85 | + color:rgb(0, 0, 0); | ||
86 | + justify-content: center; | ||
87 | + align-items: center; | ||
88 | + margin-top: 50px; | ||
89 | + margin-bottom: 50px; | ||
90 | + margin-left: 5%; | ||
91 | + margin-right: 1%; | ||
92 | + } | ||
93 | + | ||
94 | + .Bottom{ | ||
95 | + display:flex; | ||
96 | + flex-wrap: wrap; | ||
97 | + flex-direction: column; | ||
98 | + font-size: 30px; | ||
99 | + border: 2px solid; | ||
100 | + color:rgb(0, 0, 0); | ||
101 | + justify-content: center; | ||
102 | + align-items: center; | ||
103 | + margin-top: 50px; | ||
104 | + margin-bottom: 50px; | ||
105 | + margin-left: 1%; | ||
106 | + margin-right: 5%; | ||
107 | + } | ||
108 | + | ||
109 | + .Head{ | ||
110 | + display:flex; | ||
111 | + flex-wrap: wrap; | ||
112 | + flex-direction: column; | ||
113 | + font-size: 30px; | ||
114 | + border: 2px solid; | ||
115 | + color:rgb(0, 0, 0); | ||
116 | + justify-content: center; | ||
117 | + align-items: center; | ||
118 | + margin-top: 50px; | ||
119 | + margin-bottom: 50px; | ||
120 | + margin-left: 1%; | ||
121 | + margin-right: 1%; | ||
122 | + } | ||
123 | + .Shoes{ | ||
124 | + display:flex; | ||
125 | + flex-wrap: wrap; | ||
126 | + flex-direction: column; | ||
127 | + font-size: 30px; | ||
128 | + border: 2px solid; | ||
129 | + color:rgb(0, 0, 0); | ||
130 | + justify-content: center; | ||
131 | + align-items: center; | ||
132 | + margin-top: 50px; | ||
133 | + margin-bottom: 50px; | ||
134 | + margin-left: 1%; | ||
135 | + margin-right: 1%; | ||
136 | + } | ||
137 | + } | ||
138 | + } | ||
139 | +} | ||
140 | + | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | +* { | ||
2 | + margin: 0; | ||
3 | + padding: 0; | ||
4 | + box-sizing: border-box; | ||
5 | + background-color: rgb(245, 235, 223); | ||
6 | +} | ||
7 | + | ||
8 | +#body { | ||
9 | + display: flex; | ||
10 | + justify-content: center; | ||
11 | + align-items: center; | ||
12 | + border-top: 2px solid; | ||
13 | + border-bottom: 2px solid; | ||
14 | + | ||
15 | + .register-box { | ||
16 | + border: 2px solid; | ||
17 | + width: 35%; | ||
18 | + height: 60%; | ||
19 | + margin-top: 30px; | ||
20 | + margin-bottom: 30px; | ||
21 | + h2 { | ||
22 | + text-align: center; | ||
23 | + margin-top: 20px; | ||
24 | + margin-bottom: 20px; | ||
25 | + } | ||
26 | + } | ||
27 | + .input-area { | ||
28 | + display: flex; | ||
29 | + justify-content: center; | ||
30 | + align-items: center; | ||
31 | + margin-bottom: 5px; | ||
32 | + | ||
33 | + input { | ||
34 | + padding: 10px 0.1rem; | ||
35 | + background-color: rgb(255, 255, 255); | ||
36 | + } | ||
37 | + } | ||
38 | + .check-variable { | ||
39 | + display: flex; | ||
40 | + justify-content: center; | ||
41 | + align-items: center; | ||
42 | + margin-bottom: 5px; | ||
43 | + } | ||
44 | + .btn-area { | ||
45 | + display: flex; | ||
46 | + justify-content: center; | ||
47 | + margin-top: 30px; | ||
48 | + margin-bottom: 35px; | ||
49 | + | ||
50 | + button { | ||
51 | + width: 120px; | ||
52 | + height: 40px; | ||
53 | + font-size: large; | ||
54 | + font-weight: bold; | ||
55 | + background-color:rgb(255, 253, 238); | ||
56 | + cursor: pointer; | ||
57 | + } | ||
58 | + } | ||
59 | +} |
1 | +#header { | ||
2 | + display: flex; | ||
3 | + position: fixed; | ||
4 | + justify-content: center; | ||
5 | + align-items: center; | ||
6 | + height: 15%; | ||
7 | + width: 100%; | ||
8 | + border-top: 2px solid; | ||
9 | + border-bottom: 2px solid; | ||
10 | + | ||
11 | + .header_title { | ||
12 | + display: flex; | ||
13 | + justify-content: center; | ||
14 | + align-items: center; | ||
15 | + margin-left: 300px; | ||
16 | + margin-right: 300px; | ||
17 | + cursor:pointer; | ||
18 | + h1 { | ||
19 | + font-size: 50px; | ||
20 | + font-family: 'Times New Roman', Times, serif; | ||
21 | + color: rgb(0, 0, 0); | ||
22 | + } | ||
23 | + } | ||
24 | + .header_choice_box { | ||
25 | + display: flex; | ||
26 | + justify-content: right; | ||
27 | + align-items: right; | ||
28 | + margin-right: 10x; | ||
29 | + } | ||
30 | + button { | ||
31 | + width: 70px; | ||
32 | + height: 25px; | ||
33 | + font-size: 15px; | ||
34 | + font-weight: bold; | ||
35 | + cursor: pointer; | ||
36 | + } | ||
37 | + } | ||
38 | +#body { | ||
39 | + display: flex; | ||
40 | + justify-content: center; | ||
41 | + align-items: center; | ||
42 | + flex-wrap: wrap; | ||
43 | + flex-direction: column; | ||
44 | + border-top: 2px solid; | ||
45 | + border-bottom: 2px solid; | ||
46 | + .address { | ||
47 | + display: flex; | ||
48 | + justify-content: center; | ||
49 | + align-items: center; | ||
50 | + margin-top: 150px; | ||
51 | + font-size: 30px; | ||
52 | + } | ||
53 | + .today_weather { | ||
54 | + display: flex; | ||
55 | + justify-content: center; | ||
56 | + align-items: center; | ||
57 | + border: 2px solid; | ||
58 | + width: 50%; | ||
59 | + margin-top: 30px; | ||
60 | + margin-bottom: 10px; | ||
61 | + .today_now_weather_info { | ||
62 | + display: flex; | ||
63 | + justify-content: center; | ||
64 | + align-items: center; | ||
65 | + flex-direction: column; | ||
66 | + margin-right: 30px; | ||
67 | + } | ||
68 | + .days { | ||
69 | + display: flex; | ||
70 | + justify-content: center; | ||
71 | + align-items: center; | ||
72 | + flex-wrap: wrap; | ||
73 | + flex-direction: column; | ||
74 | + margin-top: 25px; | ||
75 | + margin-bottom: 25px; | ||
76 | + margin-left: 15px; | ||
77 | + margin-right: 200px; | ||
78 | + } | ||
79 | + .today_whole_weather{ | ||
80 | + display: flex; | ||
81 | + flex-direction: row; | ||
82 | + } | ||
83 | + } | ||
84 | + | ||
85 | + .tommorrow_weather { | ||
86 | + display: flex; | ||
87 | + justify-content: center; | ||
88 | + align-items: center; | ||
89 | + border: 2px solid; | ||
90 | + width: 50%; | ||
91 | + margin-top: 20px; | ||
92 | + margin-bottom: 20px; | ||
93 | + .days { | ||
94 | + display: flex; | ||
95 | + justify-content: center; | ||
96 | + align-items: center; | ||
97 | + flex-wrap: wrap; | ||
98 | + flex-direction: column; | ||
99 | + margin-top: 25px; | ||
100 | + margin-bottom: 25px; | ||
101 | + margin-left: 15px; | ||
102 | + margin-right: 200px; | ||
103 | + } | ||
104 | + .tommorrow_weather_info { | ||
105 | + display: flex; | ||
106 | + justify-content: center; | ||
107 | + align-items: center; | ||
108 | + flex-direction: column; | ||
109 | + margin-right: 30px; | ||
110 | + .tommorrow_whole_weather{ | ||
111 | + display: flex; | ||
112 | + flex-direction: row; | ||
113 | + } | ||
114 | + } | ||
115 | + } | ||
116 | + .weather-btn-area { | ||
117 | + display: flex; | ||
118 | + justify-content: center; | ||
119 | + margin-top: 20px; | ||
120 | + margin-bottom: 10px; | ||
121 | + | ||
122 | + button { | ||
123 | + width: 150px; | ||
124 | + height: 60px; | ||
125 | + font-size: 15px; | ||
126 | + font-weight: bold; | ||
127 | + background-color:rgb(255, 253, 238); | ||
128 | + cursor: pointer; | ||
129 | + } | ||
130 | + } | ||
131 | + } | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
... | @@ -2,13 +2,23 @@ import React from 'react'; | ... | @@ -2,13 +2,23 @@ import React from 'react'; |
2 | import ReactDOM from 'react-dom/client'; | 2 | import ReactDOM from 'react-dom/client'; |
3 | import './index.css'; | 3 | import './index.css'; |
4 | import App from './App'; | 4 | import App from './App'; |
5 | +import { Provider } from 'react-redux'; | ||
6 | +import { applyMiddleware, createStore } from 'redux'; | ||
5 | import reportWebVitals from './reportWebVitals'; | 7 | import reportWebVitals from './reportWebVitals'; |
8 | +import { BrowserRouter } from 'react-router-dom'; | ||
9 | +import rootReducer from './modules/Index'; | ||
10 | +import { composeWithDevTools } from 'redux-devtools-extension'; | ||
11 | +import ReduxThunk from 'redux-thunk'; | ||
12 | + | ||
13 | +const store = createStore(rootReducer, composeWithDevTools(applyMiddleware(ReduxThunk))); | ||
6 | 14 | ||
7 | const root = ReactDOM.createRoot(document.getElementById('root')); | 15 | const root = ReactDOM.createRoot(document.getElementById('root')); |
8 | root.render( | 16 | root.render( |
9 | - <React.StrictMode> | 17 | + <Provider store={store}> |
18 | + <BrowserRouter> | ||
10 | <App /> | 19 | <App /> |
11 | - </React.StrictMode> | 20 | + </BrowserRouter> |
21 | + </Provider>, | ||
12 | ); | 22 | ); |
13 | 23 | ||
14 | // If you want to start measuring performance in your app, pass a function | 24 | // If you want to start measuring performance in your app, pass a function | ... | ... |
weather_briefing/src/modules/Index.js
0 → 100644
1 | +import { combineReducers } from "redux"; | ||
2 | +import user from "./user.js"; | ||
3 | +import weather from "./weather"; | ||
4 | +import clothes from "./clothes"; | ||
5 | + | ||
6 | +const rootReducer = combineReducers({ | ||
7 | + user, | ||
8 | + weather, | ||
9 | + clothes, | ||
10 | +}) | ||
11 | + | ||
12 | +export default rootReducer; | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
weather_briefing/src/modules/clothes.js
0 → 100644
1 | +import axios from "axios"; | ||
2 | + | ||
3 | +const CLOTHES_RECOMMEND = 'weather/RECOMMEND'; | ||
4 | + | ||
5 | +export function recommend(dataToSubmit) { | ||
6 | + const req = axios.post('http://localhost:4000/api/clothes', dataToSubmit) | ||
7 | + .then(res => res.data); | ||
8 | + | ||
9 | + return { | ||
10 | + type: CLOTHES_RECOMMEND, | ||
11 | + payload: req, | ||
12 | + } | ||
13 | +} | ||
14 | + | ||
15 | +export default function (state = {}, action) { | ||
16 | + switch (action.type) { | ||
17 | + case CLOTHES_RECOMMEND: | ||
18 | + return { ...state, clothesRecommend: action.payload }; | ||
19 | + break; | ||
20 | + default: | ||
21 | + return state; | ||
22 | + } | ||
23 | +} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
weather_briefing/src/modules/user.js
0 → 100644
1 | +import axios from 'axios'; | ||
2 | + | ||
3 | +const USER_REGISTER = 'user/REGISTER'; | ||
4 | +const USER_LOGIN = 'user/LOGIN'; | ||
5 | +const USER_LOGOUT = 'user/LOGOUT'; | ||
6 | + | ||
7 | +export function register (dataToSubmit) { | ||
8 | + | ||
9 | + const req = axios.post('http://localhost:4000/api/register', dataToSubmit) | ||
10 | + .then(res => res.data); | ||
11 | + | ||
12 | + return { | ||
13 | + type: USER_REGISTER, | ||
14 | + payload: req, | ||
15 | + } | ||
16 | +}; | ||
17 | + | ||
18 | +export function login(dataToSubmit) { | ||
19 | + const req = axios.post('http://localhost:4000/api/login', dataToSubmit) | ||
20 | + .then(res => res.data); | ||
21 | + | ||
22 | + return { | ||
23 | + type: USER_LOGIN, | ||
24 | + payload: req, | ||
25 | + } | ||
26 | +}; | ||
27 | + | ||
28 | +export function logout(dataToSubmit) { | ||
29 | + const req = axios.post('http://localhost:4000/api/logout', dataToSubmit) | ||
30 | + .then(res => res.data); | ||
31 | + | ||
32 | + return { | ||
33 | + type: USER_LOGOUT, | ||
34 | + } | ||
35 | + } | ||
36 | + | ||
37 | +export default function (state = {}, action) { | ||
38 | + switch (action.type) { | ||
39 | + case USER_REGISTER: | ||
40 | + return { ...state, registerSuccess: action.payload }; | ||
41 | + break; | ||
42 | + case USER_LOGIN: | ||
43 | + return { ...state, loginData: action.payload }; | ||
44 | + break; | ||
45 | + case USER_LOGOUT: | ||
46 | + return { ...state, loginData: action.payload }; | ||
47 | + break; | ||
48 | + default: | ||
49 | + return state; | ||
50 | + } | ||
51 | +} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
weather_briefing/src/modules/weather.js
0 → 100644
1 | +import axios from "axios"; | ||
2 | + | ||
3 | +const WEATHER_ADDRESS = 'weather/ADDRESS'; | ||
4 | +const WEATHER_COORDINATE = 'weather/COORDINATE'; | ||
5 | +const WEATHER_TODAY_INFORMATION = 'weather/TODAY_INFORMATION'; | ||
6 | +const WEATHER_TOMMORROW_INFORMATION = 'weather/TOMMORROW_INFORMATION'; | ||
7 | + | ||
8 | +export function address() { | ||
9 | + const req = axios.post('http://localhost:4000/api/address') | ||
10 | + .then(res => res.data); | ||
11 | + | ||
12 | + return { | ||
13 | + type: WEATHER_ADDRESS, | ||
14 | + payload: req, | ||
15 | + } | ||
16 | +} | ||
17 | + | ||
18 | +export function coordinate(dataToSubmit) { | ||
19 | + | ||
20 | + const req = axios.post('http://localhost:4000/api/cordinate', dataToSubmit) | ||
21 | + .then(res => res.data); | ||
22 | + | ||
23 | + return { | ||
24 | + type: WEATHER_COORDINATE, | ||
25 | + payload: req, | ||
26 | + } | ||
27 | +}; | ||
28 | + | ||
29 | +export function todayInformation(dataToSubmit) { | ||
30 | + const req = axios.post('http://localhost:4000/api/weather', dataToSubmit) | ||
31 | + .then(res => res.data); | ||
32 | + return { | ||
33 | + type: WEATHER_TODAY_INFORMATION, | ||
34 | + payload: req, | ||
35 | + } | ||
36 | +}; | ||
37 | + | ||
38 | +export function tommorrowInformation(dataToSubmit) { | ||
39 | + const req = axios.post('http://localhost:4000/api/tommorrow', dataToSubmit) | ||
40 | + .then(res => res.data); | ||
41 | + return { | ||
42 | + type: WEATHER_TOMMORROW_INFORMATION, | ||
43 | + payload: req, | ||
44 | + } | ||
45 | +}; | ||
46 | + | ||
47 | +export default function (state = {}, action) { | ||
48 | + switch (action.type) { | ||
49 | + case WEATHER_ADDRESS: | ||
50 | + return { ...state, address: action.payload }; | ||
51 | + break; | ||
52 | + case WEATHER_COORDINATE: | ||
53 | + return { ...state, dot: action.payload }; | ||
54 | + break; | ||
55 | + case WEATHER_TODAY_INFORMATION: | ||
56 | + return { ...state, todayInformation: action.payload }; | ||
57 | + break; | ||
58 | + case WEATHER_TOMMORROW_INFORMATION: | ||
59 | + return { ...state, tommorrowInformation: action.payload }; | ||
60 | + break; | ||
61 | + default: | ||
62 | + return state; | ||
63 | + } | ||
64 | +} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
weather_briefing/src/setupProxy.js
0 → 100644
1 | +const { createProxyMiddleware } = require("http-proxy-middleware"); | ||
2 | + | ||
3 | +module.exports = function(app) { | ||
4 | + app.use( | ||
5 | + createProxyMiddleware('/api', { | ||
6 | + target: 'http://localhost:4000', //접속하려는 서버의 루트 URL | ||
7 | + changeOrigin: true | ||
8 | + }) | ||
9 | + ); | ||
10 | +}; | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
-
Please register or login to post a comment