diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index f664c92..8c00743 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -7,6 +7,9 @@ import Header from "./components/common/Header"; import Register from "./Page/Register"; import HowtoPage from "./Page/HowtoPage"; import ErrorPage from "./components/common/ErrorPage"; +import DefaultHowPage from "./Page/DefaultHowPage"; + +import GreenBack from "./images/greenBack"; import MyTrashcan from "./components/Mypage/MyTrashcan"; import MyTrashChart from "./components/Mypage/MyTrashChart"; import MyChallenge from "./components/Mypage/MyChallenge"; @@ -33,16 +36,13 @@ function App() { } /> } /> } /> + } /> {/* mypage 에 접근 못하게 라우팅 */} }> }> } /> - {/* } - /> */} } /> } /> } /> diff --git a/frontend/src/Auth/checkToken.ts b/frontend/src/Auth/checkToken.ts index 9a4ee13..f3b6ae9 100644 --- a/frontend/src/Auth/checkToken.ts +++ b/frontend/src/Auth/checkToken.ts @@ -81,7 +81,7 @@ const getRefreshToken = async () => { localStorage.removeItem("access_token"); if (accessToken !== null) { - setAccessToken(accessToken); + setAccessToken(accessToken,false); window.location.reload(); } diff --git a/frontend/src/Auth/tokenManager.tsx b/frontend/src/Auth/tokenManager.tsx index 67e6297..e4b2767 100644 --- a/frontend/src/Auth/tokenManager.tsx +++ b/frontend/src/Auth/tokenManager.tsx @@ -1,18 +1,13 @@ -import axios from "axios"; import { rs } from "src/utils/types"; -import { decodeToken } from "./tokenGetter"; // 받아온 토큰을 만료일을 설정해 로컬 스토리지에 저장 -const setAccessToken = (accessToken: string) => { +const setAccessToken = (accessToken: string, changeToken: boolean) => { + if (changeToken = true) { + localStorage.removeItem("access_token"); + } const today = new Date(); const accessExpires = new Date().setTime(today.getTime() + 1000 * 60 * 30); // 만료 30분 - // const accessExpires = new Date(); - - // accessExpires.setTime(today.getTime() + 1000 * 60 * 30); // 30 minute - - // decodeToken(accessToken); - const accessStorage: rs.TokenInfo = { value: accessToken, expiry: accessExpires, @@ -20,27 +15,23 @@ const setAccessToken = (accessToken: string) => { localStorage.setItem("access_token", JSON.stringify(accessStorage)); }; -const setRefreshToken = (refreshtoken: string) => { +const setRefreshToken = (refreshtoken: string, changeToken: boolean) => { + if (changeToken = true) { + localStorage.removeItem("refresh_token"); + } const today = new Date(); - // const refreshExpires = new Date().setTime( - // today.getTime() + 1000 * 60 * 60 * 24 * 14 - // ); + const refreshExpires = new Date().setTime( - today.getTime() + 1000 * 60 * 24 * 14 + today.getTime() + 1000 * 60 * 60 * 24 * 14 ); - // const refreshExpires = new Date(); - - // refreshExpires.setTime(today.getTime() + 1000 * 60 * 60 * 24 * 7); // 7 day - - // decodeToken(accessToken); - const refreshStorage = { value: refreshtoken, expiry: refreshExpires, }; localStorage.setItem("refresh_token", JSON.stringify(refreshStorage)); }; + // 로컬 스토리지에 있는 토큰을 확인 const getToken = () => { const access = localStorage.getItem("access_token"); diff --git a/frontend/src/Page/DefaultHowPage.tsx b/frontend/src/Page/DefaultHowPage.tsx new file mode 100644 index 0000000..442dc37 --- /dev/null +++ b/frontend/src/Page/DefaultHowPage.tsx @@ -0,0 +1,73 @@ +import * as React from "react"; +import { Box, Grid, Typography, Link } from "@mui/material"; +import SearchBar from "../components/mainpage/SearchBar"; +import ExplanationTrash from "../components/howtopage/ExplanationTrash"; + +import { useLocation } from 'react-router-dom'; + +const HowtoPage = () => { + + const item = useLocation(); + const itemform = item?.state as any; + + const itemImage = itemform.needImages; + const itemKind = itemform.needKind; + + return ( + +
+ + + + + + + + + How to recycle? + + + + + {" "} + Go To Mainpage{" 👉"}{" "} + + +
+
+ ); +}; + +export default HowtoPage; diff --git a/frontend/src/Page/HowtoPage.tsx b/frontend/src/Page/HowtoPage.tsx index 1b5d6b6..14e423d 100644 --- a/frontend/src/Page/HowtoPage.tsx +++ b/frontend/src/Page/HowtoPage.tsx @@ -37,6 +37,8 @@ const HowtoPage = () => { const userIdToRedux = ReduxModule().decodeInfo?.id; const reduxKindAndImg = ReduxImgApi(itemID, userIdToRedux); + console.log(userIdToRedux); + console.log(itemID); const { state } = useLocation() as TypeChallenge; @@ -85,7 +87,7 @@ const HowtoPage = () => { }} > @@ -115,7 +117,7 @@ const HowtoPage = () => { fontWeight: "bold", fontFamily: "Itim", padding: 100, - color: "black", + color: "#737458", fontSize: 30, }} > diff --git a/frontend/src/Page/Login.tsx b/frontend/src/Page/Login.tsx index 95fdbbf..f0083e0 100644 --- a/frontend/src/Page/Login.tsx +++ b/frontend/src/Page/Login.tsx @@ -50,8 +50,8 @@ function Login() { console.log("받아온 결과2", result.refresh_token); if (result.access_token !== null) { - setAccessToken(result.access_token); - setRefreshToken(result.refresh_token); + setAccessToken(result.access_token,false); + setRefreshToken(result.refresh_token,false); alert("로그인 성공♻️"); // checkAccessToken(); diff --git a/frontend/src/Page/MyPage.tsx b/frontend/src/Page/MyPage.tsx index b067cb3..6eb7a96 100644 --- a/frontend/src/Page/MyPage.tsx +++ b/frontend/src/Page/MyPage.tsx @@ -1,6 +1,6 @@ import * as React from "react"; import MyPageNavigation from "../components/Mypage/MyPageNavigation"; -import { Box, Container } from "@mui/material"; +import { Container } from "@mui/material"; import { Outlet } from "react-router-dom"; function MyPage() { diff --git a/frontend/src/Page/Register.tsx b/frontend/src/Page/Register.tsx index 91b69e2..315381d 100644 --- a/frontend/src/Page/Register.tsx +++ b/frontend/src/Page/Register.tsx @@ -73,7 +73,7 @@ const UserInfoTf = styled(TextField)(({}) => ({ const FormHelperTexts = styled(FormHelperText)` width: 100%; - padding: "auto; + padding:6px; font-weight: 600; color: #c65959; font-size: 12px; @@ -87,11 +87,8 @@ interface User { } const Register = () => { - const [emailError, setEmailError] = useState(""); const [passwordState, setPasswordState] = useState(""); const [passwordError, setPasswordError] = useState(""); - const [nameError, setNameError] = useState(""); - const [aliasError, setAliasError] = useState(""); const [name, setName] = useState(""); const [email, setEmail] = useState(""); @@ -102,9 +99,9 @@ const Register = () => { const emailRegex = /([\w-.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/; - const passwordRegex = /^[가-힣a-zA-Z]+$/; - const nameRegex = /^[가-힣a-zA-Z]+$/; - const aliasRegex = /^[가-힣a-zA-Z]+$/; + const passwordRegex = /^[가-힣a-zA-Z0-9]+$/; + const nameRegex = /^[가-힣a-zA-Z0-9]+$/; + const aliasRegex = /^[가-힣a-zA-Z0-9]+$/; //form 비교 const handleSubmit = (e: React.FormEvent) => { @@ -138,7 +135,9 @@ const Register = () => { nameRegex.test(user.name as string) && aliasRegex.test(user.alias as string) ) { + Api.post(`/users/`, user) + .then((response) => { // Handle success. handleOpen(); @@ -163,31 +162,29 @@ const Register = () => { if (props[0] === "name") { if (!nameRegex.test(name as string) || (name as string).length < 1) { - setNameError("올바른 이름을 입력해주세요."); - setCheckName(""); + setCheckName("올바른 이름을 입력해주세요."); } else { - setNameError(""); - if (res.data.result == false) setCheckName("사용 중인 아이디입니다."); + + if (res.data.result === false) setCheckName("사용 중인 아이디입니다."); + else setCheckName("사용 가능한 아이디 입니다."); } } if (props[0] === "email") { if (!emailRegex.test(email as string)) { - setEmailError("올바른 이메일 형식이 아닙니다."); + setCheckEmail("올바른 이메일 형식이 아닙니다."); } else { - setEmailError(""); - if (res.data.result === false) - setCheckEmail("사용 중인 이메일 입니다."); + + if (res.data.result === false) setCheckEmail("사용 중인 이메일 입니다."); + else setCheckEmail("사용 가능한 이메일 입니다."); } } if (props[0] === "alias") { if (!aliasRegex.test(alias as string) || (alias as string).length < 1) { - setAliasError("올바른 이름을 입력해주세요."); - setCheckName(""); + setCheckAlias("올바른 이름을 입력해주세요."); } else { - setAliasError(""); if (res.data.result === false) setCheckAlias("사용 중인 닉네임 입니다."); else setCheckAlias("사용 가능한 닉네임 입니다."); @@ -246,18 +243,8 @@ const Register = () => { onBlur={(event) => { onBlurInfo(["name", name], event); }} - error={nameError !== "" || false} /> - - {checkName} - - {nameError} + {checkName} { label="Password" type="password" id="password" - error={passwordState !== "" || false} /> {passwordState} { label="Password Confirm" type="password" id="rePassword" - error={passwordError !== "" || false} /> {passwordError} @@ -293,19 +278,9 @@ const Register = () => { onBlur={(event) => { onBlurInfo(["email", email], event); }} - error={emailError !== "" || false} /> - - {checkEmail} - - {emailError} + {checkEmail} { onBlurInfo(["alias", alias], event); }} /> - - {checkAilas} - + {checkAilas} - - + - + ); } diff --git a/frontend/src/components/Mypage/Change_nickname.tsx b/frontend/src/components/Mypage/Change_nickname.tsx new file mode 100644 index 0000000..b9923de --- /dev/null +++ b/frontend/src/components/Mypage/Change_nickname.tsx @@ -0,0 +1,209 @@ +import * as React from "react"; +import { createTheme, ThemeProvider } from "@mui/material/styles"; +import axios from "axios"; +import { rs } from "src/utils/types"; +import { API_BASE_URL } from "src/utils/constants"; +import { getAccess } from "../../Auth/tokenManager"; +import { setAccessToken, setRefreshToken } from "src/Auth/tokenManager"; +import { useState } from "react"; +import Api from "../../utils/customApi"; + +import { + FormHelperText, + Typography, + Container, + styled, + TextField, + Box, + Link, + Button, +} from "@mui/material"; + +const theme = createTheme({ + palette: { + primary: { + main: "#737458", + }, + }, +}); + +const UserInfoChange = styled(TextField)(({}) => ({ + borderRadius: 5, + textAlign: "center", + "&:hover": { + color: "#737458", + }, + + "& .MuiOutlinedInput-root": { + "&:hover fieldset": { + borderColor: "#737458", + }, + }, +})); + +const FormHelperTexts = styled(FormHelperText)` + width: 100%; + padding-left: 6px; + font-weight: 600; + color: #c65959; + font-size: 12px; +`; + +function ChangeNickName() { + const aliasRegex = /^[가-힣a-zA-Z0-9]+$/; + const [checkAilas, setCheckAlias] = useState(""); + const [alias, setAlias] = useState(""); + const [newAccess, getNewAccess] = useState(""); + + const onBlurInfo = async (props: Array, event: any) => { + const res = await Api.get( + `/users/?case=${props[0]}&value=${props[1] as string}` + ); + if (props[0] === "alias") { + if (!aliasRegex.test(alias as string) || (alias as string).length < 1) { + setCheckAlias("올바른 닉네임을 입력해주세요."); + } else { + if (res.data.result == false) setCheckAlias("사용 중인 닉네임 입니다."); + else setCheckAlias("사용 가능한 닉네임 입니다."); + } + } + }; // 닉네임 유효성 체크 + + // 닉네임 체크에 통과될 때 + const aliasChange = async (changeAlias: string) => { + const stringAccess: any = getAccess(); + + if (stringAccess !== null) { + // stringAccess if문 안써주면 코드 오류 발생 + /* const access: rs.TokenInfo = JSON.parse(stringAccess); // string형태로 받는 토큰 JSON으로 만들어줌*/ + console.log("넘겨줄 토큰값", stringAccess); + + await axios + .patch( + `${API_BASE_URL}/users/`, + { value: { alias: changeAlias } }, + { + //patch : 바디 -> 변경할 alias & 헤더 -> 확인해야되는 토큰 + headers: { + Authorization: `${stringAccess.value}`, + }, + } + ) + .then((response) => { + console.log("response", response.data); + setAccessToken(response.data.access_token, true); // 그 전의 access토큰 초기화 + setRefreshToken(response.data.refresh_token, true); // 그 전의 refresh토큰 초기화 + alert("닉네임이 정상적으로 변경되었습니다!"); + window.location.reload(); + }) + .catch((e) => { + // 의도치 않는 오류 + alert("로그인 정보에 오류가 생겼습니다."); + }); + } + }; + + const handleSubmit = (e: any) => { + e.preventDefault(); + const data = new FormData(e.currentTarget); + const changeAlias = data.get("alias"); + if ( + aliasRegex.test(changeAlias as string) && + checkAilas === "사용 가능한 닉네임 입니다." + ) { + aliasChange(changeAlias as string); + } else e.preventDefault(); + //오류 생길때는 활성화 X 화면 넘어가지 않도록 + }; + + React.useEffect(() => {}, [alias]); + React.useEffect(() => { + console.log("newAccess",newAccess); + }, [newAccess]); + + return ( + + + + 닉네임 변경 + + + + + setAlias(e.target.value)} + onBlur={(event) => { + onBlurInfo(["alias", alias], event); + }} + /> + {checkAilas} + + + + + + ); +} + +export default ChangeNickName; diff --git a/frontend/src/components/Mypage/Change_password.tsx b/frontend/src/components/Mypage/Change_password.tsx new file mode 100644 index 0000000..65761d4 --- /dev/null +++ b/frontend/src/components/Mypage/Change_password.tsx @@ -0,0 +1,204 @@ +import * as React from "react"; +import { createTheme, ThemeProvider } from "@mui/material/styles"; +import axios from "axios"; +import { rs } from "src/utils/types"; +import { API_BASE_URL } from "src/utils/constants"; +import { getAccess } from "../../Auth/tokenManager"; +import { setAccessToken, setRefreshToken } from "src/Auth/tokenManager"; +import { useState } from "react"; +import Api from "../../utils/customApi"; + +import { + FormHelperText, + Typography, + Container, + styled, + TextField, + Box, + Link, + Button +} from "@mui/material"; + +const theme = createTheme({ + palette: { + primary: { + main: "#737458", + }, + }, +}); + +const UserInfoChange = styled(TextField)(({ }) => ({ + borderRadius: 5, + textAlign: "center", + "&:hover": { + color: "#737458", + }, + + "& .MuiOutlinedInput-root": { + "&:hover fieldset": { + borderColor: "#737458", + }, + }, +})); + +const FormHelperTexts = styled(FormHelperText)` + width: 100%; + padding-left:6px; + font-weight: 600; + color: #c65959; + font-size: 12px; +`; + + +function ChangePassWord() { + const [passwordState, setPasswordState] = useState(""); + const [passwordError, setPasswordError] = useState(""); + const passwordRegex = /^[가-힣a-zA-Z0-9]+$/; + + const aliasChange = async (changePassword : string) => { + const stringAccess: any = getAccess(); + + if (stringAccess !== null) { // stringAccess if문 안써주면 코드 오류 발생 + /* const access: rs.TokenInfo = JSON.parse(stringAccess); // string형태로 받는 토큰 JSON으로 만들어줌*/ + console.log("넘겨줄 토큰값", stringAccess); + + await axios + .patch(`${API_BASE_URL}/users/`, { "value": { password: changePassword } }, { //patch : 바디 -> 변경할 alias & 헤더 -> 확인해야되는 토큰 + headers: { + Authorization: `${stringAccess.value}`, + }, + }) + .then((response) => { + console.log("response", response.data); + setAccessToken(response.data.access_token, true); // 그 전의 access토큰 초기화 + setRefreshToken(response.data.refresh_token, true); // 그 전의 refresh토큰 초기화 + alert("비밀번호가 정상적으로 변경되었습니다!"); + window.location.reload(); + }) + .catch((e) => { // 의도치 않는 오류 + alert("로그인 정보에 오류가 생겼습니다."); + }); + }; + } + + + const handleSubmit = (e: any) => { + e.preventDefault(); + const data = new FormData(e.currentTarget); + const rePassword = data.get("rePassword"); + const changePassword = data.get("password"); + + // 비밀번호 유효성 체크 + if (!passwordRegex.test(changePassword as string)) + setPasswordState("비밀번호를 형식에 맞춰 입력해주세요!"); + else setPasswordState(""); + + // 비밀번호 같은지 체크 + if (changePassword !== rePassword) + setPasswordError("비밀번호가 일치하지 않습니다."); + else setPasswordError(""); + + if (passwordRegex.test(changePassword as string) && + (changePassword as string) === rePassword) { // 닉네임 체크에 통과될 때 + aliasChange(changePassword as string); + } + else e.preventDefault(); + //오류 생길때는 활성화 X 화면 넘어가지 않도록 + } + + + + return ( + + + + 비밀번호 변경 + + + + + + + {passwordState} + + + {passwordError} + + + + + + + ); +} + +export default ChangePassWord; diff --git a/frontend/src/components/Mypage/MultiActionAreaCard.tsx b/frontend/src/components/Mypage/MultiActionAreaCard.tsx index bdc01c5..95c138d 100644 --- a/frontend/src/components/Mypage/MultiActionAreaCard.tsx +++ b/frontend/src/components/Mypage/MultiActionAreaCard.tsx @@ -5,10 +5,12 @@ import { CardActions, Card, CardMedia, - Typography, styled, - Link, } from "@mui/material"; +import { useDispatch } from "react-redux"; +import { save_ID } from "../../actions/ImgIDActions"; + +import { useNavigate } from "react-router-dom"; const MyTrashcanBtn = styled(Button)(({}) => ({ backgroundColor: "#B0B09A", @@ -20,10 +22,21 @@ const MyTrashcanBtn = styled(Button)(({}) => ({ }, })); -export default function MultiActionAreaCard({ image = "", id = 0 }) { - console.log(id); +export default function MultiActionAreaCard({ image = "", id = "" }) { + const navigate = useNavigate(); + + const dispatch = useDispatch(); + //const itemID = useSelector((state: RootReducerType) => state.ImgIDReducer); + const onDispatch = () => { + // console.log(id); + dispatch(save_ID(id)); + navigate(`/howtopage`); + }; + return ( - + - - 상세보기 - + 더보기 diff --git a/frontend/src/components/Mypage/MyChallenge.tsx b/frontend/src/components/Mypage/MyChallenge.tsx index c074ce0..93c1c5d 100644 --- a/frontend/src/components/Mypage/MyChallenge.tsx +++ b/frontend/src/components/Mypage/MyChallenge.tsx @@ -13,23 +13,23 @@ interface Contentlist { const trashlist: Contentlist = { list: [ { - challenge_number: 1, + challenge_id: 1, type: false, }, { - challenge_number: 2, + challenge_id: 2, type: false, }, { - challenge_number: 3, + challenge_id: 3, type: false, }, { - challenge_number: 4, + challenge_id: 4, type: false, }, { - challenge_number: 5, + challenge_id: 5, type: false, }, ], @@ -40,6 +40,7 @@ function MyBadge() { const userIdtoRedux = ReduxModule().decodeInfo?.id; const [myChallenge, setMyChallenge] = useState(); + const fetchMyChallenge = async () => { const result = await Api.get(`/trash/users/${userIdtoRedux}/challenges`, { headers: { @@ -47,10 +48,10 @@ function MyBadge() { }, }).then((res) => res.data as rs.Challenge[]); const challengeList = result; - + console.log(result); const temptList: rs.Challenge[] = trashlist.list?.map((trashlist: any) => { challengeList?.map((getlist: any) => { - if (getlist?.challenge_number === trashlist.challenge_number) { + if (getlist?.challenge_id === trashlist.challenge_id) { trashlist.type = true; } return getlist; @@ -58,11 +59,13 @@ function MyBadge() { return trashlist; }); setMyChallenge(temptList); + console.log(temptList); return temptList; }; + useEffect(() => { fetchMyChallenge(); - }, [myChallenge]); + }, []); return ( @@ -99,7 +103,7 @@ function MyBadge() { {trashlist && trashlist?.list?.map((list: rs.Challenge, index: any) => ( diff --git a/frontend/src/components/Mypage/MyTrashChart.tsx b/frontend/src/components/Mypage/MyTrashChart.tsx index 9766de0..ba5cab3 100644 --- a/frontend/src/components/Mypage/MyTrashChart.tsx +++ b/frontend/src/components/Mypage/MyTrashChart.tsx @@ -20,20 +20,26 @@ function MyTrashchart() { borderRadius: 5, borderColor: "transparent", minWidth: "100%", - height: "80vh", + height: "100vh", }}> 내 쓰레기 통계 - - + + + + + + ); diff --git a/frontend/src/components/Mypage/MyTrashcan.tsx b/frontend/src/components/Mypage/MyTrashcan.tsx index 5bae626..a3eeae2 100644 --- a/frontend/src/components/Mypage/MyTrashcan.tsx +++ b/frontend/src/components/Mypage/MyTrashcan.tsx @@ -1,5 +1,13 @@ import { useState, useEffect, useRef } from "react"; -import { Box, Typography, Container, Button } from "@mui/material"; +import { + Box, + Typography, + Container, + Button, + Link, + styled, + Switch, +} from "@mui/material"; import MultiActionAreaCard from "./MultiActionAreaCard"; import Api from "../../utils/customApi"; import lottie from "lottie-web"; @@ -7,10 +15,23 @@ import MoreIcon from "../../images/moreIcon"; import { rs } from "src/utils/types"; import { getAccess } from "src/Auth/tokenManager"; import { ReduxModule } from "../../modules/ReduxModule"; +import { alpha } from "@mui/material/styles"; +import { isAutoSave, changeAutoSave } from "../../utils/autoSaveToggle"; interface Props { trashlist?: Array; } +const GreenSwitch = styled(Switch)(({ theme }) => ({ + "& .MuiSwitch-switchBase.Mui-checked": { + color: "#93C85B", + "&:hover": { + backgroundColor: alpha("#DAEEC5", theme.palette.action.hoverOpacity), + }, + }, + "& .MuiSwitch-switchBase.Mui-checked + .MuiSwitch-track": { + backgroundColor: "#D9D9D9", + }, +})); const GetNoTrashLottie = () => { //lottie @@ -30,12 +51,11 @@ const GetNoTrashLottie = () => { function MyTrashcan(props: Props) { const what: any = getAccess(); const userIdtoRedux = ReduxModule().decodeInfo?.id; - + //=============MyTrashCan API================ const [trashes, setTrashes] = useState(props.trashlist); const [more, setMore] = useState(false); const [page, setPage] = useState(1); - - const [last, setLast] = useState(true); + const [last, setLast] = useState(false); const fetchMyTrash = async () => { await Api.get(`/trash/users/${userIdtoRedux}/pages/${page}`, { @@ -46,9 +66,9 @@ function MyTrashcan(props: Props) { if (res.data) { const newArray = trashes ? [...trashes, ...res.data] : res.data; setTrashes(newArray); - console.log(trashes); - } else { setLast(false); + } else { + setLast(true); } }); }; @@ -64,7 +84,21 @@ function MyTrashcan(props: Props) { } }, [page]); - useEffect(() => {}, [trashes]); + useEffect(() => { + console.log(trashes); + }, [trashes]); + + //=============MyTrashCan API================ + const isSaved = isAutoSave(); + const [checked, setChecked] = useState(true); + isSaved.then((e) => { + setChecked(e.user_autosave); + }); + + const switchHandler = (event: any) => { + setChecked(event.target.checked); + changeAutoSave(checked); + }; return ( + {" "} + + + auto save + + + + {" "} - 쓰레기를 사진을 업로드 해보세요. + + fill your ReBIKE > + ) : ( - - {trashes && - Object.values(trashes)?.map((item: rs.Trash, index: any) => ( - - ))} - - )} - - {last === true ? ( - - ) : ( - - no more data! + {last ? ( + + ) : ( + + )} - )} - + + )} diff --git a/frontend/src/components/chart/Chart.tsx b/frontend/src/components/chart/Chart.tsx index 299ab0d..87204ae 100644 --- a/frontend/src/components/chart/Chart.tsx +++ b/frontend/src/components/chart/Chart.tsx @@ -2,9 +2,10 @@ import { slideAnimationDuration } from '@mui/x-date-pickers/CalendarPicker/Picke import React, { PureComponent, useState } from 'react'; import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts'; + interface Content { - trash_kind: string; - cnt: number; + kind: string; + count: number; } interface Contentlist { @@ -15,28 +16,28 @@ const trashlist: Contentlist = { list: [ { - trash_kind: "GLASS", - cnt: 0 + kind: "GLASS", + count: 0 }, { - trash_kind: "BIODEGRADABLE", - cnt: 0 + kind: "BIODEGRADABLE", + count: 0 }, { - trash_kind: "CARDBOARD", - cnt: 0 + kind: "CARDBOARD", + count: 0 }, { - trash_kind: "PAPER", - cnt: 0 + kind: "PAPER", + count: 0 }, { - trash_kind: "METAL", - cnt: 0 + kind: "METAL", + count: 0 }, { - trash_kind: "PLASTIC", - cnt: 0 + kind: "PLASTIC", + count: 0 }, ] } @@ -50,7 +51,7 @@ function TrashChart({ list }: Contentlist) { for (let i = 0; i < trashlist.list.length; i++) { for (let j = 0; j < list.length; j++) { if (list[j].trash_kind === trashlist.list[i].trash_kind) { - trashlist.list[i].cnt = list[j].cnt; + trashlist.list[i].count = list[j].cnt; console.log("같은 것을 발견"); } } @@ -65,7 +66,7 @@ function TrashChart({ list }: Contentlist) { if (list) { if (list.length === 0) { // 받아오는 데이터가 존재하지 않을 때 const needList: Content[] = trashlist.list?.map((blanklist: any) => { - blanklist.cnt = 0; + blanklist.count = 0; return blanklist; }) setBasicList(needList); @@ -74,8 +75,8 @@ function TrashChart({ list }: Contentlist) { else { // 그 외 데이터가 존재할 때 const tempList: Content[] = trashlist.list?.map((trashlist: any) => { list?.map((getlist: any) => { - if (getlist?.trash_kind === trashlist?.trash_kind) { - trashlist.cnt = getlist.cnt; + if (getlist?.kind === trashlist?.kind) { + trashlist.count = getlist.cnt; console.log("같은 것을 발견"); } return getlist; @@ -103,11 +104,11 @@ function TrashChart({ list }: Contentlist) { }} > - + - + ); diff --git a/frontend/src/components/chart/Date.tsx b/frontend/src/components/chart/Date.tsx index edc4aea..a546a5e 100644 --- a/frontend/src/components/chart/Date.tsx +++ b/frontend/src/components/chart/Date.tsx @@ -6,6 +6,9 @@ import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider"; import { DatePicker } from "@mui/x-date-pickers/DatePicker"; import { createTheme, ThemeProvider } from "@mui/material/styles"; import axios from "axios"; +import { API_BASE_URL } from "src/utils/constants"; +import { getAccess } from "../../Auth/tokenManager"; +import { ReduxModule } from "../../modules/ReduxModule"; const theme = createTheme({ palette: { @@ -25,6 +28,7 @@ function formatDate(date: Date) { function Dates({ onClickRetrieve }: { onClickRetrieve: any }) { // 함수의 반환 : onClickRetrieve + const userIdtoRedux = ReduxModule().decodeInfo?.id; const [StartDate, setStartDate] = React.useState(null); const [StartLock, setStartLock] = React.useState(null); @@ -61,22 +65,33 @@ function Dates({ onClickRetrieve }: { onClickRetrieve: any }) { } } - axios - .get( - `http://localhost:8080/trash/mypage/users/2c762f6e-b369-4985-96f9-29ccb4f9fc34/statistics${periodStr}${startDateStr}${endDateStr}` - ) - .then((response) => { - // Handle success. - const responseUserData = response.data; - console.log("data saved!"); - console.log(response.data); - onClickRetrieve(responseUserData); - }) - .catch((error) => { - // Handle error. - console.log("An error occurred:", error.response); - }); - }; + const getDate = async () => { + const stringAccess: any = getAccess(); + console.log("잘 온거?", stringAccess); + if (stringAccess !== null) { // stringAccess if문 안써주면 코드 오류 발생 + /* const access: rs.TokenInfo = JSON.parse(stringAccess); // string형태로 받는 토큰 JSON으로 만들어줌*/ + await axios + .get( + `${API_BASE_URL}/trash/users/${userIdtoRedux}/statistics${periodStr}${startDateStr}${endDateStr}`, { //patch : 바디 -> 변경할 alias & 헤더 -> 확인해야되는 토큰 + headers: { + Authorization: `${stringAccess.value}` + } + }) + .then((response) => { + // Handle success. + const responseUserData = response.data; + console.log("data saved!"); + console.log(response.data); + onClickRetrieve(responseUserData); + }) + .catch((error) => { + // Handle error. + console.log("An error occurred:", error.response); + }); + }; + } + getDate(); + } React.useEffect(() => { fetchUserData(); @@ -103,7 +118,7 @@ function Dates({ onClickRetrieve }: { onClickRetrieve: any }) { > - 조회 + Submit diff --git a/frontend/src/components/common/Footer.tsx b/frontend/src/components/common/Footer.tsx index 9101a64..a44cab8 100644 --- a/frontend/src/components/common/Footer.tsx +++ b/frontend/src/components/common/Footer.tsx @@ -50,20 +50,50 @@ function Footer() { color: "white", fontSize: 10, display: "flex", - flexDirection: "column", + flexDirection: "row", justifyContent: "center", alignItems: "center", + marginTop: 3, }} > -
FrontEnd
-
이채현
-
이정우
-
진호병
-
-
-
BackEnd
-
김용민
-
김유림
-
박성빈
+
+
FrontEnd
+
이채현
+
이정우
+
진호병
+
+
+ X +
+
+
BackEnd
+
김용민
+
김유림
+
박성빈
+
({ + border: 4, + borderColor: "#F7F8E9", + fontSize: "small", + color: "#F7F8E9", + backgroundColor: "#B0B09A", + "&:hover": { + color: "black", + }, +})); + function Header() { const token = localStorage.getItem("access_token"); @@ -31,18 +79,29 @@ function Header() { } }, []); - const [mouseOn, setMouseOn] = useState(false); + function deleteToken() { + localStorage.clear(); + } - const handlePopoverOpen = () => { - setMouseOn(true); + //============Mypage List============ + const navigate = useNavigate(); + + const [anchorEl, setAnchorEl] = useState(null); + const [selectedIndex, setSelectedIndex] = useState(0); + const open = Boolean(anchorEl); + const handleClickListItem = (event: any) => { + setAnchorEl(event.currentTarget); }; - const handlePopoverClose = () => { - setMouseOn(false); + + const handleMenuItemClick = (event: any, index: any, option: any) => { + setSelectedIndex(index); + setAnchorEl(null); + navigate(option.to); }; - function deleteToken() { - localStorage.clear(); - } + const handleClose = () => { + setAnchorEl(null); + }; return ( @@ -76,23 +135,74 @@ function Header() { {token ? ( // if IsLogin is true
-
-
- - + + + + 2nd + + + + + + {secondData?.kind} + + + + + + + + + 3rd + + + + + + {thridData?.kind} + + + + + + ); } + +export default MultiActionAreaCard; diff --git a/frontend/src/images/moreIcon.tsx b/frontend/src/images/moreIcon.tsx index 7049aed..2aaba56 100644 --- a/frontend/src/images/moreIcon.tsx +++ b/frontend/src/images/moreIcon.tsx @@ -11,7 +11,7 @@ function IconExpand() { ); diff --git a/frontend/src/utils/autoSaveToggle.tsx b/frontend/src/utils/autoSaveToggle.tsx new file mode 100644 index 0000000..74cd89a --- /dev/null +++ b/frontend/src/utils/autoSaveToggle.tsx @@ -0,0 +1,34 @@ +import Api from "./customApi"; +import { getAccess } from "src/Auth/tokenManager"; +import { rs } from "../utils/types"; + +const what: any = getAccess(); +let user_autosave: rs.AutoSave; + +const isAutoSave = async () => { + await Api.get(`/users/autosave`, { + headers: { + Authorization: `${what.value}`, + }, + }).then((res) => { + user_autosave = res.data; + + return user_autosave; + }); + return user_autosave; +}; + +const changeAutoSave = async (isBoolean: boolean) => { + await Api.patch(`/users/autosave`, isBoolean, { + headers: { + Authorization: `${what.value}`, + }, + }).then((res) => { + user_autosave = res.data; + + return user_autosave; + }); + return user_autosave; +}; + +export { isAutoSave, changeAutoSave }; diff --git a/frontend/src/utils/types.tsx b/frontend/src/utils/types.tsx index 23dd6f2..173788e 100644 --- a/frontend/src/utils/types.tsx +++ b/frontend/src/utils/types.tsx @@ -16,7 +16,7 @@ export namespace rs { } export interface Trash { - uploaded_trash_image_id: number; + id?: any; image: string; } @@ -34,7 +34,7 @@ export namespace rs { } //❌ export interface Challenge { - challenge_number: number; + challenge_id: number; type: boolean; } export interface ChallengeInfo { @@ -43,4 +43,8 @@ export namespace rs { imgF: string; test: string; } + + export interface AutoSave { + user_autosave: boolean; + } }