diff --git a/src/types/react-syntax-highlighter.d.ts b/@Types/react-syntax-highlighter.d.ts similarity index 100% rename from src/types/react-syntax-highlighter.d.ts rename to @Types/react-syntax-highlighter.d.ts diff --git a/package.json b/package.json index ef988b3..5ed4936 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "@types/jest": "^27.0.1", "@types/js-cookie": "^3.0.6", "@types/node": "^16.7.13", - "@types/react": "^18.0.0", + "@types/react": "^18.3.3", "@types/react-dom": "^18.0.0", "axios": "^1.7.2", "concurrently": "^8.2.2", @@ -19,6 +19,7 @@ "react-dom": "^18.3.1", "react-markdown": "^9.0.1", "react-query": "^3.39.3", + "react-query-devtools": "^2.6.3", "react-router-dom": "^6.23.1", "react-scripts": "5.0.1", "react-syntax-highlighter": "^15.5.0", @@ -26,6 +27,7 @@ "styled-components": "^6.1.11", "styled-reset": "^4.5.2", "sweetalert2": "^11.11.1", + "swiper": "^11.1.8", "typescript": "^4.4.2", "unified": "^11.0.5", "unist-util-position": "^5.0.0", @@ -53,6 +55,7 @@ }, "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e", "devDependencies": { - "@types/react-syntax-highlighter": "^15.5.13" + "@types/react-syntax-highlighter": "^15.5.13", + "@types/swiper": "^6.0.0" } } diff --git a/src/assets/imgs/Signimg/Expand_down.svg b/src/assets/imgs/Signimg/Expand_down.svg new file mode 100644 index 0000000..089cd4e --- /dev/null +++ b/src/assets/imgs/Signimg/Expand_down.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/imgs/alarm/alert.svg b/src/assets/imgs/main/alert.svg similarity index 100% rename from src/assets/imgs/alarm/alert.svg rename to src/assets/imgs/main/alert.svg diff --git a/src/assets/imgs/main/metometi.svg b/src/assets/imgs/main/metometi.svg new file mode 100644 index 0000000..e204ea5 --- /dev/null +++ b/src/assets/imgs/main/metometi.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/imgs/postHeader/post.png b/src/assets/imgs/postHeader/post.png new file mode 100644 index 0000000..29b5ce4 Binary files /dev/null and b/src/assets/imgs/postHeader/post.png differ diff --git a/src/components/auth/Login/index.tsx b/src/components/auth/Login/index.tsx index 9d31f35..afd2add 100644 --- a/src/components/auth/Login/index.tsx +++ b/src/components/auth/Login/index.tsx @@ -23,8 +23,8 @@ const LoginComponent = ({ setIsLogin }: Props) => { 아이디

*

{ 비밀번호

*

{ const signupComponents: ReactNode[] = [ , , ]; diff --git a/src/components/auth/Signup/signupFirst/index.tsx b/src/components/auth/Signup/signupFirst/index.tsx index 2bf6189..f92428a 100644 --- a/src/components/auth/Signup/signupFirst/index.tsx +++ b/src/components/auth/Signup/signupFirst/index.tsx @@ -27,8 +27,8 @@ const SignupFirst = ({ 아이디

*

*

*

>; - signupData: Sign; - handleSignupData: (e: React.ChangeEvent) => void; - submitSignupDataSecond: () => void; - keydownButton: (e: React.KeyboardEvent) => void; - } + setSection: Dispatch>; + signupData: Sign; + handleSignupData: ( + e: React.ChangeEvent + ) => void; + emailKeydownButton: (e: React.KeyboardEvent) => void; + submitSignupDataSecond: () => void; + keydownButton: (e: React.KeyboardEvent) => void; + chckEmailAuthCode: () => void; + isWaiting: string; +} -const SignupSecond = ({ setSection,signupData, - handleSignupData, - keydownButton, - submitSignupDataSecond, - }:Props) => { +const SignupSecond = ({ + setSection, + signupData, + handleSignupData, + keydownButton, + submitSignupDataSecond, + chckEmailAuthCode, + emailKeydownButton, + isWaiting, +}: Props) => { return ( <> - setSection("first")}> - 돌아가라 어리석은것 - 돌아가기 + setSection("first")}> + 돌아가라 어리석은것 + 돌아가기 이름

*

- 이메일

*

+ 학교

*

- + > + + + + + + +
- 이메일 인증번호

*

+ 이메일

*

+ + + + 인증하기 + + +
+ + + + {" "} + 이메일 인증번호

*

+
+

+ {isWaiting === "전송중" + ? "이메일 전송중.." + : isWaiting === "전송성공" + ? "이메일 전송성공" + : ""} +

+
- + Page {currentPage} of {displayTotalPages} + + ); diff --git a/src/components/post/senior-to-junior/index.style.ts b/src/components/post/senior-to-junior/index.style.ts new file mode 100644 index 0000000..fc6c2f3 --- /dev/null +++ b/src/components/post/senior-to-junior/index.style.ts @@ -0,0 +1,118 @@ +import styled from "styled-components"; +import ImageSrc from "src/assets/imgs/postHeader/post.png"; + +export const PostImage = styled.div` + width: 100%; + height: 250px; + background-image: url(${ImageSrc}); + background-size: cover; + background-position: center; + border-radius: 8px 8px 0 0; +`; + +export const PostContainer = styled.div` + min-width: 240px; + width: 300px; + height: 244px; + max-height: 244px; + overflow: hidden; + display: flex; + flex-direction: column; + border-radius: 8px; + box-shadow: 0px 3px 9px 0px rgba(0, 0, 0, 0.04); + transition: transform 0.3s ease, box-shadow 0.3s ease; + + &:hover { + transform: translateY(-10px); + box-shadow: 0px 10px 20px rgba(0, 0, 0, 0.1); + cursor: pointer; + } +`; + +export const PostContentWrapper = styled.div` + padding: 10px; + display: flex; + flex-direction: column; + justify-content: space-between; + height: 100%; +`; + +export const PostTitle = styled.h2` + color: #000; + font-family: Pretendard; + font-size: 15px; + font-style: normal; + font-weight: 700; + line-height: 26px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +`; + +export const PostContent = styled.p` + font-size: 13px; + color: #555; + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + height: calc(13px * 2); +`; + +export const PostFooter = styled.div` + display: flex; + flex-direction: column; + justify-content: space-between; + align-items: flex-start; + font-size: 12px; + color: #888; + + & > div:first-child { + width: 100%; + margin-bottom: 4px; + } + + & > div:last-child { + width: 100%; + } +`; + +export const PostDate = styled.span` + color: var(--Gary-800, #818181); + font-family: Pretendard; + font-size: 12px; + font-style: normal; + font-weight: 500; + line-height: 13px; +`; + +export const PostReaction = styled.span` + color: var(--Gary-800, #818181); + font-family: Pretendard; + font-size: 13px; + font-style: normal; + font-weight: 500; + line-height: 13px; + margin-left: 8px; +`; + +export const AuthorProfile = styled.img` + width: 14px; + height: 14px; +`; + +export const PostAuthor = styled.span` + color: var(--DarkGray-900, #0e0e0e); + font-family: Pretendard; + font-size: 13px; + font-style: normal; + font-weight: 600; + line-height: 26px; + margin-left: 4px; +`; + +export const AuthorWrap = styled.div` + display: flex; + align-items: center; +`; diff --git a/src/components/post/senior-to-junior/index.tsx b/src/components/post/senior-to-junior/index.tsx new file mode 100644 index 0000000..7ca7bd8 --- /dev/null +++ b/src/components/post/senior-to-junior/index.tsx @@ -0,0 +1,37 @@ +import React from 'react'; +import * as S from 'src/components/post/senior-to-junior/index.style'; + +import AvatarImg from 'src/assets/imgs/header/AvatarImg.svg'; + +interface PostItemProps { + title: string; + content: string; + date: string; + reaction: number; + author: string; + style:React.CSSProperties; +} + +const PostItem = ({ title, content, date, reaction, author,style }: PostItemProps) => { + return ( + + + + {title} + {content} + +
+ {date} + {reaction} +
+ + + {author} + +
+
+
+ ); +}; + +export default PostItem; \ No newline at end of file diff --git a/src/components/routers/index.tsx b/src/components/routers/index.tsx index 157a376..894b1b8 100644 --- a/src/components/routers/index.tsx +++ b/src/components/routers/index.tsx @@ -1,7 +1,7 @@ import { Route, Routes } from "react-router-dom"; import Sign from "src/pages/auth/page"; import Main from "src/pages/main/page"; -import Wirte from "src/pages/wirte/page"; +import Write from "src/pages/wirte/page"; import Seniortojunior from "src/pages/seniortojunior/page"; import Portfolio from "src/pages/portfolio/page"; import Competition from "src/pages/competition/page"; @@ -12,11 +12,17 @@ const Router = () => { } /> } /> - } /> + } /> + } /> + } /> - }/> + } /> + } /> + } /> + + } /> } /> ); diff --git a/src/components/textFields/index.tsx b/src/components/textFields/index.tsx index aa5488d..cb46eee 100644 --- a/src/components/textFields/index.tsx +++ b/src/components/textFields/index.tsx @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React, { useState, useCallback } from "react"; import { Text_Field, Text_Field_Main } from "./style"; import deleteButton from "src/assets/imgs/textfield/close_ring_fill.svg"; import openEye from "src/assets/imgs/textfield/open-eye.svg"; @@ -22,26 +22,47 @@ const TextField = ({ type = "", onKeyDown, style, - value + value, + }: TextFieldProps) => { const [showPassword, setShowPassword] = useState(false); const [textBox, setTextBox] = useState(false); - + const [internalValue, setInternalValue] = useState(value); + + const handleChange = useCallback( + (e: React.ChangeEvent) => { + setInternalValue(e.target.value); + if (onChange) { + onChange(e); + } + }, + [onChange] + ); + + const handleClear = useCallback(() => { + setInternalValue(""); + if (onChange) { + onChange({ target: { name, value: "" } } as React.ChangeEvent); + } + }, [onChange, name]); + + return ( {type === "text" ? ( - { }}/> + ) : ( { const navigate = useNavigate(); const [LoginData, setLoginData] = useState({ - id: "", - password:"", + memberId: "", + memberPassword:"", }); const [loading, setLoading] = useState(false); @@ -34,15 +38,15 @@ export const useLogin = () => { [LoginData] ); - + const [, setTokenValid] = useAtom(tokenValidAtom); const handleLogin = async () => { - if (LoginData.id === "") { + if (LoginData.memberId === "") { showToast("아이디를 입력해주세요", "INFO"); return; } - if (LoginData.password === "") { + if (LoginData.memberPassword === "") { showToast("비밀번호를 입력해주세요", "INFO"); return; } @@ -50,13 +54,15 @@ export const useLogin = () => { LoginData, { onSuccess: (data) => { + setTokenValid(true); navigate("/"); showToast("success", "로그인 성공"); token.setToken(ACCESS_TOKEN_KEY, data.data.accessToken); token.setToken(REFRESH_TOKEN_KEY, data.data.refreshToken); }, - onError: () => { - showToast("error", "로그인 실패"); + onError: (error) => { + const errorCode = error as AxiosError; + showToast("error", errorHandler.loginError(errorCode.response?.status!)); }, } ); diff --git a/src/hooks/auth/useSign.ts b/src/hooks/auth/useSign.ts index 80f1ce0..4d28f62 100644 --- a/src/hooks/auth/useSign.ts +++ b/src/hooks/auth/useSign.ts @@ -1,26 +1,26 @@ import React, { useState, useCallback } from "react"; import { Sign } from "src/types/auth/signup.type"; import { showToast } from "src/libs/toast/swal"; -import { useSignUpMutation } from "src/queries/auth/queries"; +import { useSignUpMutation, useEmailNumber } from "src/queries/auth/queries"; +import { AxiosError } from "axios"; +import { SIGNUP_DATA } from "src/constants/signup/signup.constants"; +import errorHandler from "src/utils/error/errorHandler"; export const useSignup = () => { const SignUpMutation = useSignUpMutation(); + const EmailMutation = useEmailNumber(); const [section, setSection] = useState("first"); - const [signUpData, setsignUpData] = useState({ - id: "", - password: "", - checkPasswrod: "", - name: "", - email: "", - checkNumber: "", - }); - const handleSigUpData = useCallback( - (e: React.ChangeEvent): void => { + const [signupData, setsignupData] = useState(SIGNUP_DATA); + + const handleSignupData = useCallback( + (e: React.ChangeEvent): void => { const { name, value } = e.target; - setsignUpData((prev) => ({ ...prev, [name]: value })); + + setsignupData((prev) => ({ ...prev, [name]: value })); + }, - [signUpData] + [signupData] ); const firstHandleKeyDown = (e: React.KeyboardEvent) => { @@ -28,41 +28,131 @@ export const useSignup = () => { submitSignupDataFirst(); } }; + const secondHandleKeyDown = (e: React.KeyboardEvent) => { + if (e.key === "Enter") { + submitSignupDataSecond(); + } + }; const submitSignupDataFirst = useCallback(async () => { - const { id, password, checkPasswrod } = signUpData; + const { memberId, memberPassword, memberChckPassword } = signupData; - if (id === "" || password === "" || checkPasswrod === "") { - showToast("error", "양식이 비어있습니다"); + if (memberId === "" ) { + showToast("error", "아이디가 비었습니다"); + return; + }else if( memberPassword === ""){ + showToast("error", "비밀번호가 비었습니다"); + return; + }else if(memberChckPassword === ""){ + showToast("error", "확인 비밀번호가 비었습니다"); return; } - if (password !== checkPasswrod) { + if (memberPassword !== memberChckPassword) { showToast("error", "비밀번호가 다릅니다"); } setSection("second"); - }, [signUpData]); + }, [signupData]); + + const [isWaiting, setIsWaiting] = useState(""); + + const checkEmailAuthCode = () => { + setIsWaiting("전송중"); + const { memberEmail, memberSchool } = signupData; + const domain = memberEmail.split("@")[1]; + if (memberEmail === "") { + showToast("error", "이메일을 작성해주세요"); + } else if ( + domain !== "dgsw.hs.kr" && + memberSchool !== "대구소프트웨어마이스터고" + ) { + showToast("error", "학교이메일이 다릅니다"); + setIsWaiting("전송실패"); + return; + } + // else if ( + // domain !== "bssm.hs.kr" && + // memberSchool !== "부산소프트웨어마이스터고" + // ) { + // showToast("error", "학교이메일이 다릅니다"); + // setIsWaiting("전송실패"); + // return; + // } else if ( + // domain !== "gsm.gen.hs.kr" && + // memberSchool !== "광주소프트웨어마이스터고" + // ) { + // showToast("error", "학교이메일이 다릅니다"); + // setIsWaiting("전송실패"); + // return; + // } else if ( + // domain !== "dsmhs.djsch.kr" && + // memberSchool !== "대덕소프트웨어마이스터고" + // ) { + // showToast("error", "학교이메일이 다릅니다"); + // setIsWaiting("전송실패"); + // return; + // } + const email = memberEmail; + EmailMutation.mutate(email, { + onSuccess: () => { + setIsWaiting("전송성공"); + }, + onError: (error) => { + setIsWaiting(""); + const errorCode = error as AxiosError; + + showToast("error", errorHandler.signEmailError(errorCode.response?.status!)); + + }, + }); + }; + + const emailKeydownButton = (e: React.KeyboardEvent) => { + if (e.key === "Enter") { + checkEmailAuthCode(); + } + }; const submitSignupDataSecond = useCallback(async () => { - const { name, email, checkNumber } = signUpData; - if (name === "" || email === "" || checkNumber === "") { + const { memberName, memberEmail, authCode, memberSchool } = signupData; + if ( + memberName === "" + ) { showToast("error", "형식이 비어있습니다"); return; + }else if( memberEmail === "" ){ + showToast("error", "이메일이 비었습니다"); + return; + } + else if( authCode === "" ){ + showToast("error", "인증코드가 비었습니다"); + return; } - SignUpMutation.mutate(signUpData, { + else if( memberSchool === ""){ + showToast("error", "학교가 비었습니다"); + return; + } + + SignUpMutation.mutate(signupData, { onSuccess: () => { + showToast("success", "회원가입 성공"); window.location.reload(); }, - onError: () => { - showToast("error", "회원가입 실패"); + onError: (error) => { + const errorCode = error as AxiosError; + showToast("error", errorHandler.signupError(errorCode.response?.status!)); }, }); - }, [signUpData]); + }, [signupData]); return { + isWaiting, + signupData, section, + emailKeydownButton, + secondHandleKeyDown, + checkEmailAuthCode, setSection, - signUpData, submitSignupDataSecond, - handleSigUpData, + handleSignupData, firstHandleKeyDown, submitSignupDataFirst, }; diff --git a/src/hooks/main/useMain.ts b/src/hooks/main/useMain.ts new file mode 100644 index 0000000..4f84c12 --- /dev/null +++ b/src/hooks/main/useMain.ts @@ -0,0 +1,17 @@ +import { showToast } from "@src/libs/toast/swal"; +import { useState } from "react"; +import { useGetSeniortojuniorList } from "src/queries/seniortojunior/seniortojunior.quey"; +import { pageParms } from "src/repositories/SeniortojuniorRespository/SeniortojuniorRepository"; + + +export const UseMain=()=>{ + const pageParms={ + page:1, + size:4 + } +const {data}=useGetSeniortojuniorList(pageParms); +return{ + data +} +} + diff --git a/src/libs/axios/requestHandler.ts b/src/libs/axios/requestHandler.ts index 459fdf1..ee42c92 100644 --- a/src/libs/axios/requestHandler.ts +++ b/src/libs/axios/requestHandler.ts @@ -9,8 +9,6 @@ import token from "../token/token"; const requestHandler = (config: AxiosRequestConfig): AxiosRequestConfig => { if (token.getToken(REFRESH_TOKEN_KEY) === undefined ) { - alert("세션 만료") - window.location.href = "/login"; return config; } diff --git a/src/libs/axios/responseHandler.ts b/src/libs/axios/responseHandler.ts index b2b678d..eb4d2b3 100644 --- a/src/libs/axios/responseHandler.ts +++ b/src/libs/axios/responseHandler.ts @@ -7,8 +7,6 @@ import { ACCESS_TOKEN_KEY, REFRESH_TOKEN_KEY, } from "src/constants/token/token.constants"; -import { useQueryClient } from "react-query"; - let isRefreshing = false; let refreshSubscribers: ((accessToken: string) => void)[] = []; @@ -22,53 +20,50 @@ const addRefreshSubscriber = (callback: (accessToken: string) => void) => { }; const ResponseHandler = async (error: AxiosError) => { - if (error.response) { const { config: originalRequest, response: { status }, } = error; - const usingAccessToken = Token.getToken(ACCESS_TOKEN_KEY); - const usingRefreshToken = Token.getToken(REFRESH_TOKEN_KEY); + const usingAccessToken = Token.getToken(ACCESS_TOKEN_KEY); + const usingRefreshToken = Token.getToken(REFRESH_TOKEN_KEY); - if ( - status === 401 && - usingAccessToken!== undefined && - usingRefreshToken!== undefined && - !isRefreshing - ) { - isRefreshing = true; + if ( + status === 401 && + usingAccessToken !== undefined && + usingRefreshToken !== undefined && + !isRefreshing + ) { + isRefreshing = true; + try { + const { data: newAccessToken } = + await AuthRepositoryImpl.refreshAccessToken({ + refreshToken: usingRefreshToken, + }); - try { - - const { accessToken: newAccessToken } = - await AuthRepositoryImpl.refreshAccessToken({ - refreshToken: usingRefreshToken, - }); - SOPOAxios.defaults.headers.common[ - REQUEST_TOKEN_KEY - ] = `Bearer ${newAccessToken}`; - - Token.setToken(ACCESS_TOKEN_KEY, newAccessToken); + SOPOAxios.defaults.headers.common[ + REQUEST_TOKEN_KEY + ] = `Bearer ${newAccessToken}`; + + Token.setToken(ACCESS_TOKEN_KEY, newAccessToken.accessToken); - isRefreshing = false; - onTokenRefreshed(newAccessToken); - - return new Promise((resolve) => { - addRefreshSubscriber((accessToken: string) => { - originalRequest!.headers![REQUEST_TOKEN_KEY] = `Bearer ${accessToken}`; - resolve(SOPOAxios(originalRequest!)); + isRefreshing = false; + onTokenRefreshed(newAccessToken.accessToken); + + return new Promise((resolve) => { + addRefreshSubscriber((accessToken: string) => { + originalRequest!.headers![ + REQUEST_TOKEN_KEY + ] = `Bearer ${accessToken}`; + resolve(SOPOAxios(originalRequest!)); + }); }); - }); - } catch (error) { - console.error("Failed to refresh access token:", error); - Token.clearToken(); - window.alert("세션이 만료되었습니다."); - window.location.href = "/login"; + } catch (error) { + Token.clearToken(); + } } } - } return Promise.reject(error); }; diff --git a/src/libs/tokenCheck/tokenCheck.ts b/src/libs/tokenCheck/tokenCheck.ts new file mode 100644 index 0000000..53ac2cf --- /dev/null +++ b/src/libs/tokenCheck/tokenCheck.ts @@ -0,0 +1,17 @@ +import { useAtom, useSetAtom } from 'jotai'; +import { tokenValidAtom } from 'src/store/token/token.atom'; + +export const tokenCheck = () => { + const setTokenValid = useSetAtom(tokenValidAtom); + const [tokenValid] = useAtom(tokenValidAtom); + + const setTokenCheck = (token: boolean): void => { + setTokenValid(token); + }; + + const getTokenCheck = () => { + return tokenValid; + }; + + return { setTokenCheck, getTokenCheck }; +}; diff --git a/src/pages/wirte/page.style.ts b/src/pages/wirte/page.style.ts index d1e8052..10ece0b 100644 --- a/src/pages/wirte/page.style.ts +++ b/src/pages/wirte/page.style.ts @@ -2,8 +2,8 @@ import style from "react-syntax-highlighter/dist/esm/styles/hljs/a11y-dark"; import styled from "styled-components"; export const MarkdownEditorWrap = styled.div` - /* width: 100vw; */ - height: 100vh; + width: 100vw; + /* height: 100vh; */ justify-content: center; align-items: center; diff --git a/src/pages/wirte/page.tsx b/src/pages/wirte/page.tsx index 188de1b..f5b1840 100644 --- a/src/pages/wirte/page.tsx +++ b/src/pages/wirte/page.tsx @@ -6,11 +6,9 @@ import * as S from "src/pages/wirte/page.style" const Index: React.FC = () => { return ( - - ); }; diff --git a/src/queries/auth/queries.ts b/src/queries/auth/queries.ts index 49c2600..5e3deaa 100644 --- a/src/queries/auth/queries.ts +++ b/src/queries/auth/queries.ts @@ -8,4 +8,8 @@ export const useLoginMutation = () => { export const useSignUpMutation = ()=>{ const mutation = useMutation(AuthRepositoryImpl.signUp); return mutation; -} \ No newline at end of file +} +export const useEmailNumber = ()=>{ + const mutation = useMutation(AuthRepositoryImpl.emailNumber); + return mutation; +} diff --git a/src/queries/profile/profile.query.ts b/src/queries/profile/profile.query.ts new file mode 100644 index 0000000..20e1e6b --- /dev/null +++ b/src/queries/profile/profile.query.ts @@ -0,0 +1,24 @@ +import { useMutation, useQuery } from "react-query"; +import profileRepositoryImpl from "src/repositories/profileRepository/profileRepositoryImpl"; +import { profileType } from "src/types/profile/profile.type"; +import { AxiosError } from "axios"; +import { sopoQueryKey } from "../queryKeys"; + +export const usePathProfileMutation = () => { + const mutation = useMutation(profileRepositoryImpl.patchProfile); + return mutation; +}; +export const useGetProfileList = () => { + const useGetProfile = useQuery< + profileType, + AxiosError, + profileType, + string[] + >({ + queryKey: [sopoQueryKey.profile.getProfile], + queryFn: () => profileRepositoryImpl.getProfileInfo(), + staleTime: 1 * 60 * 1000, + cacheTime: 1 * 60 * 1000, + }); + return useGetProfile; +}; diff --git a/src/queries/queryKeys.ts b/src/queries/queryKeys.ts new file mode 100644 index 0000000..1b261d6 --- /dev/null +++ b/src/queries/queryKeys.ts @@ -0,0 +1,9 @@ +export const sopoQueryKey={ + seniortojunior:{ + getSeniortojunior:"/bord" + }, + profile:{ + getProfile:"/member", + + } +} \ No newline at end of file diff --git a/src/queries/seniortojunior/seniortojunior.quey.ts b/src/queries/seniortojunior/seniortojunior.quey.ts new file mode 100644 index 0000000..5770662 --- /dev/null +++ b/src/queries/seniortojunior/seniortojunior.quey.ts @@ -0,0 +1,28 @@ +import { useQuery } from "react-query"; +import { AxiosError } from "axios"; +import { sopoQueryKey } from "../queryKeys"; +import { + SeniortojuniorResponse, +} from "src/types/seniortojunior/seniortojunior.type"; +import SeniortojuniorRepositoryImpl from "src/repositories/SeniortojuniorRespository/SeniortojuniorRepositoryImpl"; +import { pageParms } from "src/repositories/SeniortojuniorRespository/SeniortojuniorRepository"; + +export const useGetSeniortojuniorList = (pageParms:pageParms) => { + const useGetSeniortojunior = useQuery< + SeniortojuniorResponse, + AxiosError, + SeniortojuniorResponse, + string[] + >({ + queryKey: [sopoQueryKey.seniortojunior.getSeniortojunior], + queryFn: () => SeniortojuniorRepositoryImpl.getSeniortojunior(pageParms), + staleTime: 1 * 60 * 1000, + cacheTime: 1 * 60 * 1000, + }); + return useGetSeniortojunior; +}; +// export const usePostSeniortojunior=()=>{ +// cosnt mutate = useMutation({ +// mutationFn:() +// }) +// } diff --git a/src/repositories/SeniortojuniorRespository/SeniortojuniorRepository.ts b/src/repositories/SeniortojuniorRespository/SeniortojuniorRepository.ts new file mode 100644 index 0000000..ed5d82e --- /dev/null +++ b/src/repositories/SeniortojuniorRespository/SeniortojuniorRepository.ts @@ -0,0 +1,9 @@ +import { SeniortojuniorResponse, SeniortojuniorTypes } from "src/types/seniortojunior/seniortojunior.type"; + +export interface SeniortojuniorRepository{ + getSeniortojunior(pageParms:pageParms):Promise +} +export interface pageParms{ + page:number; + size:number; +} diff --git a/src/repositories/SeniortojuniorRespository/SeniortojuniorRepositoryImpl.ts b/src/repositories/SeniortojuniorRespository/SeniortojuniorRepositoryImpl.ts new file mode 100644 index 0000000..f71a35e --- /dev/null +++ b/src/repositories/SeniortojuniorRespository/SeniortojuniorRepositoryImpl.ts @@ -0,0 +1,16 @@ +import SOPOAxios from "src/libs/axios/customAxios"; +import { SeniortojuniorResponse } from "src/types/seniortojunior/seniortojunior.type"; +import {SeniortojuniorRepository ,pageParms} from "./SeniortojuniorRepository"; + +class SeniortojuniorRepositoryImpl implements SeniortojuniorRepository{ + public async getSeniortojunior(pageParms:pageParms):Promise{ + try { + const { data } = await SOPOAxios.get("/board",{params:pageParms}); + return data; + } catch (error) { + console.error(error); + throw error; + } + } +} +export default new SeniortojuniorRepositoryImpl; \ No newline at end of file diff --git a/src/repositories/authRepository/authRepository.ts b/src/repositories/authRepository/authRepository.ts index d8bce99..32841db 100644 --- a/src/repositories/authRepository/authRepository.ts +++ b/src/repositories/authRepository/authRepository.ts @@ -1,21 +1,24 @@ -import { LoginResponse } from "src/types/auth/login.types"; +import { LoginResponse, Login } from "src/types/auth/login.types"; import { Sign } from "src/types/auth/signup.type"; export interface AuthRepository { - login(loginData: Login): Promise; + login(loginData: LoginParmas): Promise; signUp(signUpData:SignUpParams): Promise; + emailNumber(email:string):Promise; refreshAccessToken(refreshToken: { refreshToken: string; }): Promise; } -export interface Login { - id: string; - password: string; -}; +export interface LoginParmas extends Login{} +export interface emailRespose{ + authCode:string; +} export interface NewAccessTokenResponse { - accessToken: string + data:{ + accessToken: string + } }; export interface SignUpParams extends Sign{}; diff --git a/src/repositories/authRepository/authRepositoryImpl.ts b/src/repositories/authRepository/authRepositoryImpl.ts index 8fbacbb..3d6b3f0 100644 --- a/src/repositories/authRepository/authRepositoryImpl.ts +++ b/src/repositories/authRepository/authRepositoryImpl.ts @@ -1,28 +1,57 @@ import { LoginResponse } from "src/types/auth/login.types"; -import { AuthRepository, NewAccessTokenResponse, Login, SignUpParams } from "./authRepository"; -import config from "src/config/config.json" +import { + AuthRepository, + NewAccessTokenResponse, + LoginParmas, + SignUpParams, + emailRespose +} from "./authRepository"; +import config from "src/config/config.json"; import axios from "axios"; -class authRepositoryImpl implements AuthRepository{ - public async login(loginData: Login): Promise{ - const { data } = await axios.post(`${config.server}/auth`, loginData); - return data; +class authRepositoryImpl implements AuthRepository { + public async login(loginData: LoginParmas): Promise { + try { + const { data } = await axios.post(`${config.server}/auth/sign_in`, loginData); + return data; + } catch (error) { + console.error(error); + throw new Error('Failed to login'); + } + } + + public async signUp(signUpData: SignUpParams): Promise { + try { + const { data } = await axios.post(`${config.server}/auth/sign_up`, signUpData); + return data; + } catch (error) { + console.error(error); + throw new Error('Failed to sign up'); } - public async signUp(signUpData:SignUpParams ):Promise{ - const {data} = await axios.post(`${config.server}/sign`,signUpData) + } + + public async emailNumber(email: string): Promise { + try { + const { data } = await axios.post(`${config.server}/email?email=${email}`); return data; + } catch (error) { + console.error( error); + throw new Error('Failed to verify email'); } - - public async refreshAccessToken(refreshToken: { - refreshToken: string; - }): Promise { - const { data } = await axios.post( - `${config.server}/auth/refresh`, - refreshToken - ); - return data; - } - + } + public async refreshAccessToken(refreshToken: { refreshToken: string }): Promise { + try { + const { data } = await axios.post( + `${config.server}/re_provide`, + refreshToken + ); + return data; + } catch (error) { + console.error('Error occurred during token refresh:', error); + throw new Error('Failed to refresh access token'); + } + } } -export default new authRepositoryImpl(); \ No newline at end of file + +export default new authRepositoryImpl(); diff --git a/src/repositories/profileRepository/profileRepository.ts b/src/repositories/profileRepository/profileRepository.ts new file mode 100644 index 0000000..bba9a1a --- /dev/null +++ b/src/repositories/profileRepository/profileRepository.ts @@ -0,0 +1,22 @@ +import { profileType } from "src/types/profile/profile.type"; + +export interface ProfileRepository { + getProfileInfo(): Promise; +} + +export interface patchProfileParam { + memberName: string; + memberEmail: string; + authCode: string; + memberPassword: string; +} + +// export interface emailRespose{ +// authCode:string; +// } + +// export interface NewAccessTokenResponse { +// accessToken: string +// }; + +// export interface SignUpParams extends Sign{}; diff --git a/src/repositories/profileRepository/profileRepositoryImpl.ts b/src/repositories/profileRepository/profileRepositoryImpl.ts new file mode 100644 index 0000000..b7b08d7 --- /dev/null +++ b/src/repositories/profileRepository/profileRepositoryImpl.ts @@ -0,0 +1,14 @@ +import { ProfileRepository,patchProfileParam } from "./profileRepository" +import { profileType } from "src/types/profile/profile.type" +import SOPOAxios from "src/libs/axios/customAxios"; + +class ProfileRepositoryimpl implements ProfileRepository{ + public async getProfileInfo(): Promise { + const { data } = await SOPOAxios.get("/profile"); + return data; + } + public async patchProfile(pramsData:patchProfileParam):Promise{ + await SOPOAxios.patch("/profile",pramsData) + } +} +export default new ProfileRepositoryimpl \ No newline at end of file diff --git a/src/store/token/token.atom.ts b/src/store/token/token.atom.ts new file mode 100644 index 0000000..84f84fa --- /dev/null +++ b/src/store/token/token.atom.ts @@ -0,0 +1,2 @@ +import { atom } from 'jotai' +export const tokenValidAtom = atom(false); \ No newline at end of file diff --git a/src/types/auth/login.types.ts b/src/types/auth/login.types.ts index c9b85e8..179b5ef 100644 --- a/src/types/auth/login.types.ts +++ b/src/types/auth/login.types.ts @@ -12,6 +12,6 @@ export interface Props { } export interface Login{ - id:string; - password:string; + memberId:string; + memberPassword:string; } \ No newline at end of file diff --git a/src/types/auth/signup.type.ts b/src/types/auth/signup.type.ts index 92662cd..789351b 100644 --- a/src/types/auth/signup.type.ts +++ b/src/types/auth/signup.type.ts @@ -1,9 +1,10 @@ -export interface Sign{ - id:string; - password:string; - checkPasswrod:string; - name:string; - email:string; - checkNumber:string; +export interface Sign { + memberId: string; + memberName: string; + memberEmail: string; + authCode: string; + memberPassword: string; + memberChckPassword: string; + memberSchool: string; + memberFcmToken: string; } - diff --git a/src/types/profile/profile.type.ts b/src/types/profile/profile.type.ts new file mode 100644 index 0000000..6a67a3b --- /dev/null +++ b/src/types/profile/profile.type.ts @@ -0,0 +1,8 @@ +export interface profileType { + data: { + memberId: string; + memberName: string; + memberEmail: string; + memberSchool: string; + }; +} diff --git a/src/types/seniortojunior/seniortojunior.type.ts b/src/types/seniortojunior/seniortojunior.type.ts new file mode 100644 index 0000000..ece075c --- /dev/null +++ b/src/types/seniortojunior/seniortojunior.type.ts @@ -0,0 +1,10 @@ +export interface SeniortojuniorTypes { + boardId: number; + boardTitle: string; + boardContent: string; + boardLikeCount: number; +} +export interface SeniortojuniorResponse extends Response{ + data:SeniortojuniorTypes[]; +} + diff --git a/src/types/util/response.type.ts b/src/types/util/response.type.ts index ab73193..a0381b3 100644 --- a/src/types/util/response.type.ts +++ b/src/types/util/response.type.ts @@ -1,4 +1,5 @@ export interface Response { status: number; message: string; - } \ No newline at end of file + } + \ No newline at end of file diff --git a/src/utils/error/errorHandler.ts b/src/utils/error/errorHandler.ts new file mode 100644 index 0000000..7745c29 --- /dev/null +++ b/src/utils/error/errorHandler.ts @@ -0,0 +1,52 @@ +import { AxiosError } from "axios"; +import { stat } from "fs"; + +class ErrorHandler { + loginError = (status: number) => { + switch (status) { + case 400: + return "탈퇴된 멤버입니다."; + case 401: + return "멤버가 일치하지 않습니다."; + case 403: + return"비밀번호가 옳지 않습니다"; + case 404: + return "멤버를 찾을수 없습니다."; + case 500: + return "서버 오류가 발생하였습니다."; + default: + return "로그인에 실패하였습니다."; + } + }; + + signupError = (status: number) => { + switch (status) { + case 400: + return "인증코드가 일치하지 않습니다."; + case 404: + return "이미 존재하는 멤버입니다."; + case 500: + return "서버 오류가 발생하였습니다."; + default: + return "회원가입에 실패하였습니다."; + } + + }; + signEmailError = (status:number)=>{ + switch (status) { + case 403: + return "이메일을 보낼 수 없습니다."; + case 409: + return "이메일이 이미 존재합니다"; + case 404: + return "인증코드 에러"; + case 500: + return "서버 에러"; + default: + return "이메일 전송 싫패"; + } + } + +} + +export default new ErrorHandler(); \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index e87308c..ff3e80a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1123,6 +1123,13 @@ resolved "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz" integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA== +"@babel/runtime@^7.10.5": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.25.0.tgz#3af9a91c1b739c569d5d80cc917280919c544ecb" + integrity sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw== + dependencies: + regenerator-runtime "^0.14.0" + "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.3", "@babel/runtime@^7.21.0", "@babel/runtime@^7.23.2", "@babel/runtime@^7.23.8", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": version "7.24.7" resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.7.tgz" @@ -2238,7 +2245,7 @@ dependencies: "@types/react" "*" -"@types/react@*", "@types/react@^18.0.0": +"@types/react@*", "@types/react@^18.3.3": version "18.3.3" resolved "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz" integrity sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw== @@ -2304,6 +2311,13 @@ resolved "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.5.tgz" integrity sha512-1Xve+NMN7FWjY14vLoY5tL3BVEQ/n42YLwaqJIPYhotZ9uBHt87VceMwWQpzmdEt2TNXIorIFG+YeCUUW7RInw== +"@types/swiper@^6.0.0": + version "6.0.0" + resolved "https://registry.yarnpkg.com/@types/swiper/-/swiper-6.0.0.tgz#9934ecd569611b660a2a9bf200f25ce5ba4b4d63" + integrity sha512-QPZRgxZ+ivXXtzV43B3LxpXUIC7FE/EoKM+rtxngmgt2M7eeUYypZhyqZD8UxJtlBcUDw/ATGoVeSNpvBBrz2w== + dependencies: + swiper "*" + "@types/testing-library__jest-dom@^5.9.1": version "5.14.9" resolved "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.9.tgz" @@ -7001,6 +7015,14 @@ markdown-table@^3.0.0: resolved "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz" integrity sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw== +match-sorter@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/match-sorter/-/match-sorter-4.2.1.tgz#575b4b3737185ba9518b67612b66877ea0b37358" + integrity sha512-s+3h9TiZU9U1pWhIERHf8/f4LmBN6IXaRgo2CI17+XGByGS1GvG5VvXK9pcGyCjGe3WM3mSYRC3ipGrd5UEVgw== + dependencies: + "@babel/runtime" "^7.10.5" + remove-accents "0.4.2" + match-sorter@^6.0.2: version "6.3.4" resolved "https://registry.npmjs.org/match-sorter/-/match-sorter-6.3.4.tgz" @@ -8912,9 +8934,16 @@ react-markdown@^9.0.1: unist-util-visit "^5.0.0" vfile "^6.0.0" +react-query-devtools@^2.6.3: + version "2.6.3" + resolved "https://registry.yarnpkg.com/react-query-devtools/-/react-query-devtools-2.6.3.tgz#f7c982839d4b0001cee4d5ddfa826493c2f6341f" + integrity sha512-pSvWq5Q8zgIP7QbF0+4BerCHLaLn5HPzce7sIXYqz4XEizcYJHkJtcrAwn6bUkCu5JmAt1Y7fViQtZwOIG2SYA== + dependencies: + match-sorter "^4.1.0" + react-query@^3.39.3: version "3.39.3" - resolved "https://registry.npmjs.org/react-query/-/react-query-3.39.3.tgz" + resolved "https://registry.yarnpkg.com/react-query/-/react-query-3.39.3.tgz#4cea7127c6c26bdea2de5fb63e51044330b03f35" integrity sha512-nLfLz7GiohKTJDuT4us4X3h/8unOh+00MLb2yJoGTPjxKs2bc1iDhkNx2bd5MKklXnOD3NrVZ+J2UXujA5In4g== dependencies: "@babel/runtime" "^7.5.5" @@ -9197,6 +9226,11 @@ remark-stringify@^11.0.0: mdast-util-to-markdown "^2.0.0" unified "^11.0.0" +remove-accents@0.4.2: + version "0.4.2" + resolved "https://registry.yarnpkg.com/remove-accents/-/remove-accents-0.4.2.tgz#0a43d3aaae1e80db919e07ae254b285d9e1c7bb5" + integrity sha512-7pXIJqJOq5tFgG1A2Zxti3Ht8jJF337m4sowbuHsW30ZnkQFnDzy9qBNhgzX8ZLW4+UBcXiiR7SwR6pokHsxiA== + remove-accents@0.5.0: version "0.5.0" resolved "https://registry.npmjs.org/remove-accents/-/remove-accents-0.5.0.tgz" @@ -10052,6 +10086,11 @@ sweetalert2@^11.11.1: resolved "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.11.1.tgz" integrity sha512-7jumu0I0/QdRa5R7K1mh05ZdhmsMV6rZOVtjpratZGidxyJD4Sn7rDSA+zmKHzvMef9hVTwPmDU3VxnvhVQMNg== +swiper@*, swiper@^11.1.8: + version "11.1.8" + resolved "https://registry.yarnpkg.com/swiper/-/swiper-11.1.8.tgz#16a9ce0441a45cc8d754280361a100e530364583" + integrity sha512-sBFp7fA+IfZ/7BMcg8/JSEqDD1qZXBUyliT76yk3zIYVu2fMwFVAghhAJ9vBM5tJUtHW5qcD0pmeEGQs1EK14w== + symbol-tree@^3.2.4: version "3.2.4" resolved "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz" @@ -10587,7 +10626,7 @@ vary@~1.1.2: resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz" integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== -vfile-message@^4.0.0: +vfile-message@^4.0.0, vfile-message@^4.0.2: version "4.0.2" resolved "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz" integrity sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw== @@ -10595,14 +10634,6 @@ vfile-message@^4.0.0: "@types/unist" "^3.0.0" unist-util-stringify-position "^4.0.0" -vfile-message@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-4.0.2.tgz#c883c9f677c72c166362fd635f21fc165a7d1181" - integrity sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw== - dependencies: - "@types/unist" "^3.0.0" - unist-util-stringify-position "^4.0.0" - vfile@^6.0.0: version "6.0.2" resolved "https://registry.npmjs.org/vfile/-/vfile-6.0.2.tgz"