diff --git a/src/api/auth.ts b/src/api/auth.ts index bc80e3cb..d6bf6a1c 100644 --- a/src/api/auth.ts +++ b/src/api/auth.ts @@ -8,24 +8,14 @@ export const signUp = async (formData: SignUpForm) => { return response.data; }; -// 로그아웃 -// export const signOut = async () => { -// const user = userStorage.get(); -// const response = await instance.delete('/api/member/logout', { -// data: { -// refreshToken: user?.refreshToken, -// }, -// }); -// return response; -// }; - // 재발급 -// export const retryToken = async (refreshToken: string) => { -// const response = await instance.post('/api/member/refreshToken', { -// refreshToken, -// }); -// return response.data; -// }; +export const retryToken = async (refreshToken: string) => { + // const response = await instance.post('/api/member/refreshToken', { + const response = await instance.post('/api/member/refreshToken', { + refreshToken, + }); + return response.data; +}; // 닉네임 중복 체크 export const CheckDuplicatedName = async (name: string) => { diff --git a/src/api/index.ts b/src/api/index.ts index 92615f1d..dbb4303a 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -1,6 +1,7 @@ import axios from 'axios'; import { getUserTokens } from 'repository/auth'; import { userStorage } from 'repository/userStorage'; +import { retryToken } from './auth'; export const instance = axios.create({ baseURL: 'http://localhost:8080', @@ -19,3 +20,55 @@ instance.interceptors.request.use( return Promise.reject(error); }, ); + +instance.interceptors.response.use( + response => { + return response; + }, + async error => { + const { config, response } = error; + console.log(config); + console.log(response); + if (response.status == 401) { + // 401(Unauthorized): 클라이언트가 인증되지 않았기 때문에 요청을 정상적으로 처리할 수 없음 + const originalRequest = config; + const tokens = getUserTokens(); + + if (!tokens) { + return window.location.replace('/'); + } + + try { + // if (response.status == 401 && response.data.message == "기간이 만료된 토큰") + const { accessToken: newAccessToken, refreshToken: newRefreshToken } = + await retryToken(tokens.refreshToken); + // RefreshToken으로 AccessToken 재발급 요청 + + const newUser = { + accessToken: newAccessToken, + refreshToken: newRefreshToken, + }; + + userStorage.set(newUser); + // 발급 받은 AccessToken을 state에 재저장 + + axios.defaults.headers.common.Authorization = `Bearer ${newAccessToken}`; + originalRequest.headers.Authorization = `Bearer ${newAccessToken}`; + return axios(originalRequest); + // 방금 실패했던 API 재요청 + } catch (error) { + userStorage.remove(); + return window.location.replace('/'); + } + } + + if (error.response.status == 403) { + // 403(Forbidden): 클라이언트가 해당 요청에 대한 권한이 없음 + throw new Error('접근 권한이 없습니다.'); + } + + throw error.response.status; + // throw error.response.error; + // TODO: 예외 처리 개선 + }, +); diff --git a/src/api/mypage.ts b/src/api/mypage.ts new file mode 100644 index 00000000..977d561d --- /dev/null +++ b/src/api/mypage.ts @@ -0,0 +1,7 @@ +import { instance } from 'api'; +import { MyPage } from 'types/api'; + +export const getMyPage = async (): Promise => { + const response = await instance.get(`/api/mypage`); + return response.data; +}; diff --git a/src/api/problem.ts b/src/api/problem.ts index 3580c3c5..4f3e297f 100644 --- a/src/api/problem.ts +++ b/src/api/problem.ts @@ -1,18 +1,9 @@ -/* -------- POST 요청 -------- */ import { instance } from 'api'; import { FieldValues } from 'react-hook-form'; // 문제 생성하기 & 대량 문제 생성하기 export const problemSet = async (formData: FieldValues) => { - if (formData.length === 1) { - const response = await instance.post('/api/question', formData[0]); - return response.data; - } + const response = await instance.post('/api/questions', formData); - if (formData.length > 1) { - const response = await instance.post('/api/questions', formData); - return response.data; - } - - throw new Error('문제 생성에 실패했습니다.'); + return response.data; }; diff --git a/src/api/request.ts b/src/api/request.ts index 878b20ea..56f6ffec 100644 --- a/src/api/request.ts +++ b/src/api/request.ts @@ -1,39 +1,53 @@ import { instance } from 'api'; import { FieldValues } from 'react-hook-form'; -// import { RequestDetail, ToggleRequestList } from 'types/api'; - -/* -------- Get 요청 -------- */ +import { RequestDetail, ToggleRequestList } from 'types/api'; // 게시판 글 조회 -// export const getRequest = async ( -// id: string | undefined, -// ): Promise => { -// const response = await instance.get(`/api/request/${id}`); -// return response.data; -// }; +export const getRequest = async ( + id: string | undefined, +): Promise => { + const response = await instance.get(`/api/request/${id}`); + return response.data; +}; // 게시판 전체 리스트 / 내가 요청한 문제 조회 -// export const getToggleRequestList = async ({ -// page = 0, -// size = 10, -// query = 'list', -// }): Promise => { -// const response = await instance.get( -// `/api/request/${query}?page=${page}&size=${size}`, -// ); -// return response.data; -// }; - -/* -------- POST 요청 -------- */ +export const getToggleRequestList = async ({ + page = 0, + size = 10, + sort = 'list', +}): Promise => { + const response = await instance.get( + `/api/request/requests?page=${page}&size=${size}&$sort=${sort}`, + ); + return response.data; +}; +export const getRequestListTest = () => { + const response = instance.get(`/api/request/requests`); + return response; +}; // 게시판 문제 요청글 생성 export const createRequest = (RequestForm: FieldValues) => { - const response = instance.post('/api/request/create', RequestForm); + const response = instance.post('/api/request', RequestForm); return response; }; -// 게시글 상태 수정 +// 게시글 상태(승인/대기) 수정 export const approveRequest = (RequestForm: FieldValues) => { - const response = instance.post('/api/request/approve', RequestForm); + const response = instance.put('/api/request/approve', RequestForm); return response; }; + +// 게시글 수정 +export const editRequest = (RequestForm: FieldValues) => { + const response = instance.put('/api/request', RequestForm); + return response; +}; + +// 게시글 삭제 +export const deleteRequest = async ( + id: string | undefined, +): Promise => { + const response = await instance.delete(`/api/request/${id}`); + return response.data; +}; diff --git a/src/assets/CSutdybanner.gif b/src/assets/CSutdybanner.gif index a70c0bae..4b00ba3b 100644 Binary files a/src/assets/CSutdybanner.gif and b/src/assets/CSutdybanner.gif differ diff --git a/src/components/NavLinkStyles.ts b/src/components/NavLinkStyles.ts index 7f948ab8..3a1157e0 100644 --- a/src/components/NavLinkStyles.ts +++ b/src/components/NavLinkStyles.ts @@ -1,12 +1,15 @@ import { NavLink } from 'react-router-dom'; import styled from 'styled-components'; import { FONT } from 'constants/Font'; +import { COLOR } from 'constants/Color'; export const StyleNavLink = styled(NavLink)` &.active { font-weight: bold; } + font-size: ${FONT.REGULAR_14}; + color: ${COLOR.BLACK}; &.mypage { font-size: ${FONT.REGULAR_14}; padding: 0.5rem; diff --git a/src/pages/Admin/common/index.tsx b/src/components/admin/List/index.tsx similarity index 100% rename from src/pages/Admin/common/index.tsx rename to src/components/admin/List/index.tsx diff --git a/src/pages/Admin/common/style.ts b/src/components/admin/List/style.ts similarity index 100% rename from src/pages/Admin/common/style.ts rename to src/components/admin/List/style.ts diff --git a/src/components/commons/Container/index.tsx b/src/components/commons/Container/index.tsx index 7618cf4c..e81b7610 100644 --- a/src/components/commons/Container/index.tsx +++ b/src/components/commons/Container/index.tsx @@ -3,7 +3,7 @@ import * as S from './style'; const Container = ({ children }: React.PropsWithChildren) => { return ( - + {children} diff --git a/src/components/commons/Header/Header.tsx b/src/components/commons/Header/Header.tsx index 17762d86..91916937 100644 --- a/src/components/commons/Header/Header.tsx +++ b/src/components/commons/Header/Header.tsx @@ -9,19 +9,27 @@ import { openModal } from 'hooks/@redux/modalSlice'; import { useSignOut } from 'hooks/@query/useSignOut'; import { logout } from 'hooks/@redux/authSlice'; import useModal from 'hooks/useModal'; -import Modal from 'components/unit/Modal'; -import SignModal from '../Modal/SignModal'; +import Modal from '../../unit/Modal'; import SignInModal from 'components/unit/SignIn'; +import SignModal from '../Modal/SignModal'; +import SignUp from 'components/unit/SignUp'; +import { useState } from 'react'; const Header = () => { const { modalIsOpen, toggleModal } = useModal(); - const isAuthenticated = useSelector( - (state: any) => state.auth.isAuthenticated, - ); + const [signupModal, setSignupModal] = useState(true); + // const isAuthenticated = useSelector( + // (state: any) => state.auth.isAuthenticated, + // ); const { mutate: signOut } = useSignOut(); const openModal = () => { toggleModal(); + setSignupModal(false); + }; + const openSignupModal = () => { + toggleModal(); + setSignupModal(true); }; return ( @@ -34,28 +42,6 @@ const Header = () => { - - {modalIsOpen && ( - - - - - - )} - {isAuthenticated ? ( - <> - - 마이페이지 - - ) : ( - <> - - 회원가입 - - )} - - - @@ -78,7 +64,34 @@ const Header = () => { - + + {modalIsOpen && ( + + + + + + )} + {modalIsOpen && signupModal && ( + + + + + + )} + {/* {isAuthenticated ? ( + <> */} + {/* + 마이페이지 + + ) : ( + <> */} + + + {/* + )} */} + + ); }; diff --git a/src/components/commons/Header/style.ts b/src/components/commons/Header/style.ts index e4d012bd..13685391 100644 --- a/src/components/commons/Header/style.ts +++ b/src/components/commons/Header/style.ts @@ -6,9 +6,15 @@ export const Wrapper = styled.header` display: flex; align-items: center; width: 100%; - padding: 2rem 0; + padding: 1.5rem 0; justify-content: space-between; background-color: ${COLOR.WHITE}; + border-bottom: 1px solid #e9e9e9; + position: sticky; + top: 0; + left: 0; + width: 100%; + z-index: 99; `; export const LogoWrap = styled.h1` @@ -23,7 +29,7 @@ export const Nav = styled.nav` export const NavList = styled.ul` display: flex; justify-content: center; - font-size: ${FONT.REGULAR_16}; + font-size: ${FONT.REGULAR_14}; color: #181818; `; @@ -35,13 +41,13 @@ export const NavItem = styled.li` & > a { display: inline-block; padding: 0.5rem 1.5rem; - color: ${COLOR.BLACK}; } `; export const Sign = styled.div` display: flex; padding-right: 1.8rem; + align-items: center; & > button { padding: 0.5rem; font-size: ${FONT.REGULAR_14}; @@ -51,14 +57,3 @@ export const Sign = styled.div` margin-right: 1.4rem; } `; - -export const NavHeader = styled.header` - border-bottom: 1px solid #e9e9e9; - position: sticky; - top: 0; - left: 0; - width: 100%; - padding: 1rem 0 1.5rem 0; - background-color: ${COLOR.WHITE}; - z-index: 99; -`; diff --git a/src/components/commons/Input/index.tsx b/src/components/commons/Input/index.tsx new file mode 100644 index 00000000..ff51bd62 --- /dev/null +++ b/src/components/commons/Input/index.tsx @@ -0,0 +1,62 @@ +import { FieldErrors, FieldValues, UseFormRegister } from 'react-hook-form'; +import * as Styled from './style'; + +interface InputProps { + id: string; + label?: string; + type?: string; + disabled?: boolean; + required?: boolean; + placeholder?: string; + register: UseFormRegister; + errors: FieldErrors; + defaultValue?: string; + pattern?: { + value: RegExp; + message: string; + }; + onErrorMsg?: boolean; + smallLabel?: boolean; +} + +const Input = ({ + id, + label, + type = 'text', + disabled, + required, + register, + errors, + placeholder, + defaultValue, + pattern, + onErrorMsg, + smallLabel, +}: InputProps) => { + return ( + + {label && ( + + {label} + + )} + + {onErrorMsg && errors[id] && ( + + {errors[id]?.message as string} + + )} + + ); +}; + +export default Input; diff --git a/src/components/commons/Input/style.ts b/src/components/commons/Input/style.ts new file mode 100644 index 00000000..3bffdf22 --- /dev/null +++ b/src/components/commons/Input/style.ts @@ -0,0 +1,32 @@ +import styled, { css } from 'styled-components'; +import { FONT } from 'constants/Font'; +import { COLOR } from 'constants/Color'; +import { InputStyleProps } from 'types/style'; + +export const Field = styled.div` + display: flex; + flex-direction: column; +`; + +export const Label = styled.label<{ smallLabel?: boolean }>` + ${({ smallLabel }) => (smallLabel ? FONT.BOLD_14 : FONT.BOLD_20)} +`; + +export const Input = styled.input` + ${({ type }) => + type === 'text' && + css` + margin-top: 1rem; + padding: 1.2rem; + font-size: ${FONT.REGULAR_18}; + border-radius: 0.4rem; + border: 0.16rem solid + ${({ errors, id }) => + errors[id] ? `${COLOR.RED}` : `${COLOR.GRAY_50};`}; + `} +`; + +export const ErrorMsg = styled.span` + ${FONT.BOLD_14}; + color: ${COLOR.RED}; +`; diff --git a/src/components/commons/Layout.tsx b/src/components/commons/Layout.tsx index 8c5f5a12..6d666808 100644 --- a/src/components/commons/Layout.tsx +++ b/src/components/commons/Layout.tsx @@ -16,6 +16,5 @@ export default Layout; const Wrapper = styled.div` position: relative; - max-width: 1200px; - margin: 0 auto; + min-height: 100vh; `; diff --git a/src/components/commons/Modal/AuthModal/style.ts b/src/components/commons/Modal/AuthModal/style.ts new file mode 100644 index 00000000..7de7afca --- /dev/null +++ b/src/components/commons/Modal/AuthModal/style.ts @@ -0,0 +1,74 @@ +import { COLOR } from 'constants/Color'; +import styled from 'styled-components'; + +export const Container = styled.div` + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + position: fixed; + top: 50%; + left: 50%; + z-index: 100; + width: 58rem; + height: 57rem; + border-radius: 3.2rem; + background-color: ${COLOR.WHITE}; + transform: translate(-50%, -50%); + animation: showModal 0.25s ease-in-out; + + @keyframes showModal { + 0% { + transform: translate(-50%, -50%) scale(0.8); + opacity: 0; + } + 100% { + transform: translate(-50%, -50%) scale(1); + opacity: 1; + } + } +`; + +export const XButton = styled.span` + position: absolute; + top: 2.5rem; + right: 2.5rem; + cursor: pointer; +`; + +export const Title = styled.div` + text-align: center; + font-size: 20px; + margin-bottom: 1.4rem; +`; + +export const Line = styled.div` + display: flex; + justify-content: center; + align-items: center; + width: 100%; + margin-top: 3rem; +`; + +export const TextSocialLogin = styled.span` + margin: 0 2.8rem; + color: #949494; +`; + +export const Hr = styled.span` + width: 14.5rem; + height: 1px; + background: #949494; +`; + +export const SocialLogin = styled.div` + margin: 3rem auto 0; +`; + +export const GoogleLogo = styled.img` + width: 7rem; + height: 7rem; + padding: 1rem; + border-radius: 50%; + cursor: pointer; +`; diff --git a/src/components/commons/Modal/GlobalAuthModals/index.tsx b/src/components/commons/Modal/GlobalAuthModals/index.tsx new file mode 100644 index 00000000..27c57d4e --- /dev/null +++ b/src/components/commons/Modal/GlobalAuthModals/index.tsx @@ -0,0 +1,27 @@ +// import { useSelector, useDispatch } from 'react-redux'; +// import { toggleLoginModal } from 'hooks/@redux/loginModalSlice'; +// import { toggleRegisterModal } from 'hooks/@redux/registerModalSlice'; +// import Modal from 'components/commons/Modal'; + +const GlobalAuthModals = () => { + // const dispatch = useDispatch(); + // const isLoginOpen = useSelector(state => state.loginModal.isOpen); + // const isRegisterOpen = useSelector(state => state.registerModal.isOpen); + + return ( + <> + {/* {isLoginOpen && ( + dispatch(toggleLoginModal())}> + + + )} + {isRegisterOpen && ( + dispatch(toggleRegisterModal())}> + + + )} */} + + ); +}; + +export default GlobalAuthModals; diff --git a/src/components/commons/Modal/SignModal/index.tsx b/src/components/commons/Modal/SignModal/index.tsx index b5a39aeb..4d848d14 100644 --- a/src/components/commons/Modal/SignModal/index.tsx +++ b/src/components/commons/Modal/SignModal/index.tsx @@ -16,11 +16,11 @@ const SignModal = ({ children, toggleModal }: Props) => { CSTUDY에 오신 것을 환영합니다! {children} - + {/* 소셜 로그인 - + */} ; errors: FieldErrors; } diff --git a/src/components/commons/TextArea/style.ts b/src/components/commons/TextArea/style.ts index ca25fc1c..7e54b6b4 100644 --- a/src/components/commons/TextArea/style.ts +++ b/src/components/commons/TextArea/style.ts @@ -20,5 +20,5 @@ export const TextArea = styled.textarea` border: 0.1rem solid ${({ errors, id }) => (errors[id] ? `${COLOR.RED}` : `${COLOR.WHITE}`)}; resize: none; - border: 2px solid ${COLOR.GRAY_50}; + border: 0.16rem solid ${COLOR.GRAY_50}; `; diff --git a/src/components/main/Banner/style.ts b/src/components/main/Banner/style.ts index 95dccd12..66793d29 100644 --- a/src/components/main/Banner/style.ts +++ b/src/components/main/Banner/style.ts @@ -1,7 +1,7 @@ import { styled } from 'styled-components'; export const BannerWrapper = styled.div` - height: 50rem; + padding-top: 2rem; `; export const BannerImg = styled.img` diff --git a/src/components/main/Contents/style.ts b/src/components/main/Contents/style.ts index 277c78c5..90b9a821 100644 --- a/src/components/main/Contents/style.ts +++ b/src/components/main/Contents/style.ts @@ -5,6 +5,8 @@ import { COLOR } from 'constants/Color'; export const ContentSection = styled.section` padding-top: 3rem; + max-width: 1200px; + margin: 0 auto; `; export const ContentWrapper = styled.div` display: flex; diff --git a/src/components/unit/CreateProblem/CreateProblemInput/index.tsx b/src/components/unit/CreateProblem/CreateProblemInput/index.tsx new file mode 100644 index 00000000..d8a8b2c3 --- /dev/null +++ b/src/components/unit/CreateProblem/CreateProblemInput/index.tsx @@ -0,0 +1,50 @@ +import { FieldValues, UseFormRegister } from 'react-hook-form'; +import * as S from './style'; + +interface CreateProblemInputProps { + label?: string; + id?: string; + placeholder?: string; + type?: string; + register: UseFormRegister; + name: string; + required?: boolean; + disabled?: boolean; + value?: string; +} + +const CreateProblemInput = ({ + id, + placeholder, + type, + register, + name, + label, + value, +}: CreateProblemInputProps) => { + return ( + <> + {type === 'text' && ( + <> + {label} + + + )} + {type === 'checkbox' && ( + + )} + + ); +}; + +export default CreateProblemInput; diff --git a/src/components/unit/CreateProblem/CreateProblemInput/style.ts b/src/components/unit/CreateProblem/CreateProblemInput/style.ts new file mode 100644 index 00000000..3bf6ae14 --- /dev/null +++ b/src/components/unit/CreateProblem/CreateProblemInput/style.ts @@ -0,0 +1,15 @@ +import styled from 'styled-components'; + +export const Input = styled.input` + padding: 1rem 5rem 1rem 1rem; +`; + +export const Label = styled.label` + padding: 1.5rem; +`; + +export const CheckBoxInput = styled.input` + position: absolute; + top: 20%; + right: 0; +`; diff --git a/src/components/unit/CreateProblem/CreateProblemSelect/index.tsx b/src/components/unit/CreateProblem/CreateProblemSelect/index.tsx new file mode 100644 index 00000000..d5379bdd --- /dev/null +++ b/src/components/unit/CreateProblem/CreateProblemSelect/index.tsx @@ -0,0 +1,23 @@ +import { FieldValues, UseFormRegister } from 'react-hook-form'; + +interface CreateProblemSelectProp { + register: UseFormRegister; + name: string; +} + +const CreateProblemSelect = ({ register, name }: CreateProblemSelectProp) => { + return ( + <> + + + + ); +}; + +export default CreateProblemSelect; diff --git a/src/components/unit/CreateProblem/index.tsx b/src/components/unit/CreateProblem/index.tsx new file mode 100644 index 00000000..25e4104e --- /dev/null +++ b/src/components/unit/CreateProblem/index.tsx @@ -0,0 +1,192 @@ +import React from 'react'; +import Button from 'components/commons/Button/Button'; +import * as S from './style'; +import List from '../../admin/List'; +import { FieldValues } from 'react-hook-form'; +import { useForm } from 'react-hook-form'; +import { useDispatch } from 'react-redux'; +import { useCreateProblem } from 'hooks/useCreateProblem'; +import { AppDispatch } from 'hooks/@redux/problemSlice'; +import { useNavigate } from 'react-router-dom'; +import CreateProblemSelect from './CreateProblemSelect'; +import CreateProblemInput from './CreateProblemInput'; + +const ProblemForm = () => { + const dispatch = useDispatch(); + const navigate = useNavigate(); + + const { + register, + handleSubmit, + formState: { errors }, + } = useForm({ + defaultValues: { + createQuestionRequestDto: { + questionTitle: '', + questionDesc: '', + questionExplain: '', + }, + categoryRequestDto: { + category: '네트워크', + }, + createChoicesAboutQuestionDto: [ + { + number: 1, + content: '', + answer: '', + }, + { + number: 2, + content: '', + answer: '', + }, + { + number: 3, + content: '', + answer: '', + }, + { + number: 4, + content: '', + answer: '', + }, + ], + }, + }); + + const onSubmit = (formData: FieldValues) => { + console.log(formData); + dispatch(useCreateProblem(formData)); + }; + + return ( + + + + + 문제 생성 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default ProblemForm; diff --git a/src/components/unit/CreateProblem/style.ts b/src/components/unit/CreateProblem/style.ts new file mode 100644 index 00000000..e4740715 --- /dev/null +++ b/src/components/unit/CreateProblem/style.ts @@ -0,0 +1,67 @@ +import { COLOR } from 'constants/Color'; +import { FONT } from 'constants/Font'; +import { styled } from 'styled-components'; + +export const CPWrapper = styled.div` + padding-top: 10rem; + max-width: 1200px; + margin: 0 auto; +`; + +export const innerCP = styled.div` + display: flex; + justify-content: space-around; +`; + +export const CpDiv = styled.div` + padding: 3rem 6rem; + border-radius: 1.2rem; + background-color: rgb(219, 236, 244); +`; +export const CpTitle = styled.h2` + padding-bottom: 5rem; +`; + +export const CpForm = styled.form` + display: flex; +`; + +export const CpInputSelect = styled.div` + display: flex; + flex-direction: column; + margin-right: 10rem; + label { + padding: 1.5rem; + } + input { + padding: 1rem 5rem 1rem 1rem; + } + select { + padding: 1rem 1rem; + margin-bottom: 2rem; + } +`; + +export const CpInput = styled.div` + display: flex; + flex-direction: column; + label { + padding: 1.5rem; + } + input { + padding: 1rem 5rem 1rem 1rem; + } +`; + +export const CpButton = styled.div` + display: flex; + button { + margin: 2rem 2rem 0 0; + } +`; + +export const Ex = styled.div` + position: relative; + display: flex; + flex-direction: column; +`; diff --git a/src/components/unit/Mypage/MypageInfo/index.tsx b/src/components/unit/Mypage/MypageInfo/index.tsx new file mode 100644 index 00000000..97d882e2 --- /dev/null +++ b/src/components/unit/Mypage/MypageInfo/index.tsx @@ -0,0 +1,5 @@ +const MyPageInfo = () => { + return
ㅇㅇ
; +}; + +export default MyPageInfo; diff --git a/src/components/unit/RequestList/style.ts b/src/components/unit/Mypage/MypageInfo/style.ts similarity index 100% rename from src/components/unit/RequestList/style.ts rename to src/components/unit/Mypage/MypageInfo/style.ts diff --git a/src/components/unit/Request/RequestDetail/index.tsx b/src/components/unit/Request/RequestDetail/index.tsx new file mode 100644 index 00000000..5bea3835 --- /dev/null +++ b/src/components/unit/Request/RequestDetail/index.tsx @@ -0,0 +1,56 @@ +import { useNavigate, useParams } from 'react-router-dom'; + +import useGetRequest from 'hooks/@query/request/useGetRequest'; + +import Container from 'components/commons/Container'; +import * as S from './style'; +import Button from 'components/commons/Button/Button'; +import ApproveStatus from 'components/commons/Status'; +import { useDeleteRequest } from 'hooks/@query/request/useMutateRequest'; + +const RequestDetail = () => { + const { id } = useParams(); + const navigate = useNavigate(); + + const request = useGetRequest(id); + const { mutate: deleteRequest } = useDeleteRequest(); + + const handleNavigateEdit = () => { + navigate(`/request/${id}/edit`); + }; + + const handleNavigateBack = () => { + navigate(-1); + }; + + const handleDeleteRequest = () => { + deleteRequest(id); + }; + + return ( + + + + {request?.title} + + {request?.memberName} + · + {request?.createAt} + + {' '} + + {request?.description} + + + + + + + ); +}; + +export default RequestDetail; diff --git a/src/components/unit/RequestDetail/style.ts b/src/components/unit/Request/RequestDetail/style.ts similarity index 85% rename from src/components/unit/RequestDetail/style.ts rename to src/components/unit/Request/RequestDetail/style.ts index 9f8bb732..478e0ccb 100644 --- a/src/components/unit/RequestDetail/style.ts +++ b/src/components/unit/Request/RequestDetail/style.ts @@ -27,3 +27,9 @@ export const Detail = styled.div` export const Content = styled.div` margin-top: 4rem; `; + +export const ButtonWrapper = styled.div` + display: flex; + justify-content: flex-end; + width: 100%; +`; diff --git a/src/components/unit/Request/RequestItem/index.tsx b/src/components/unit/Request/RequestItem/index.tsx new file mode 100644 index 00000000..4ec2f765 --- /dev/null +++ b/src/components/unit/Request/RequestItem/index.tsx @@ -0,0 +1,38 @@ +import { Link } from 'react-router-dom'; +import * as S from './style'; +import ApproveStatus from 'components/commons/Status'; + +interface RequestListProps { + id: number; + flag: boolean; + title: string; + description: string; + memberName: string; + createAt: string; +} + +const RequestItem = (props: RequestListProps) => { + const { id, flag, title, description, memberName, createAt } = props; + + const checkAndDisplayLoginModal = () => { + return; + }; + return ( + + + + + + {title} + + {description} + + {memberName}·{createAt} + + + + + ); +}; + +export default RequestItem; diff --git a/src/components/unit/RequestItem/style.ts b/src/components/unit/Request/RequestItem/style.ts similarity index 100% rename from src/components/unit/RequestItem/style.ts rename to src/components/unit/Request/RequestItem/style.ts diff --git a/src/components/unit/Request/RequestList/index.tsx b/src/components/unit/Request/RequestList/index.tsx new file mode 100644 index 00000000..f600855e --- /dev/null +++ b/src/components/unit/Request/RequestList/index.tsx @@ -0,0 +1,72 @@ +import Container from 'components/commons/Container'; +import Modal from 'components/unit/Modal'; +import useModal from 'hooks/useModal'; +import ConfirmModal from 'components/commons/Modal/ConfirmModal'; +import RequestItem from '../RequestItem'; +import { isLogin } from 'repository/auth'; +import { getRequestListTest } from 'api/request'; +import { useEffect, useState } from 'react'; +import Button from 'components/commons/Button/Button'; +import * as S from './style'; +import { ToggleRequestList } from 'types/api'; +import { useNavigate } from 'react-router-dom'; + +const RequestList = () => { + const [requestList, setRequestList] = useState(); + const { modalIsOpen, toggleModal } = useModal(); + const fetchRequestList = async () => { + const data = await getRequestListTest(); + setRequestList(data.data); + }; + const navigate = useNavigate(); + + useEffect(() => { + fetchRequestList(); + console.log(requestList); + }, []); + + const openModal = () => { + toggleModal(); + }; + + const checkLogin = () => { + if (!isLogin()) { + alert('로그인 후 이용하실 수 있습니다.'); + } else { + navigate('/request/new'); + } + }; + + return ( + <> + {modalIsOpen && ( + + + + )} + + + + + + + {requestList?.content?.map(props => ( + + ))} + + + + ); +}; + +export default RequestList; diff --git a/src/components/unit/Request/RequestList/style.ts b/src/components/unit/Request/RequestList/style.ts new file mode 100644 index 00000000..a372e9f3 --- /dev/null +++ b/src/components/unit/Request/RequestList/style.ts @@ -0,0 +1,9 @@ +import styled from 'styled-components'; + +export const ButtonWrapper = styled.div` + display: flex; + justify-content: flex-end; + width: 100%; +`; + +export const ContentWrapper = styled.div``; diff --git a/src/components/unit/RequestDetail/index.tsx b/src/components/unit/RequestDetail/index.tsx deleted file mode 100644 index 15892f74..00000000 --- a/src/components/unit/RequestDetail/index.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import Container from 'components/commons/Container'; -import * as S from './style'; -import Button from 'components/commons/Button/Button'; - -const RequestDetail = () => { - return ( - - - {/* */}승인 - {/* {request?.title} */}문제 올려주세요 - - {/* {request?.memberName} */}test - · - {/* {request?.createAt} */}2023-09-01 - - {/* {request?.description} */}문제 만들어주세요 - -
- -
-
- ); -}; - -export default RequestDetail; diff --git a/src/components/unit/RequestItem/index.tsx b/src/components/unit/RequestItem/index.tsx deleted file mode 100644 index a5d32655..00000000 --- a/src/components/unit/RequestItem/index.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import * as S from './style'; - -const RequestItem = () => { - return ( - - {/* */} - - - 승인 - - {/* {title} */} - 문제 올려주세요 - - - {/* {description} */}글 요약 - - - {/* {memberName} */} - test - - · - - {/* {createAt} */} - 2023-09-23 - - - - {/* */} - - ); -}; - -export default RequestItem; diff --git a/src/components/unit/RequestList/index.tsx b/src/components/unit/RequestList/index.tsx deleted file mode 100644 index 4b19c718..00000000 --- a/src/components/unit/RequestList/index.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import Container from 'components/commons/Container'; -import Modal from 'components/unit/Modal'; -import useModal from 'hooks/useModal'; -import SignModal from 'components/commons/Modal/SignModal'; -import ConfirmModal from 'components/commons/Modal/ConfirmModal'; -import RequestItem from '../RequestItem'; - -const RequestList = () => { - const { modalIsOpen, toggleModal } = useModal(); - - const openModal = () => { - toggleModal(); - }; - - return ( - <> - {modalIsOpen && ( - - - - )} - - -

요청 게시판

-
- -
-
- - ); -}; - -export default RequestList; diff --git a/src/components/unit/SignUp/index.tsx b/src/components/unit/SignUp/index.tsx index 4f749a93..06c1bd43 100644 --- a/src/components/unit/SignUp/index.tsx +++ b/src/components/unit/SignUp/index.tsx @@ -1,7 +1,11 @@ import React from 'react'; import Container from 'components/commons/Container'; import * as S from './style'; -import { useSignUp } from 'hooks/useSignUp'; +import { useSignUp } from 'hooks/@query/useSignUp'; +import { useDispatch, useSelector } from 'react-redux'; +import { toggle, close } from 'hooks/@redux/registerModalSlice'; +import Modal from 'components/unit/Modal'; +import AuthModalFrame from 'components/commons/Modal/SignModal'; const SignUp = () => { const { @@ -19,144 +23,153 @@ const SignUp = () => { onCheckAuthNumber, } = useSignUp(); - return ( - -
- - state.registerModal.isOpen); - onChange: e => - setValue('name', e.target.value, { - shouldValidate: true, - shouldDirty: true, - shouldTouch: true, - }), - })} - /> - - 중복확인 - - - {errors.name?.message as string} - - - setValue('email', e.target.value, { - shouldValidate: true, - shouldDirty: true, - shouldTouch: true, - }), - })} - /> - - {noDuplicatedEmail ? '인증번호 전송' : '중복확인'} - - - - {errors.email?.message as React.ReactNode} - - - {authenticating && ( - - {authenticating && ( - - setValue('emailAuthNumber', e.target.value, { - shouldValidate: true, - shouldDirty: true, - shouldTouch: true, - }), - })} - /> - )} - {authenticating && ( - - 인증 - - )} - - )} - - {errors.emailAuthNumber?.message as string} - + const changeModalHandler = () => { + // closeSignUpModal(); + // loginModalOpen(); + dispatch(toggle()); + }; + return ( + // dispatch(toggle())}> + // dispatch(close())}> + + - setValue('password', e.target.value, { + setValue('name', e.target.value, { shouldValidate: true, shouldDirty: true, shouldTouch: true, }), })} /> - {errors.password?.message as string} - + + 중복확인 + + + {errors.name?.message as string} + - setValue('passwordConfirm', e.target.value, { + setValue('email', e.target.value, { shouldValidate: true, shouldDirty: true, shouldTouch: true, }), - validate: value => - value === watchedPassword || '비밀번호가 일치하지 않습니다.', })} /> - - {errors.passwordConfirm?.message as string} - + + {noDuplicatedEmail ? '인증번호 전송' : '중복확인'} + + + + {errors.email?.message as React.ReactNode} + + + {authenticating && ( + + {authenticating && ( + + setValue('emailAuthNumber', e.target.value, { + shouldValidate: true, + shouldDirty: true, + shouldTouch: true, + }), + })} + /> + )} + {authenticating && ( + + 인증 + + )} + + )} + + {errors.emailAuthNumber?.message as string} + + + + setValue('password', e.target.value, { + shouldValidate: true, + shouldDirty: true, + shouldTouch: true, + }), + })} + /> + {errors.password?.message as string} + + + setValue('passwordConfirm', e.target.value, { + shouldValidate: true, + shouldDirty: true, + shouldTouch: true, + }), + validate: value => + value === watchedPassword || '비밀번호가 일치하지 않습니다.', + })} + /> + + {errors.passwordConfirm?.message as string} + - 회원가입 - - 회원이신가요? - - - -
+ 회원가입 + + 회원이신가요? + + + + // + // ); }; diff --git a/src/hooks/@query/request/useApproveRequest.ts b/src/hooks/@query/request/useApproveRequest.ts new file mode 100644 index 00000000..81dbc1b4 --- /dev/null +++ b/src/hooks/@query/request/useApproveRequest.ts @@ -0,0 +1,21 @@ +import { useMutation, useQueryClient } from '@tanstack/react-query'; +import { approveRequest } from 'api/request'; +// import toast from 'provider/Toast'; + +export const useApproveRequest = () => { + const queryClient = useQueryClient(); + const { mutate: ApproveRequest } = useMutation(approveRequest, { + onSuccess: () => { + queryClient.invalidateQueries(['request']); + queryClient.invalidateQueries(['requestList']); + // toast.success('글이 승인되었습니다.'); + alert('글이 승인되었습니다.'); + }, + onError: () => { + // toast.error('글 승인에 실패했습니다.'); + alert('글 승인에 실패했습니다.'); + }, + }); + + return ApproveRequest; +}; diff --git a/src/hooks/@query/request/useGetRequest.ts b/src/hooks/@query/request/useGetRequest.ts new file mode 100644 index 00000000..5a0fa180 --- /dev/null +++ b/src/hooks/@query/request/useGetRequest.ts @@ -0,0 +1,9 @@ +import { useQuery } from '@tanstack/react-query'; +import { getRequest } from 'api/request'; + +const useGetRequest = (id: string | undefined) => { + const { data: request } = useQuery(['request', { id }], () => getRequest(id)); + return request; +}; + +export default useGetRequest; diff --git a/src/hooks/1.ts b/src/hooks/@query/request/useGetRequestList.ts similarity index 100% rename from src/hooks/1.ts rename to src/hooks/@query/request/useGetRequestList.ts diff --git a/src/hooks/@query/request/useMutateRequest.ts b/src/hooks/@query/request/useMutateRequest.ts new file mode 100644 index 00000000..7270d330 --- /dev/null +++ b/src/hooks/@query/request/useMutateRequest.ts @@ -0,0 +1,65 @@ +import { useMutation, useQueryClient } from '@tanstack/react-query'; +import { createRequest, deleteRequest, editRequest } from 'api/request'; +import { useNavigate } from 'react-router-dom'; +// import toast from 'provider/Toast'; + +// 작성 +export const useCreateRequest = () => { + const queryClient = useQueryClient(); + const navigate = useNavigate(); + + return useMutation(createRequest, { + onSuccess: () => { + queryClient.invalidateQueries(['requestList']); + // toast.success('글이 등록되었습니다.'); + alert('글이 등록되었습니다.'); + navigate('/request'); + window.scrollTo(0, 0); + }, + onError: () => { + // toast.error('글 등록에 실패했습니다.'); + alert('글 등록에 실패했습니다.'); + navigate('/request'); + }, + }); +}; + +// 수정 +export const useEditRequest = () => { + const queryClient = useQueryClient(); + const navigate = useNavigate(); + + return useMutation(editRequest, { + onSuccess: () => { + queryClient.invalidateQueries(['requestList']); + // toast.success('글이 등록되었습니다.'); + alert('글이 수정되었습니다.'); + navigate('/request'); + window.scrollTo(0, 0); + }, + onError: () => { + // toast.error('글 등록에 실패했습니다.'); + alert('글 수정에 실패했습니다.'); + }, + }); +}; + +// 삭제 +export const useDeleteRequest = () => { + const queryClient = useQueryClient(); + const navigate = useNavigate(); + + return useMutation(deleteRequest, { + onSuccess: () => { + queryClient.invalidateQueries(['requestList']); + // toast.success('글이 등록되었습니다.'); + alert('글이 삭제되었습니다.'); + navigate('/request'); + window.scrollTo(0, 0); + }, + onError: () => { + // toast.error('글 등록에 실패했습니다.'); + alert('글 삭제에 실패했습니다.'); + }, + }); +}; diff --git a/src/hooks/useSignUp.ts b/src/hooks/@query/useSignUp.ts similarity index 100% rename from src/hooks/useSignUp.ts rename to src/hooks/@query/useSignUp.ts diff --git a/src/hooks/@redux/index.ts b/src/hooks/@redux/index.ts index be0292f9..fb09293d 100644 --- a/src/hooks/@redux/index.ts +++ b/src/hooks/@redux/index.ts @@ -1,10 +1,12 @@ import { combineReducers } from 'redux'; import authReducer from './authSlice'; import loginmodalReducer from './modalSlice'; +import registerModalReducer from './registerModalSlice'; const rootReducer = combineReducers({ auth: authReducer, loginModal: loginmodalReducer, + registerModal: registerModalReducer, }); export default rootReducer; diff --git a/src/hooks/@redux/loginModalSlice.ts b/src/hooks/@redux/loginModalSlice.ts new file mode 100644 index 00000000..10b0211e --- /dev/null +++ b/src/hooks/@redux/loginModalSlice.ts @@ -0,0 +1,22 @@ +import { createSlice } from '@reduxjs/toolkit'; + +interface LoginModalState { + isOpen: boolean; +} + +const initialState: LoginModalState = { + isOpen: false, +}; + +const loginModalSlice = createSlice({ + name: 'loginModal', + initialState, + reducers: { + toggleLoginModal: (state: any) => { + state.isOpen = !state.isOpen; + }, + }, +}); + +export const { toggleLoginModal } = loginModalSlice.actions; +export default loginModalSlice.reducer; diff --git a/src/hooks/@redux/problemSlice.ts b/src/hooks/@redux/problemSlice.ts new file mode 100644 index 00000000..05fb2691 --- /dev/null +++ b/src/hooks/@redux/problemSlice.ts @@ -0,0 +1,36 @@ +import { createSlice, PayloadAction } from '@reduxjs/toolkit'; +import { useCreateProblem } from 'hooks/useCreateProblem'; +import store from 'stroe'; + +export interface problemState { + formData: object; + error: null; + loading: boolean; +} + +const initialState: problemState = { + formData: {}, + error: null, + loading: true, +}; + +const ProblemSlice = createSlice({ + name: 'problem', + initialState, + reducers: {}, + extraReducers: builder => { + builder.addCase(useCreateProblem.pending, state => { + state.loading = false; + }); + builder.addCase(useCreateProblem.fulfilled, (state, action) => { + state.formData = action.payload; + }); + builder.addCase(useCreateProblem.rejected, state => { + state.loading = true; + }); + }, +}); + +export type AppDispatch = typeof store.dispatch; + +export default ProblemSlice.reducer; diff --git a/src/hooks/@redux/registerModalSlice.ts b/src/hooks/@redux/registerModalSlice.ts new file mode 100644 index 00000000..8c4b47f6 --- /dev/null +++ b/src/hooks/@redux/registerModalSlice.ts @@ -0,0 +1,25 @@ +import { createSlice } from '@reduxjs/toolkit'; + +export interface RegisterModalState { + isOpen: boolean; +} + +const initialState: RegisterModalState = { + isOpen: false, +}; + +const registerModalSlice = createSlice({ + name: 'registerModal', + initialState, + reducers: { + toggle: (state: any) => { + state.isOpen = !state.isOpen; + }, + close: (state: any) => { + state.isOpen = false; + }, + }, +}); + +export const { toggle, close } = registerModalSlice.actions; +export default registerModalSlice.reducer; diff --git a/src/hooks/query/request/useCreateRequest.ts b/src/hooks/query/request/useCreateRequest.ts deleted file mode 100644 index 3d764134..00000000 --- a/src/hooks/query/request/useCreateRequest.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { createRequest } from 'api/request'; -import { useNavigate } from 'react-router-dom'; -// import toast from 'provider/Toast'; - -export const useCreateRequest = () => { - const queryClient = useQueryClient(); - const navigate = useNavigate(); - - return useMutation(createRequest, { - onSuccess: () => { - queryClient.invalidateQueries(['requestList']); - // toast.success('글이 등록되었습니다.'); - alert('글이 등록되었습니다.'); - navigate('/board'); - window.scrollTo(0, 0); - }, - onError: () => { - // toast.error('글 등록에 실패했습니다.'); - alert('글 등록에 실패했습니다.'); - }, - }); -}; diff --git a/src/hooks/useCreateProblem.ts b/src/hooks/useCreateProblem.ts new file mode 100644 index 00000000..6b343253 --- /dev/null +++ b/src/hooks/useCreateProblem.ts @@ -0,0 +1,17 @@ +import { createAsyncThunk } from '@reduxjs/toolkit'; +import { problemSet } from 'api/problem'; +import { FieldValues } from 'react-hook-form'; + +export const useCreateProblem = createAsyncThunk( + 'problem/useCreateProblem', + async (formData: FieldValues, thunkAPI) => { + try { + const data = await problemSet(formData); + alert('문제생성이 완료되었습니다'); + return thunkAPI.fulfillWithValue(data); + } catch (error) { + alert('문제생성이 실패했습니다'); + return thunkAPI.rejectWithValue(error); + } + }, +); diff --git a/src/pages/Admin/CreateProblem/index.tsx b/src/pages/Admin/CreateProblem/index.tsx index a2139c2c..ace1c79d 100644 --- a/src/pages/Admin/CreateProblem/index.tsx +++ b/src/pages/Admin/CreateProblem/index.tsx @@ -1,116 +1,11 @@ -import Button from 'components/commons/Button/Button'; import React from 'react'; -import * as S from './style'; -import List from '../common'; -import { problemSet } from 'api/problem'; -import { FieldValues, SubmitHandler, useForm } from 'react-hook-form'; +import ProblemForm from 'components/unit/CreateProblem'; const CreateProblem = () => { - const { - register, - handleSubmit, - formState: { errors }, - } = useForm({ - defaultValues: {}, - }); - - const onSubmit: SubmitHandler = FormData => { - console.log(FormData); - }; - return ( - - - - - 문제 생성 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + <> + + ); }; diff --git a/src/pages/Admin/CreateProblem/style.ts b/src/pages/Admin/CreateProblem/style.ts index 1ae11b17..cb0ff5c3 100644 --- a/src/pages/Admin/CreateProblem/style.ts +++ b/src/pages/Admin/CreateProblem/style.ts @@ -1,73 +1 @@ -import { COLOR } from 'constants/Color'; -import { FONT } from 'constants/Font'; -import { styled } from 'styled-components'; - -export const CPWrapper = styled.div` - padding-top: 10rem; - max-width: 1200px; - margin: 0 auto; -`; - -export const innerCP = styled.div` - display: flex; - justify-content: space-around; -`; - -export const CpDiv = styled.div` - padding: 3rem 6rem; - border-radius: 1.2rem; - background-color: rgb(219, 236, 244); -`; -export const CpTitle = styled.h2` - padding-bottom: 5rem; -`; - -export const CpForm = styled.form` - display: flex; -`; - -export const CpInputSelect = styled.div` - display: flex; - flex-direction: column; - margin-right: 10rem; - label { - padding: 1.5rem; - } - input { - padding: 1rem 5rem 1rem 1rem; - } - select { - padding: 1rem 1rem; - margin-bottom: 2rem; - } -`; - -export const CpInput = styled.div` - display: flex; - flex-direction: column; - label { - padding: 1.5rem; - } - input { - padding: 1rem 5rem 1rem 1rem; - } -`; - -export const CpButton = styled.div` - display: flex; - button { - margin: 2rem 2rem 0 0; - } -`; - -export const CheckBoxInput = styled.input` - position: absolute; - top: 20%; - right: 0; -`; - -export const Ex = styled.div` - position: relative; - display: flex; - flex-direction: column; -`; +export {}; diff --git a/src/pages/Main/index.tsx b/src/pages/Main/index.tsx index 847cd246..5d016ab8 100644 --- a/src/pages/Main/index.tsx +++ b/src/pages/Main/index.tsx @@ -6,13 +6,22 @@ import { useSelector } from 'react-redux'; import Banner from 'components/main/Banner'; const Main = () => { - const isAuthenticated = useSelector( - (state: any) => state.auth.isAuthenticated, - ); + // const isAuthenticated = useSelector( + // (state: any) => state.auth.isAuthenticated, + // ); return ( - {/*
+ + + + ); +}; + +export default Main; + +{ + /*

버튼 컴포넡트

@@ -36,11 +45,5 @@ const Main = () => {
-
*/} - - - - ); -}; - -export default Main; +
*/ +} diff --git a/src/pages/Request/RequestEdit/index.tsx b/src/pages/Request/RequestEdit/index.tsx new file mode 100644 index 00000000..f1f8926a --- /dev/null +++ b/src/pages/Request/RequestEdit/index.tsx @@ -0,0 +1,12 @@ +import useGetRequest from 'hooks/@query/request/useGetRequest'; +import RequestWrite from 'pages/RequestWrite'; +import { useParams } from 'react-router-dom'; + +const RequestEdit = () => { + const { id } = useParams(); + const request = useGetRequest(id); + + return ; +}; + +export default RequestEdit; diff --git a/src/pages/Request/RequestEdit/style.ts b/src/pages/Request/RequestEdit/style.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/src/pages/Request/RequestEdit/style.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/pages/Request/index.tsx b/src/pages/Request/index.tsx index 42749ad5..5ab24729 100644 --- a/src/pages/Request/index.tsx +++ b/src/pages/Request/index.tsx @@ -1,4 +1,4 @@ -import RequestList from 'components/unit/RequestList'; +import RequestList from 'components/unit/Request/RequestList'; const Request = () => { return ( diff --git a/src/pages/RequestDetail/index.tsx b/src/pages/RequestDetail/index.tsx index b9d33a51..a4b7b643 100644 --- a/src/pages/RequestDetail/index.tsx +++ b/src/pages/RequestDetail/index.tsx @@ -1,6 +1,4 @@ -import RequestDetail from 'components/unit/RequestDetail'; -import * as S from './style'; -import Button from 'components/commons/Button/Button'; +import RequestDetail from 'components/unit/Request/RequestDetail'; const RequestDetailPage = () => { return ; diff --git a/src/pages/RequestWrite/index.tsx b/src/pages/RequestWrite/index.tsx index 3e5c7b57..866a3ef2 100644 --- a/src/pages/RequestWrite/index.tsx +++ b/src/pages/RequestWrite/index.tsx @@ -1,6 +1,9 @@ import { useNavigate } from 'react-router-dom'; import { FieldValues, SubmitHandler, useForm } from 'react-hook-form'; -import { useCreateRequest } from 'hooks/query/request/useCreateRequest'; +import { + useCreateRequest, + useEditRequest, +} from 'hooks/@query/request/useMutateRequest'; // import ContentContainer from 'components/@shared/ContentContainer'; // import ContentHeaderWrapper from 'components/@shared/ContentHeaderWrapper'; @@ -11,8 +14,14 @@ import * as S from './style'; import Container from 'components/commons/Container'; import TextArea from 'components/commons/TextArea'; import Button from 'components/commons/Button/Button'; +import Input from 'components/commons/Input'; -const RequestWrite = () => { +interface RequesetWriteProps { + isEdit: boolean; + data?: any; +} + +const RequestWrite = ({ isEdit, data }: RequesetWriteProps) => { const navigate = useNavigate(); const { @@ -31,38 +40,46 @@ const RequestWrite = () => { }; const { mutate: createRequest } = useCreateRequest(); + const { mutate: editRequest } = useEditRequest(); const submitForm: SubmitHandler = FormData => { - createRequest(FormData); + console.log(FormData); + const updateRequestInput = { + title: '글수정', + description: '글수정', + id: data?.id, + }; + // if(title) + // if(description) + if (isEdit) editRequest(updateRequestInput); + else createRequest(FormData); }; return (
-

제목

-