From 8676f21fa858a5290cda4ab8a9022cd4f896888d Mon Sep 17 00:00:00 2001 From: YouD0313 <102004480+YouD0313@users.noreply.github.com> Date: Sun, 18 May 2025 01:02:02 +0900 Subject: [PATCH 01/27] =?UTF-8?q?design:=20=EC=BB=A8=ED=85=90=ED=8A=B8=20?= =?UTF-8?q?=EA=B8=B8=EC=9D=B4=EB=A7=8C=ED=81=BC=20=EA=B0=80=EC=A0=B8?= =?UTF-8?q?=EC=98=A4=EA=B2=8C=20=EC=9E=90=EC=8B=9D=20=EB=86=92=EC=9D=B4=20?= =?UTF-8?q?100%=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/user/mypage/ContentTab.styled.ts | 1 - .../user/mypage/joinedProject/MyJoinProjects.styled.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/src/components/user/mypage/ContentTab.styled.ts b/src/components/user/mypage/ContentTab.styled.ts index 974acd21..95c5c3da 100644 --- a/src/components/user/mypage/ContentTab.styled.ts +++ b/src/components/user/mypage/ContentTab.styled.ts @@ -74,7 +74,6 @@ export const WrapperButton = styled.div<{ $height: string }>` export const FilterContainer = styled.div` width: 100%; - height: 100%; background-color: ${({ theme }) => theme.color.lightgrey}; border-radius: ${({ theme }) => theme.borderRadius.large}; `; diff --git a/src/components/user/mypage/joinedProject/MyJoinProjects.styled.ts b/src/components/user/mypage/joinedProject/MyJoinProjects.styled.ts index d1e9efeb..de62e10c 100644 --- a/src/components/user/mypage/joinedProject/MyJoinProjects.styled.ts +++ b/src/components/user/mypage/joinedProject/MyJoinProjects.styled.ts @@ -39,7 +39,6 @@ export const WrapperProject = styled.div` flex-wrap: wrap; justify-content: space-between; gap: 2rem; - height: 100%; @media ${({ theme }) => theme.mediaQuery.tablet} { padding: 1rem; From b87b6068cac3e026018db129522bdc1143cd1b15 Mon Sep 17 00:00:00 2001 From: YouD0313 <102004480+YouD0313@users.noreply.github.com> Date: Sun, 18 May 2025 17:14:15 +0900 Subject: [PATCH 02/27] =?UTF-8?q?design:=20noContent=20=EC=A4=91=EA=B0=84?= =?UTF-8?q?=EC=A0=95=EB=A0=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/noContent/NoContent.styled.ts | 2 ++ src/components/user/mypage/ContentTab.styled.ts | 7 +++++++ .../activityLog/commentsActivity/CommentsActivity.tsx | 2 +- .../user/mypage/activityLog/inquiries/Inquiries.styled.ts | 3 ++- .../user/mypage/activityLog/inquiries/Inquiries.tsx | 2 +- .../user/mypage/joinedProject/MyJoinProjects.styled.ts | 1 + src/components/user/mypage/notifications/all/All.tsx | 2 +- 7 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/components/common/noContent/NoContent.styled.ts b/src/components/common/noContent/NoContent.styled.ts index 21bbe938..917368d3 100644 --- a/src/components/common/noContent/NoContent.styled.ts +++ b/src/components/common/noContent/NoContent.styled.ts @@ -3,6 +3,7 @@ import styled from 'styled-components'; export const Wrapper = styled.div` width: 100%; height: 100%; + min-height: 100%; display: flex; flex-direction: column; justify-content: center; @@ -14,6 +15,7 @@ export const Wrapper = styled.div` `; export const NoContentText = styled.h1` + height: 100%; font-size: 2rem; font-weight: 600; color: ${({ theme }) => theme.color.navy}; diff --git a/src/components/user/mypage/ContentTab.styled.ts b/src/components/user/mypage/ContentTab.styled.ts index 95c5c3da..84361fef 100644 --- a/src/components/user/mypage/ContentTab.styled.ts +++ b/src/components/user/mypage/ContentTab.styled.ts @@ -76,4 +76,11 @@ export const FilterContainer = styled.div` width: 100%; background-color: ${({ theme }) => theme.color.lightgrey}; border-radius: ${({ theme }) => theme.borderRadius.large}; + + &:has(> div[data-type='noContent']) { + min-height: 100%; + display: flex; + justify-content: center; + align-items: center; + } `; diff --git a/src/components/user/mypage/activityLog/commentsActivity/CommentsActivity.tsx b/src/components/user/mypage/activityLog/commentsActivity/CommentsActivity.tsx index d935e8e5..f21e1f1c 100644 --- a/src/components/user/mypage/activityLog/commentsActivity/CommentsActivity.tsx +++ b/src/components/user/mypage/activityLog/commentsActivity/CommentsActivity.tsx @@ -14,7 +14,7 @@ export default function CommentsActivity() { if (!myCommentsData || myCommentsData.length === 0) { return ( - + ); diff --git a/src/components/user/mypage/activityLog/inquiries/Inquiries.styled.ts b/src/components/user/mypage/activityLog/inquiries/Inquiries.styled.ts index 080866c5..54f0fbcd 100644 --- a/src/components/user/mypage/activityLog/inquiries/Inquiries.styled.ts +++ b/src/components/user/mypage/activityLog/inquiries/Inquiries.styled.ts @@ -51,7 +51,8 @@ export const InquiriesWrapper = styled.div` `; export const WrapperNoContent = styled.div` - height: 95%; + height: 100%; + min-height: 100%; display: flex; align-items: center; `; diff --git a/src/components/user/mypage/activityLog/inquiries/Inquiries.tsx b/src/components/user/mypage/activityLog/inquiries/Inquiries.tsx index ecb5ba25..bff27229 100644 --- a/src/components/user/mypage/activityLog/inquiries/Inquiries.tsx +++ b/src/components/user/mypage/activityLog/inquiries/Inquiries.tsx @@ -14,7 +14,7 @@ export default function Inquiries() { if (!myInquiriesData || myInquiriesData?.length === 0) return ( - + ); diff --git a/src/components/user/mypage/joinedProject/MyJoinProjects.styled.ts b/src/components/user/mypage/joinedProject/MyJoinProjects.styled.ts index de62e10c..002146ee 100644 --- a/src/components/user/mypage/joinedProject/MyJoinProjects.styled.ts +++ b/src/components/user/mypage/joinedProject/MyJoinProjects.styled.ts @@ -39,6 +39,7 @@ export const WrapperProject = styled.div` flex-wrap: wrap; justify-content: space-between; gap: 2rem; + min-height: 100%; @media ${({ theme }) => theme.mediaQuery.tablet} { padding: 1rem; diff --git a/src/components/user/mypage/notifications/all/All.tsx b/src/components/user/mypage/notifications/all/All.tsx index e9d0da55..5baa50f5 100644 --- a/src/components/user/mypage/notifications/all/All.tsx +++ b/src/components/user/mypage/notifications/all/All.tsx @@ -43,7 +43,7 @@ export default function All() { if (!alarmListData || alarmListData.length === 0 || filterLength === 0) { return ( - + ); From 2ca0ed5b9ebcffc289c6371b0eea488ba4ed227e Mon Sep 17 00:00:00 2001 From: YouD0313 <102004480+YouD0313@users.noreply.github.com> Date: Sun, 18 May 2025 17:28:57 +0900 Subject: [PATCH 03/27] =?UTF-8?q?refactor:=20=EB=B2=84=ED=8A=BC=20?= =?UTF-8?q?=EB=86=92=EC=9D=B4=20fit-content=20=EC=A1=B0=EC=A0=95=20?= =?UTF-8?q?=ED=9B=84=20=EC=A4=91=EA=B0=84=EC=A0=95=EB=A0=AC,=20=EA=B2=80?= =?UTF-8?q?=EC=83=89=EC=96=B4=20=EC=97=86=EC=9D=84=EB=95=8C=20=EA=B2=80?= =?UTF-8?q?=EC=83=89=20=EB=90=98=EC=A7=80=EC=95=8A=EA=B2=8C=20=EB=AA=A8?= =?UTF-8?q?=EB=8B=AC=EC=B0=BD=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CustomerServiceHeader.styled.ts | 5 ++++- .../customerService/CustomerServiceHeader.tsx | 17 ++++++++++++++--- src/constants/user/customerService.ts | 4 ++++ 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/components/user/customerService/CustomerServiceHeader.styled.ts b/src/components/user/customerService/CustomerServiceHeader.styled.ts index 76e659d4..cf7ee146 100644 --- a/src/components/user/customerService/CustomerServiceHeader.styled.ts +++ b/src/components/user/customerService/CustomerServiceHeader.styled.ts @@ -37,10 +37,13 @@ export const SearchBarInput = styled.input` export const ButtonWrapper = styled.div` display: flex; + justify-content: center; + align-items: center; gap: 0.5rem; `; -export const UturnButton = styled.button` +export const XButton = styled.button` + height: fit-content; &:hover { color: ${({ theme }) => theme.color.lightnavy}; } diff --git a/src/components/user/customerService/CustomerServiceHeader.tsx b/src/components/user/customerService/CustomerServiceHeader.tsx index 5d3e9939..fb83c498 100644 --- a/src/components/user/customerService/CustomerServiceHeader.tsx +++ b/src/components/user/customerService/CustomerServiceHeader.tsx @@ -3,6 +3,9 @@ import * as S from './CustomerServiceHeader.styled'; import MovedInquiredLink from './MoveInquiredLink'; import { Outlet } from 'react-router-dom'; import { useState } from 'react'; +import Modal from '../../common/modal/Modal'; +import { useModal } from '../../../hooks/useModal'; +import { MODAL_MESSAGE_CUSTOMER_SERVICE } from '../../../constants/user/customerService'; interface CustomerServiceHeaderProps { title: string; @@ -16,10 +19,15 @@ export default function CustomerServiceHeader({ onGetKeyword, }: CustomerServiceHeaderProps) { const [inputValue, setInputValue] = useState(''); + const { isOpen, message, handleModalOpen, handleModalClose } = useModal(); const handleSubmitKeyword = (e: React.FormEvent) => { e.preventDefault(); - onGetKeyword(inputValue); + if (inputValue.trim() === '') { + return handleModalOpen(MODAL_MESSAGE_CUSTOMER_SERVICE.noKeyword); + } else { + return onGetKeyword(inputValue); + } }; const handleChangeValue = (e: React.ChangeEvent) => { @@ -47,13 +55,13 @@ export default function CustomerServiceHeader({ /> {keyword !== '' && ( - - + )} @@ -63,6 +71,9 @@ export default function CustomerServiceHeader({ + + {message} + ); } diff --git a/src/constants/user/customerService.ts b/src/constants/user/customerService.ts index be80ebcc..63545a92 100644 --- a/src/constants/user/customerService.ts +++ b/src/constants/user/customerService.ts @@ -8,6 +8,10 @@ export const INQUIRY_CATEGORY = [ export const EMPTY_IMAGE = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7' as const; +export const MODAL_MESSAGE_CUSTOMER_SERVICE = { + noKeyword: '검색어를 입력하세요.', +}; + export const My_INQUIRIES_MESSAGE = { categoryDefault: '카테고리', fileDefault: '선택된 파일이 없습니다.', From 1cd81f2d6604639d24ea82e5939996a866081fd0 Mon Sep 17 00:00:00 2001 From: YouD0313 <102004480+YouD0313@users.noreply.github.com> Date: Sun, 18 May 2025 19:05:59 +0900 Subject: [PATCH 04/27] =?UTF-8?q?feat:=20=EA=B2=80=EC=83=89=ED=95=A0?= =?UTF-8?q?=EB=95=8C=20=EC=BF=BC=EB=A6=AC=EC=8A=A4=ED=81=AC=EB=A7=81=20+?= =?UTF-8?q?=20=EB=92=A4=EB=A1=9C=EA=B0=80=EA=B1=B0=EB=82=98=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=EC=9C=BC=EB=A1=9C=20=EA=B0=88=20=EB=95=8C=20=EA=B2=80?= =?UTF-8?q?=EC=83=89=EB=82=B4=EC=9A=A9=EC=9D=B4=20=EC=9E=88=EB=8B=A4?= =?UTF-8?q?=EB=A9=B4=20=EA=B7=B8=EB=8C=80=EB=A1=9C=20=EB=B0=9B=EC=95=84=20?= =?UTF-8?q?=EC=98=AC=20=EC=88=98=20=EC=9E=88=EA=B2=8C=20ux=20=ED=96=A5?= =?UTF-8?q?=EC=83=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../customerService/CustomerServiceHeader.tsx | 22 +++++++++++++--- .../noticeDetail/NoticeDetailBundle.tsx | 3 ++- .../bottom/NoticeDetailBottom.tsx | 4 ++- .../noticeDetail/bottom/button/ListButton.tsx | 12 +++++++-- .../user/customerService/notice/Notice.tsx | 26 ++++++++++++++----- 5 files changed, 52 insertions(+), 15 deletions(-) diff --git a/src/components/user/customerService/CustomerServiceHeader.tsx b/src/components/user/customerService/CustomerServiceHeader.tsx index fb83c498..2eca5341 100644 --- a/src/components/user/customerService/CustomerServiceHeader.tsx +++ b/src/components/user/customerService/CustomerServiceHeader.tsx @@ -1,8 +1,8 @@ import { MagnifyingGlassIcon, XCircleIcon } from '@heroicons/react/24/outline'; import * as S from './CustomerServiceHeader.styled'; import MovedInquiredLink from './MoveInquiredLink'; -import { Outlet } from 'react-router-dom'; -import { useState } from 'react'; +import { Outlet, useLocation, useSearchParams } from 'react-router-dom'; +import { useEffect, useState } from 'react'; import Modal from '../../common/modal/Modal'; import { useModal } from '../../../hooks/useModal'; import { MODAL_MESSAGE_CUSTOMER_SERVICE } from '../../../constants/user/customerService'; @@ -20,13 +20,26 @@ export default function CustomerServiceHeader({ }: CustomerServiceHeaderProps) { const [inputValue, setInputValue] = useState(''); const { isOpen, message, handleModalOpen, handleModalClose } = useModal(); + const [searchParams, setSearchParams] = useSearchParams(); + + const handleKeyword = (inputValue: string) => { + const newSearchParams = new URLSearchParams(searchParams); + if (inputValue === '') { + newSearchParams.delete('keyword'); + } else { + newSearchParams.set('keyword', inputValue); + } + setSearchParams(newSearchParams); + }; const handleSubmitKeyword = (e: React.FormEvent) => { e.preventDefault(); if (inputValue.trim() === '') { return handleModalOpen(MODAL_MESSAGE_CUSTOMER_SERVICE.noKeyword); } else { - return onGetKeyword(inputValue); + onGetKeyword(inputValue); + handleKeyword(inputValue); + return; } }; @@ -38,6 +51,7 @@ export default function CustomerServiceHeader({ const handleReset = () => { onGetKeyword(''); setInputValue(''); + handleKeyword(''); }; return ( @@ -50,7 +64,7 @@ export default function CustomerServiceHeader({ diff --git a/src/components/user/customerService/noticeDetail/NoticeDetailBundle.tsx b/src/components/user/customerService/noticeDetail/NoticeDetailBundle.tsx index e9bdcc44..5ec216b9 100644 --- a/src/components/user/customerService/noticeDetail/NoticeDetailBundle.tsx +++ b/src/components/user/customerService/noticeDetail/NoticeDetailBundle.tsx @@ -11,6 +11,7 @@ export default function NoticeDetailBundle() { const location = useLocation(); const { noticeId } = useParams(); const id = noticeId || String(location.state.id); + const keyword = location.state.keyword; const { noticeDetail: noticeDetailData, isLoading } = useGetNoticeDetail(id); @@ -57,7 +58,7 @@ export default function NoticeDetailBundle() { createdAt={createdAt} viewCount={viewCount} /> - + ); } diff --git a/src/components/user/customerService/noticeDetail/bottom/NoticeDetailBottom.tsx b/src/components/user/customerService/noticeDetail/bottom/NoticeDetailBottom.tsx index 370bf5d3..71929605 100644 --- a/src/components/user/customerService/noticeDetail/bottom/NoticeDetailBottom.tsx +++ b/src/components/user/customerService/noticeDetail/bottom/NoticeDetailBottom.tsx @@ -7,11 +7,13 @@ import * as S from './NoticeDetailBottom.styled'; interface NoticeDetailBottomProps { prev: OtherNotice | null; next: OtherNotice | null; + keyword: string; } export default function NoticeDetailBottom({ prev, next, + keyword, }: NoticeDetailBottomProps) { return ( @@ -37,7 +39,7 @@ export default function NoticeDetailBottom({ ) : ( 다음 공지사항이 없습니다. )} - + ); } diff --git a/src/components/user/customerService/noticeDetail/bottom/button/ListButton.tsx b/src/components/user/customerService/noticeDetail/bottom/button/ListButton.tsx index 34a15300..1cae25b3 100644 --- a/src/components/user/customerService/noticeDetail/bottom/button/ListButton.tsx +++ b/src/components/user/customerService/noticeDetail/bottom/button/ListButton.tsx @@ -2,12 +2,20 @@ import { ROUTES } from '../../../../../../constants/user/routes'; import ContentBorder from '../../../../../common/contentBorder/ContentBorder'; import * as S from './ListButton.styled'; -export default function ListButton() { +interface ListButtonProps { + keyword: string; +} + +export default function ListButton({ keyword }: ListButtonProps) { + const isKeyword = keyword ? `?keyword=${keyword}` : ``; + return ( <> - + 목록 diff --git a/src/pages/user/customerService/notice/Notice.tsx b/src/pages/user/customerService/notice/Notice.tsx index 44bed823..7dc6cf60 100644 --- a/src/pages/user/customerService/notice/Notice.tsx +++ b/src/pages/user/customerService/notice/Notice.tsx @@ -1,4 +1,4 @@ -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import * as S from './Notice.styled'; import { NoticeSearch } from '../../../../models/customerService'; import { useGetNotice } from '../../../../hooks/user/useGetNotice'; @@ -9,21 +9,33 @@ import { ROUTES } from '../../../../constants/user/routes'; import NoticeList from '../../../../components/user/customerService/notice/NoticeList'; import NoResult from '../../../../components/common/noResult/NoResult'; import Pagination from '../../../../components/common/pagination/Pagination'; +import { useLocation } from 'react-router-dom'; export default function Notice() { - const [keyword, setKeyword] = useState({ + const [noticeSearch, setNoticeSearch] = useState({ keyword: '', page: 1, }); const [value, setValue] = useState(''); - const { noticeData, isLoading } = useGetNotice(keyword); + const { noticeData, isLoading } = useGetNotice(noticeSearch); + const location = useLocation(); + const hasKeyword = location.search + ? decodeURI(location.search.split('=')[1]) + : ''; + + useEffect(() => { + if (hasKeyword) { + setNoticeSearch((prev) => ({ ...prev, keyword: hasKeyword })); + setValue(hasKeyword); + } + }, [hasKeyword]); const handleGetKeyword = (keyword: string) => { - setKeyword((prev) => ({ ...prev, keyword })); + setNoticeSearch((prev) => ({ ...prev, keyword })); setValue(keyword); }; const handleChangePagination = (page: number) => { - setKeyword((prev) => ({ ...prev, page })); + setNoticeSearch((prev) => ({ ...prev, page })); }; if (isLoading) { @@ -52,7 +64,7 @@ export default function Notice() { noticeData.notices.map((list) => ( @@ -64,7 +76,7 @@ export default function Notice() { )} From 1412b3d895490fbdfc34db8465c96eb574471e95 Mon Sep 17 00:00:00 2001 From: YouD0313 <102004480+YouD0313@users.noreply.github.com> Date: Mon, 19 May 2025 16:49:51 +0900 Subject: [PATCH 05/27] =?UTF-8?q?refactor:=20refresh=20=ED=86=A0=ED=81=B0?= =?UTF-8?q?=20httpOnly=20=EC=9D=B4=EB=AF=80=EB=A1=9C=20=EC=8A=A4=ED=86=A0?= =?UTF-8?q?=EB=A6=AC=EC=A7=80=20get,=20set=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/auth.api.ts | 17 +++++++++++++++++ src/api/http.api.ts | 16 ++++++---------- src/hooks/useAuth.ts | 8 ++++---- src/hooks/user/useNotification.ts | 7 +++---- src/models/auth.ts | 10 +++++++--- src/store/authStore.ts | 31 +++++++------------------------ 6 files changed, 44 insertions(+), 45 deletions(-) diff --git a/src/api/auth.api.ts b/src/api/auth.api.ts index b00e5634..5e090f44 100644 --- a/src/api/auth.api.ts +++ b/src/api/auth.api.ts @@ -17,6 +17,7 @@ export const postVerificationEmail = async (email: string) => { export const postVerifyEmailCode = async (data: VerifyEmail) => { try { const response = await httpClient.post('/authenticode/verify', data); + return response; } catch (error) { console.error('verifiyEmailCode:', error); @@ -42,6 +43,7 @@ export const postSignUp = async ( ) => { try { const response = await httpClient.post('/auth/sign-up', data); + return response; } catch (error) { console.error('signup:', error); @@ -54,6 +56,7 @@ export const postResetPassword = async ( ) => { try { const response = await httpClient.post('/auth/password/reset', data); + return response; } catch (error) { console.error('resetpassword:', error); @@ -64,9 +67,23 @@ export const postResetPassword = async ( export const postLogin = async (data: loginFormValues) => { try { const response = await httpClient.post('/auth/login', data); + + console.log(response.data); + return response.data; } catch (error) { console.error('login:', error); throw error; } }; + +export const postRefresh = async () => { + try { + const response = await httpClient.post('/auth/refresh'); + + return response.data; + } catch (e) { + console.error(e); + throw e; + } +}; diff --git a/src/api/http.api.ts b/src/api/http.api.ts index a5a163da..0e8ea275 100644 --- a/src/api/http.api.ts +++ b/src/api/http.api.ts @@ -12,10 +12,9 @@ export const createClient = (config?: AxiosRequestConfig) => { timeout: DEFAULT_TIMEOUT, headers: { 'content-type': 'application/json', - authorization: - getTokens().accessToken || getTokens().refreshToken - ? `Bearer ${getTokens().accessToken}` - : '', + authorization: getTokens().accessToken + ? `Bearer ${getTokens().accessToken}` + : '', }, withCredentials: true, ...config, @@ -50,16 +49,13 @@ export const createClient = (config?: AxiosRequestConfig) => { originalRequest._retry = true; try { - const refreshToken = getTokens().refreshToken; - const refreshResponse = await axios.post(`${BASE_URL}auth/refresh`, { - refreshToken, + withCredentials: true, }); - const { accessToken: newAccessToken, refreshToken: newRefreshToken } = - refreshResponse.data; + const { accessToken: newAccessToken } = refreshResponse.data; - storeLogin(newAccessToken, newRefreshToken); + storeLogin(newAccessToken); originalRequest.headers['Authorization'] = `Bearer ${newAccessToken}`; return await axios(originalRequest); diff --git a/src/hooks/useAuth.ts b/src/hooks/useAuth.ts index d0e3ecb3..36ba0e68 100644 --- a/src/hooks/useAuth.ts +++ b/src/hooks/useAuth.ts @@ -61,15 +61,15 @@ export const useAuth = (handleModalOpen: (message: string) => void) => { >({ mutationFn: async ({ email, password }) => { const response = await postLogin({ email, password }); - const { accessToken, refreshToken } = response.data; + const { accessToken } = response.data; const userData = response.user; - return { accessToken, refreshToken, userData }; + return { accessToken, userData }; }, onSuccess: async (data) => { - const { accessToken, refreshToken, userData } = data; + const { accessToken, userData } = data; handleModalOpen(MODAL_MESSAGE.loginSuccess); setTimeout(() => { - storeLogin(accessToken, refreshToken, userData); + storeLogin(accessToken, userData); navigate(ROUTES.main); }, 1000); }, diff --git a/src/hooks/user/useNotification.ts b/src/hooks/user/useNotification.ts index 42b542b0..32cc653c 100644 --- a/src/hooks/user/useNotification.ts +++ b/src/hooks/user/useNotification.ts @@ -29,10 +29,9 @@ const useNotification = () => { `${import.meta.env.VITE_APP_API_BASE_URL}user/sse`, { headers: { - Authorization: - getTokens().accessToken || getTokens().refreshToken - ? `Bearer ${getTokens().accessToken}` - : '', + Authorization: getTokens().accessToken + ? `Bearer ${getTokens().accessToken}` + : '', 'Content-Type': 'application/json', }, heartbeatTimeout: 12 * 60 * 1000, diff --git a/src/models/auth.ts b/src/models/auth.ts index a0a12380..0a70de2a 100644 --- a/src/models/auth.ts +++ b/src/models/auth.ts @@ -1,6 +1,4 @@ //model - -import { UserData } from '../store/authStore'; import { ApiCommonType } from './apiCommon'; export interface VerifyEmail { @@ -14,6 +12,12 @@ export interface ApiVerifyNickname extends ApiCommonType { export interface LoginResponse { accessToken: string; - refreshToken: string; userData: UserData; } + +export interface UserData { + id: number; + email: string; + nickname: string; + admin: boolean; +} diff --git a/src/store/authStore.ts b/src/store/authStore.ts index ff5f8d60..a53ba7dc 100644 --- a/src/store/authStore.ts +++ b/src/store/authStore.ts @@ -1,21 +1,12 @@ import { create } from 'zustand'; import { persist } from 'zustand/middleware'; import { decryptData, encryptData } from '../util/cryptoUtils'; - -export interface UserData { - id: number; - email: string; - nickname: string; -} +import type { UserData } from '../models/auth'; interface AuthState { isLoggedIn: boolean; userData: UserData | null; - storeLogin: ( - accessToken: string, - refreshToken?: string, - userData?: UserData - ) => void; + storeLogin: (accessToken: string, userData?: UserData) => void; storeLogout: () => void; } @@ -23,6 +14,7 @@ const initialUserData: UserData = { id: 0, email: '', nickname: '', + admin: false, }; export const getStoredUserData = () => { @@ -32,21 +24,16 @@ export const getStoredUserData = () => { export const getTokens = () => { const accessToken = localStorage.getItem('accessToken'); - const refreshToken = localStorage.getItem('refreshToken'); - return { accessToken, refreshToken }; + return { accessToken }; }; -const setTokens = (accessToken: string, refreshToken?: string) => { +const setTokens = (accessToken: string) => { localStorage.setItem('accessToken', accessToken); - if (refreshToken) { - localStorage.setItem('refreshToken', refreshToken); - } }; const removeTokens = () => { localStorage.removeItem('accessToken'); - localStorage.removeItem('refreshToken'); }; const useAuthStore = create( @@ -55,12 +42,8 @@ const useAuthStore = create( isLoggedIn: getTokens()?.accessToken ? true : false, userData: getTokens()?.accessToken ? initialUserData : null, - storeLogin: ( - accessToken: string, - refreshToken?: string, - userData?: UserData - ) => { - setTokens(accessToken, refreshToken); + storeLogin: (accessToken: string, userData?: UserData) => { + setTokens(accessToken); localStorage.setItem('userData', encryptData(userData)); set({ isLoggedIn: true, userData }); }, From 6976859efedc33cd9e262f43de28d8267daed75e Mon Sep 17 00:00:00 2001 From: YouD0313 <102004480+YouD0313@users.noreply.github.com> Date: Mon, 19 May 2025 16:58:28 +0900 Subject: [PATCH 06/27] =?UTF-8?q?fix:=20=EA=B3=B5=EA=B3=A0=EA=B4=80?= =?UTF-8?q?=EB=A6=AC=20=EB=A7=88=EC=A7=84=EB=B0=94=ED=85=80=202rem=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80,=20projectDetail=20=EC=BD=98=EC=86=94?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=20=EC=BD=94=EB=93=9C=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/user/manage/myProjectList/MyProjectList.styled.ts | 1 + src/pages/user/projectDetail/ProjectDetail.tsx | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/pages/user/manage/myProjectList/MyProjectList.styled.ts b/src/pages/user/manage/myProjectList/MyProjectList.styled.ts index ead5e9a5..1a7ba734 100644 --- a/src/pages/user/manage/myProjectList/MyProjectList.styled.ts +++ b/src/pages/user/manage/myProjectList/MyProjectList.styled.ts @@ -4,6 +4,7 @@ export const ManageProjectsContainer = styled.div` width: 100%; display: flex; justify-content: center; + margin-bottom: 2rem; `; export const ManageProjectsWrapper = styled.div` diff --git a/src/pages/user/projectDetail/ProjectDetail.tsx b/src/pages/user/projectDetail/ProjectDetail.tsx index 14079c45..6da5faa7 100644 --- a/src/pages/user/projectDetail/ProjectDetail.tsx +++ b/src/pages/user/projectDetail/ProjectDetail.tsx @@ -58,9 +58,6 @@ const ProjectDetail = () => { navigate(`/user/${userId}`); }; - console.log(data); - console.log(userData.id); - return ( From f49b976b0d2489e7beff29132b419eafa76d79ce Mon Sep 17 00:00:00 2001 From: YouD0313 <102004480+YouD0313@users.noreply.github.com> Date: Tue, 20 May 2025 09:59:19 +0900 Subject: [PATCH 07/27] =?UTF-8?q?refactor:=20=EC=9E=90=EC=9E=98=ED=95=9C?= =?UTF-8?q?=20css=20=EC=88=98=EC=A0=95,=20=ED=94=84=EB=A1=9C=ED=95=84=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=EC=8B=9C=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20?= =?UTF-8?q?=EB=B3=80=EC=88=98=EB=AA=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../customerService/inquiry/Inquiry.styled.ts | 3 ++- .../user/customerService/inquiry/Inquiry.tsx | 2 -- .../joinedProject/MyJoinProjects.styled.ts | 2 -- .../myProfile/editProfile/EditProfile.tsx | 24 +++++++++---------- src/constants/user/routes.ts | 2 +- 5 files changed, 15 insertions(+), 18 deletions(-) diff --git a/src/components/user/customerService/inquiry/Inquiry.styled.ts b/src/components/user/customerService/inquiry/Inquiry.styled.ts index ad912bb5..b63e2fdb 100644 --- a/src/components/user/customerService/inquiry/Inquiry.styled.ts +++ b/src/components/user/customerService/inquiry/Inquiry.styled.ts @@ -142,9 +142,10 @@ export const InquiryShowFile = styled.span` display: flex; justify-content: start; align-items: center; + overflow: hidden; padding: 0.5rem; border: 1px solid ${({ theme }) => theme.color.border}; - width: 40%; + width: 50%; color: ${({ theme }) => theme.color.navy}; border-radius: 0 ${({ theme }) => theme.borderRadius.primary} ${({ theme }) => theme.borderRadius.primary} 0; diff --git a/src/components/user/customerService/inquiry/Inquiry.tsx b/src/components/user/customerService/inquiry/Inquiry.tsx index af49aef4..e0982b51 100644 --- a/src/components/user/customerService/inquiry/Inquiry.tsx +++ b/src/components/user/customerService/inquiry/Inquiry.tsx @@ -65,8 +65,6 @@ export default function Inquiry() { content: form.content.trim() !== '', }; - console.log(isCategoryOpen); - if (!isValid.category) { return handleModalOpen(INQUIRY_MESSAGE.selectCategory); } diff --git a/src/components/user/mypage/joinedProject/MyJoinProjects.styled.ts b/src/components/user/mypage/joinedProject/MyJoinProjects.styled.ts index 002146ee..f89024b7 100644 --- a/src/components/user/mypage/joinedProject/MyJoinProjects.styled.ts +++ b/src/components/user/mypage/joinedProject/MyJoinProjects.styled.ts @@ -22,8 +22,6 @@ export const Section = styled.div` export const NoWrapper = styled.div` width: 100%; - height: 80%; - padding: 2rem 0 5rem; `; export const Wrapper = styled.div` diff --git a/src/components/user/mypage/myProfile/editProfile/EditProfile.tsx b/src/components/user/mypage/myProfile/editProfile/EditProfile.tsx index 0926bc72..812976b2 100644 --- a/src/components/user/mypage/myProfile/editProfile/EditProfile.tsx +++ b/src/components/user/mypage/myProfile/editProfile/EditProfile.tsx @@ -22,11 +22,11 @@ type ProfileFormData = z.infer; export default function EditProfile() { const [nickname, setNickname] = useState(''); const { - myData, + userInfoData, scrollRef, handleModalOpen, }: { - myData: UserInfo; + userInfoData: UserInfo; scrollRef: React.RefObject; handleModalOpen: (message: string) => void; } = useOutletContext(); @@ -62,14 +62,14 @@ export default function EditProfile() { }, [scrollRef]); useEffect(() => { - if (myData) { - const skillTagIds = myData.skills + if (userInfoData) { + const skillTagIds = userInfoData.skills .map( (skill) => skillTagsData.find((tag) => tag.name === skill.name)?.id ) .filter((id): id is number => id !== undefined); - const positionTagIds = myData.positions + const positionTagIds = userInfoData.positions .map( (position) => positionTagsData.find((tag) => tag.id === position.id)?.id @@ -77,14 +77,14 @@ export default function EditProfile() { .filter((id): id is number => id !== undefined); reset({ - nickname: myData.nickname, - bio: myData.bio || '', - beginner: myData.beginner, + nickname: userInfoData.nickname, + bio: userInfoData.bio || '', + beginner: userInfoData.beginner, positionTagIds, - github: myData.github || '', + github: userInfoData.github || '', skillTagIds, - career: myData.career?.length - ? myData.career.map((item) => ({ + career: userInfoData.career?.length + ? userInfoData.career.map((item) => ({ name: item.name, periodStart: item.periodStart.split('T')[0], periodEnd: item.periodEnd.split('T')[0], @@ -93,7 +93,7 @@ export default function EditProfile() { : [{ name: '', periodStart: '', periodEnd: '', role: '' }], }); } - }, [myData, skillTagsData, positionTagsData, reset]); + }, [userInfoData, skillTagsData, positionTagsData, reset]); const { fields, append, remove } = useFieldArray({ control, name: 'career' }); diff --git a/src/constants/user/routes.ts b/src/constants/user/routes.ts index a2618850..cbb668d8 100644 --- a/src/constants/user/routes.ts +++ b/src/constants/user/routes.ts @@ -10,7 +10,7 @@ export const ROUTES = { manageProjectsRoot: '/manage', manageProjectsPassNonPass: '/manage/pass-nonpass', mypage: '/mypage', - mypageEdit: '/mypage/edit', + mypageEdit: 'edit', joinedProjects: 'joined-projects', managedProjects: 'managed-projects', myPageNotifications: 'notifications', From 92773fb309449693b9671bfd1ae59b129c64811f Mon Sep 17 00:00:00 2001 From: YouD0313 <102004480+YouD0313@users.noreply.github.com> Date: Wed, 21 May 2025 14:12:13 +0900 Subject: [PATCH 08/27] =?UTF-8?q?desing:=20=EB=A7=88=EC=9D=B4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=EC=8A=A4=ED=94=BC=EB=84=88,=20noContent?= =?UTF-8?q?=20=EC=A4=91=EA=B0=84=EC=A0=95=EB=A0=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/auth.api.ts | 2 ++ src/api/http.api.ts | 11 +++++++---- .../commentsActivity/CommentsActivity.styled.ts | 7 ++----- .../commentsActivity/CommentsActivity.tsx | 10 +++++++--- .../mypage/activityLog/inquiries/Inquiries.styled.ts | 8 ++------ .../user/mypage/activityLog/inquiries/Inquiries.tsx | 10 +++++++--- src/components/user/mypage/notifications/all/All.tsx | 6 +++++- .../appliedProjects/AppliedProjects.styled.ts | 3 +++ .../appliedProjects/AppliedProjects.tsx | 12 ++++++++++-- src/util/cryptoUtils.ts | 2 +- 10 files changed, 46 insertions(+), 25 deletions(-) diff --git a/src/api/auth.api.ts b/src/api/auth.api.ts index 5e090f44..36b6d4a4 100644 --- a/src/api/auth.api.ts +++ b/src/api/auth.api.ts @@ -3,6 +3,7 @@ import { httpClient } from './http.api'; import { loginFormValues } from '../pages/login/Login'; import { registerFormValues } from '../pages/user/register/Register'; import { changePasswordFormValues } from '../pages/user/changePassword/ChangePassword'; +import useAuthStore from '../store/authStore'; export const postVerificationEmail = async (email: string) => { try { @@ -65,6 +66,7 @@ export const postResetPassword = async ( }; export const postLogin = async (data: loginFormValues) => { + console.log('로그인 api 안', useAuthStore.getState()); try { const response = await httpClient.post('/auth/login', data); diff --git a/src/api/http.api.ts b/src/api/http.api.ts index 0e8ea275..77213aec 100644 --- a/src/api/http.api.ts +++ b/src/api/http.api.ts @@ -47,18 +47,21 @@ export const createClient = (config?: AxiosRequestConfig) => { !originalRequest._retry ) { originalRequest._retry = true; + console.log('트라이문 밖', useAuthStore.getState()); try { - const refreshResponse = await axios.post(`${BASE_URL}auth/refresh`, { - withCredentials: true, - }); + console.log('트라이문 안', useAuthStore.getState()); + + const refreshResponse = await axiosInstance.post( + `${BASE_URL}/auth/refresh` + ); const { accessToken: newAccessToken } = refreshResponse.data; storeLogin(newAccessToken); originalRequest.headers['Authorization'] = `Bearer ${newAccessToken}`; - return await axios(originalRequest); + return await axiosInstance(originalRequest); } catch (refreshError) { storeLogout(); return Promise.reject(refreshError); diff --git a/src/components/user/mypage/activityLog/commentsActivity/CommentsActivity.styled.ts b/src/components/user/mypage/activityLog/commentsActivity/CommentsActivity.styled.ts index a423a17f..43576d0d 100644 --- a/src/components/user/mypage/activityLog/commentsActivity/CommentsActivity.styled.ts +++ b/src/components/user/mypage/activityLog/commentsActivity/CommentsActivity.styled.ts @@ -1,14 +1,11 @@ import styled from 'styled-components'; +import { WrapperNoContent } from '../../notifications/all/All.styled'; export const Container = styled.div` height: 100%; `; -export const WrapperNoContent = styled.div` - height: 100%; - display: flex; - align-items: center; -`; +export const WrapperNoContentAppliedProjects = styled(WrapperNoContent)``; export const CommentsWrapper = styled.div` padding: 1.5rem; diff --git a/src/components/user/mypage/activityLog/commentsActivity/CommentsActivity.tsx b/src/components/user/mypage/activityLog/commentsActivity/CommentsActivity.tsx index f21e1f1c..b5a34e29 100644 --- a/src/components/user/mypage/activityLog/commentsActivity/CommentsActivity.tsx +++ b/src/components/user/mypage/activityLog/commentsActivity/CommentsActivity.tsx @@ -9,14 +9,18 @@ export default function CommentsActivity() { const { myCommentsData, isLoading } = useGetMyComments(); if (isLoading) { - return ; + return ( + + + + ); } if (!myCommentsData || myCommentsData.length === 0) { return ( - + - + ); } diff --git a/src/components/user/mypage/activityLog/inquiries/Inquiries.styled.ts b/src/components/user/mypage/activityLog/inquiries/Inquiries.styled.ts index 54f0fbcd..4bb756a6 100644 --- a/src/components/user/mypage/activityLog/inquiries/Inquiries.styled.ts +++ b/src/components/user/mypage/activityLog/inquiries/Inquiries.styled.ts @@ -1,4 +1,5 @@ import styled from 'styled-components'; +import { WrapperNoContent } from '../../notifications/all/All.styled'; export const container = styled.div` height: 100%; @@ -50,9 +51,4 @@ export const InquiriesWrapper = styled.div` gap: 1.5rem; `; -export const WrapperNoContent = styled.div` - height: 100%; - min-height: 100%; - display: flex; - align-items: center; -`; +export const WrapperNoContentAppliedProjects = styled(WrapperNoContent)``; diff --git a/src/components/user/mypage/activityLog/inquiries/Inquiries.tsx b/src/components/user/mypage/activityLog/inquiries/Inquiries.tsx index bff27229..1bc1c918 100644 --- a/src/components/user/mypage/activityLog/inquiries/Inquiries.tsx +++ b/src/components/user/mypage/activityLog/inquiries/Inquiries.tsx @@ -9,14 +9,18 @@ export default function Inquiries() { const { myInquiriesData, isLoading } = useGetMyInquiries(); if (isLoading) { - return ; + return ( + + + + ); } if (!myInquiriesData || myInquiriesData?.length === 0) return ( - + - + ); return ( diff --git a/src/components/user/mypage/notifications/all/All.tsx b/src/components/user/mypage/notifications/all/All.tsx index 5baa50f5..f0b713c7 100644 --- a/src/components/user/mypage/notifications/all/All.tsx +++ b/src/components/user/mypage/notifications/all/All.tsx @@ -29,7 +29,11 @@ export default function All() { }; if (isLoading) { - return ; + return ( + + + + ); } const filterLength = alarmListData?.filter((list) => { diff --git a/src/components/user/mypage/notifications/appliedProjects/AppliedProjects.styled.ts b/src/components/user/mypage/notifications/appliedProjects/AppliedProjects.styled.ts index 2b173b19..9b77cb71 100644 --- a/src/components/user/mypage/notifications/appliedProjects/AppliedProjects.styled.ts +++ b/src/components/user/mypage/notifications/appliedProjects/AppliedProjects.styled.ts @@ -1,4 +1,7 @@ import styled from 'styled-components'; +import { WrapperNoContent } from '../all/All.styled'; + +export const WrapperNoContentAppliedProjects = styled(WrapperNoContent)``; export const container = styled.div` width: 100%; diff --git a/src/components/user/mypage/notifications/appliedProjects/AppliedProjects.tsx b/src/components/user/mypage/notifications/appliedProjects/AppliedProjects.tsx index 610c0a19..1eb45e5b 100644 --- a/src/components/user/mypage/notifications/appliedProjects/AppliedProjects.tsx +++ b/src/components/user/mypage/notifications/appliedProjects/AppliedProjects.tsx @@ -10,11 +10,19 @@ export default function AppliedProjects() { const { myAppliedStatusListData, isLoading } = useMyAppliedStatusList(); if (isLoading) { - return ; + return ( + + + + ); } if (!myAppliedStatusListData || myAppliedStatusListData.length === 0) { - return ; + return ( + + + + ); } return ( diff --git a/src/util/cryptoUtils.ts b/src/util/cryptoUtils.ts index 480c06cf..5e03dfbb 100644 --- a/src/util/cryptoUtils.ts +++ b/src/util/cryptoUtils.ts @@ -1,5 +1,5 @@ import CryptoJS from 'crypto-js'; -import { UserData } from '../store/authStore'; +import type { UserData } from '../models/auth'; export const encryptData = (data: UserData | undefined) => { return CryptoJS.AES.encrypt( From 5a394c966a31e42f39d83d8c423d6655dde150d5 Mon Sep 17 00:00:00 2001 From: YouD0313 <102004480+YouD0313@users.noreply.github.com> Date: Wed, 21 May 2025 15:53:43 +0900 Subject: [PATCH 09/27] =?UTF-8?q?comment:=20=EC=A3=BC=EC=84=9D-=EC=84=A4?= =?UTF-8?q?=EB=AA=85=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/http.api.ts | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/api/http.api.ts b/src/api/http.api.ts index 77213aec..ea7a187c 100644 --- a/src/api/http.api.ts +++ b/src/api/http.api.ts @@ -47,25 +47,31 @@ export const createClient = (config?: AxiosRequestConfig) => { !originalRequest._retry ) { originalRequest._retry = true; - console.log('트라이문 밖', useAuthStore.getState()); - try { - console.log('트라이문 안', useAuthStore.getState()); + /** + * http 로컬 환경이라 httpOnly인 refresh 토큰 전송 불가 + * 배포 후 사용 (주석처리) + */ + // try { + // console.log('트라이문 안', useAuthStore.getState()); - const refreshResponse = await axiosInstance.post( - `${BASE_URL}/auth/refresh` - ); + // const refreshResponse = await axiosInstance.post( + // `${BASE_URL}/auth/refresh` + // ); - const { accessToken: newAccessToken } = refreshResponse.data; + // const { accessToken: newAccessToken } = refreshResponse.data; - storeLogin(newAccessToken); - originalRequest.headers['Authorization'] = `Bearer ${newAccessToken}`; + // storeLogin(newAccessToken); + // originalRequest.headers['Authorization'] = `Bearer ${newAccessToken}`; - return await axiosInstance(originalRequest); - } catch (refreshError) { - storeLogout(); - return Promise.reject(refreshError); - } + // return await axiosInstance(originalRequest); + // } catch (refreshError) { + // storeLogout(); + // return Promise.reject(refreshError); + // } + + storeLogout(); + return Promise.reject(error); } return Promise.reject(error); } From ba3c47da8e18bc68ebd62bd78bc8968f6a49be51 Mon Sep 17 00:00:00 2001 From: YouD0313 <102004480+YouD0313@users.noreply.github.com> Date: Thu, 22 May 2025 12:56:16 +0900 Subject: [PATCH 10/27] =?UTF-8?q?refactor:=20authStroe=20=EA=B5=AC?= =?UTF-8?q?=EC=A1=B0=20=EC=88=98=EC=A0=95,=20=EB=A7=88=EC=9D=B4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20noContent=20=EC=A0=95=EB=A0=AC=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/auth.api.ts | 3 - src/api/http.api.ts | 35 +++++------ .../joinedProject/MyJoinProjects.styled.ts | 12 ++-- .../mypage/joinedProject/MyJoinProjects.tsx | 50 +++++++++------- .../appliedProjects/AppliedProjects.tsx | 2 + src/hooks/useAuth.ts | 7 ++- src/hooks/user/useNotification.ts | 9 ++- src/pages/login/LoginSuccess.tsx | 7 +-- src/store/authStore.ts | 60 +++++++------------ 9 files changed, 88 insertions(+), 97 deletions(-) diff --git a/src/api/auth.api.ts b/src/api/auth.api.ts index 36b6d4a4..317d3a4a 100644 --- a/src/api/auth.api.ts +++ b/src/api/auth.api.ts @@ -66,12 +66,9 @@ export const postResetPassword = async ( }; export const postLogin = async (data: loginFormValues) => { - console.log('로그인 api 안', useAuthStore.getState()); try { const response = await httpClient.post('/auth/login', data); - console.log(response.data); - return response.data; } catch (error) { console.error('login:', error); diff --git a/src/api/http.api.ts b/src/api/http.api.ts index ea7a187c..d71a1d92 100644 --- a/src/api/http.api.ts +++ b/src/api/http.api.ts @@ -1,28 +1,24 @@ import axios, { AxiosRequestConfig } from 'axios'; -import useAuthStore, { getTokens } from '../store/authStore'; +import useAuthStore from '../store/authStore'; +import { postRefresh } from './auth.api'; export const BASE_URL = `${import.meta.env.VITE_APP_API_BASE_URL}`; const DEFAULT_TIMEOUT = 15000; export const createClient = (config?: AxiosRequestConfig) => { - const { storeLogin, storeLogout } = useAuthStore.getState(); + const { login, logout } = useAuthStore.getState(); + console.log('전체', useAuthStore.getState()); const axiosInstance = axios.create({ baseURL: BASE_URL, timeout: DEFAULT_TIMEOUT, - headers: { - 'content-type': 'application/json', - authorization: getTokens().accessToken - ? `Bearer ${getTokens().accessToken}` - : '', - }, withCredentials: true, ...config, }); axiosInstance.interceptors.request.use( (config) => { - const { accessToken } = getTokens(); + const accessToken = useAuthStore.getState().accessToken; if (accessToken) { config.headers['Authorization'] = `Bearer ${accessToken}`; } @@ -41,36 +37,41 @@ export const createClient = (config?: AxiosRequestConfig) => { async (error) => { const originalRequest = error.config; + if (!originalRequest.retryCount) { + originalRequest.retryCount = 0; + } + if ( error.response && error.response.status === 401 && - !originalRequest._retry + originalRequest.retryCount < 5 ) { - originalRequest._retry = true; + originalRequest.retryCount += 1; /** * http 로컬 환경이라 httpOnly인 refresh 토큰 전송 불가 * 배포 후 사용 (주석처리) + * 5회 시도후 안되면 로그아웃 처리하기 */ // try { // console.log('트라이문 안', useAuthStore.getState()); - // const refreshResponse = await axiosInstance.post( - // `${BASE_URL}/auth/refresh` - // ); + // const refreshResponse = await postRefresh() // const { accessToken: newAccessToken } = refreshResponse.data; - // storeLogin(newAccessToken); + // login(newAccessToken,null); // originalRequest.headers['Authorization'] = `Bearer ${newAccessToken}`; // return await axiosInstance(originalRequest); // } catch (refreshError) { - // storeLogout(); + // logout(); // return Promise.reject(refreshError); // } - storeLogout(); + logout(); + useAuthStore.persist.clearStorage(); + window.location.href = '/login'; return Promise.reject(error); } return Promise.reject(error); diff --git a/src/components/user/mypage/joinedProject/MyJoinProjects.styled.ts b/src/components/user/mypage/joinedProject/MyJoinProjects.styled.ts index f89024b7..fac54f15 100644 --- a/src/components/user/mypage/joinedProject/MyJoinProjects.styled.ts +++ b/src/components/user/mypage/joinedProject/MyJoinProjects.styled.ts @@ -1,8 +1,14 @@ import styled from 'styled-components'; +import { WrapperNoContent } from '../notifications/all/All.styled'; -export const Container = styled.section` +export const Container = styled.section<{ $isNoContent: boolean }>` width: 100%; height: 85%; + + min-height: 100%; + display: flex; + justify-content: center; + align-items: center; `; export const FilterWrapper = styled.div` @@ -20,9 +26,7 @@ export const Section = styled.div` flex-direction: column; `; -export const NoWrapper = styled.div` - width: 100%; -`; +export const WrapperNoContentMyJoinedProjects = styled(WrapperNoContent)``; export const Wrapper = styled.div` display: flex; diff --git a/src/components/user/mypage/joinedProject/MyJoinProjects.tsx b/src/components/user/mypage/joinedProject/MyJoinProjects.tsx index ab88846b..bd4a5cfd 100644 --- a/src/components/user/mypage/joinedProject/MyJoinProjects.tsx +++ b/src/components/user/mypage/joinedProject/MyJoinProjects.tsx @@ -15,29 +15,33 @@ const MyJoinProjects = () => { } return ( - - - 참여한 프로젝트 리스트 - - {myJoinedProjectListData && myJoinedProjectListData?.length > 0 ? ( - - - {myJoinedProjectListData?.map((project) => ( - - - - ))} - - - ) : ( - - - - )} - + <> + + + 참여한 프로젝트 리스트 + + {myJoinedProjectListData && myJoinedProjectListData?.length > 0 ? ( + + + {myJoinedProjectListData?.map((project) => ( + + + + ))} + + + ) : ( + + + + )} + + ); }; diff --git a/src/components/user/mypage/notifications/appliedProjects/AppliedProjects.tsx b/src/components/user/mypage/notifications/appliedProjects/AppliedProjects.tsx index 1eb45e5b..65854817 100644 --- a/src/components/user/mypage/notifications/appliedProjects/AppliedProjects.tsx +++ b/src/components/user/mypage/notifications/appliedProjects/AppliedProjects.tsx @@ -8,6 +8,7 @@ import { ROUTES } from '../../../../../constants/user/routes'; export default function AppliedProjects() { const { myAppliedStatusListData, isLoading } = useMyAppliedStatusList(); + console.log(myAppliedStatusListData); if (isLoading) { return ( @@ -18,6 +19,7 @@ export default function AppliedProjects() { } if (!myAppliedStatusListData || myAppliedStatusListData.length === 0) { + console.log(myAppliedStatusListData); return ( diff --git a/src/hooks/useAuth.ts b/src/hooks/useAuth.ts index 36ba0e68..c17b688c 100644 --- a/src/hooks/useAuth.ts +++ b/src/hooks/useAuth.ts @@ -13,7 +13,7 @@ import { changePasswordFormValues } from '../pages/user/changePassword/ChangePas export const useAuth = (handleModalOpen: (message: string) => void) => { const navigate = useNavigate(); - const { storeLogin, storeLogout } = useAuthStore.getState(); + const { login, logout } = useAuthStore.getState(); const queryClient = useQueryClient(); const signupMutation = useMutation< @@ -69,7 +69,7 @@ export const useAuth = (handleModalOpen: (message: string) => void) => { const { accessToken, userData } = data; handleModalOpen(MODAL_MESSAGE.loginSuccess); setTimeout(() => { - storeLogin(accessToken, userData); + login(accessToken, userData); navigate(ROUTES.main); }, 1000); }, @@ -95,8 +95,9 @@ export const useAuth = (handleModalOpen: (message: string) => void) => { }; const userLogout = () => { - storeLogout(); + logout(); queryClient.removeQueries({ queryKey: myInfoKey.myProfile }); + useAuthStore.persist.clearStorage(); handleModalOpen(MODAL_MESSAGE.logout); setTimeout(() => { navigate(ROUTES.main); diff --git a/src/hooks/user/useNotification.ts b/src/hooks/user/useNotification.ts index 32cc653c..1a70e2d1 100644 --- a/src/hooks/user/useNotification.ts +++ b/src/hooks/user/useNotification.ts @@ -3,12 +3,13 @@ import { useEffect, useRef, useState } from 'react'; import { useQueryClient } from '@tanstack/react-query'; import { AlarmList } from '../queries/user/keys'; import { AlarmLive } from '../../models/alarm'; -import useAuthStore, { getTokens } from '../../store/authStore'; +import useAuthStore from '../../store/authStore'; import { useToast } from '../useToast'; const useNotification = () => { const [signalData, setSignalData] = useState(null); const queryClient = useQueryClient(); + const accessToken = useAuthStore.getState().accessToken; const userId = useAuthStore((state) => state.userData?.id); const { showToast } = useToast(); @@ -29,9 +30,7 @@ const useNotification = () => { `${import.meta.env.VITE_APP_API_BASE_URL}user/sse`, { headers: { - Authorization: getTokens().accessToken - ? `Bearer ${getTokens().accessToken}` - : '', + Authorization: accessToken ? `Bearer ${accessToken}` : '', 'Content-Type': 'application/json', }, heartbeatTimeout: 12 * 60 * 1000, @@ -67,7 +66,7 @@ const useNotification = () => { eventSourceRef.current = null; } }; - }, [queryClient, userId]); + }, [queryClient, userId, accessToken, EventSourceImpl]); useEffect(() => { if (signalData) { diff --git a/src/pages/login/LoginSuccess.tsx b/src/pages/login/LoginSuccess.tsx index 53a33a2b..130eae07 100644 --- a/src/pages/login/LoginSuccess.tsx +++ b/src/pages/login/LoginSuccess.tsx @@ -10,7 +10,7 @@ import { AUTH_MESSAGE } from '../../constants/user/authConstants'; function LoginSuccess() { const [searchParams] = useSearchParams(); - const { storeLogin } = useAuthStore.getState(); + const { login } = useAuthStore.getState(); const navigate = useNavigate(); const { isOpen, message, handleModalOpen, handleModalClose } = useModal(); @@ -18,8 +18,7 @@ function LoginSuccess() { const accessToken = searchParams.get('accessToken'); if (accessToken) { - storeLogin(accessToken); - localStorage.setItem('accessToken', accessToken); + login(accessToken, null); navigate(ROUTES.main); } else { handleModalOpen(AUTH_MESSAGE.isNotToken); @@ -27,7 +26,7 @@ function LoginSuccess() { navigate(ROUTES.login); }, 1000); } - }, [searchParams, storeLogin, handleModalOpen, navigate]); + }, [searchParams, login, handleModalOpen, navigate]); return ( diff --git a/src/store/authStore.ts b/src/store/authStore.ts index a53ba7dc..33a12b90 100644 --- a/src/store/authStore.ts +++ b/src/store/authStore.ts @@ -1,59 +1,43 @@ import { create } from 'zustand'; -import { persist } from 'zustand/middleware'; +import { createJSONStorage, persist } from 'zustand/middleware'; import { decryptData, encryptData } from '../util/cryptoUtils'; import type { UserData } from '../models/auth'; interface AuthState { isLoggedIn: boolean; userData: UserData | null; - storeLogin: (accessToken: string, userData?: UserData) => void; - storeLogout: () => void; + accessToken: string | null; + login: (accessToken: string, userData: UserData | null) => void; + logout: () => void; } -const initialUserData: UserData = { - id: 0, - email: '', - nickname: '', - admin: false, -}; - -export const getStoredUserData = () => { - const encryptedData = localStorage.getItem('userData'); - return encryptedData ? decryptData(encryptedData) : null; -}; - -export const getTokens = () => { - const accessToken = localStorage.getItem('accessToken'); - - return { accessToken }; -}; - -const setTokens = (accessToken: string) => { - localStorage.setItem('accessToken', accessToken); -}; - -const removeTokens = () => { - localStorage.removeItem('accessToken'); -}; +// 암호화 함수 +// export const getStoredUserData = () => { +// const encryptedData = localStorage.getItem('userData'); +// return encryptedData ? decryptData(encryptedData) : null; +// }; const useAuthStore = create( persist( (set) => ({ - isLoggedIn: getTokens()?.accessToken ? true : false, - userData: getTokens()?.accessToken ? initialUserData : null, - - storeLogin: (accessToken: string, userData?: UserData) => { - setTokens(accessToken); - localStorage.setItem('userData', encryptData(userData)); - set({ isLoggedIn: true, userData }); + isLoggedIn: false, + accessToken: null, + userData: null, + + login: (accessToken: string, userData: UserData | null) => { + set({ + isLoggedIn: true, + accessToken, + userData: userData ? userData : null, + }); }, - storeLogout: () => { - removeTokens(); - set({ isLoggedIn: false, userData: null }); + logout: () => { + set({ isLoggedIn: false, accessToken: null, userData: null }); }, }), { name: 'auth-storage', // 로컬스토리지에 저장될 이름 + storage: createJSONStorage(() => localStorage), } ) ); From 45957a798bb89446d1ef54138493f10d9112dae5 Mon Sep 17 00:00:00 2001 From: YouD0313 <102004480+YouD0313@users.noreply.github.com> Date: Thu, 22 May 2025 12:59:05 +0900 Subject: [PATCH 11/27] =?UTF-8?q?fix:=20http,=20auth=EC=AA=BD=20=EB=94=94?= =?UTF-8?q?=EB=B2=84=EA=B9=85=EC=9A=A9=20=EC=BD=98=EC=86=94=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=20=EC=BD=94=EB=93=9C=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/http.api.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/api/http.api.ts b/src/api/http.api.ts index d71a1d92..16647d83 100644 --- a/src/api/http.api.ts +++ b/src/api/http.api.ts @@ -7,7 +7,6 @@ const DEFAULT_TIMEOUT = 15000; export const createClient = (config?: AxiosRequestConfig) => { const { login, logout } = useAuthStore.getState(); - console.log('전체', useAuthStore.getState()); const axiosInstance = axios.create({ baseURL: BASE_URL, @@ -54,8 +53,6 @@ export const createClient = (config?: AxiosRequestConfig) => { * 5회 시도후 안되면 로그아웃 처리하기 */ // try { - // console.log('트라이문 안', useAuthStore.getState()); - // const refreshResponse = await postRefresh() // const { accessToken: newAccessToken } = refreshResponse.data; From 2854f00290585a06992f155fc44d7773d56888ff Mon Sep 17 00:00:00 2001 From: YouD0313 <102004480+YouD0313@users.noreply.github.com> Date: Thu, 22 May 2025 13:01:30 +0900 Subject: [PATCH 12/27] =?UTF-8?q?design:=20=EC=8A=A4=ED=83=80=EC=9D=BC=20?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=ED=94=84=EB=A1=AD?= =?UTF-8?q?=EC=8A=A4=EB=A7=8C=20=EB=84=98=EA=B2=A8=EC=A3=BC=EA=B3=A0=20css?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EA=B5=AC=ED=98=84=ED=95=98=EC=A7=80=20?= =?UTF-8?q?=EC=95=8A=EC=95=84=EC=84=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mypage/joinedProject/MyJoinProjects.styled.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/components/user/mypage/joinedProject/MyJoinProjects.styled.ts b/src/components/user/mypage/joinedProject/MyJoinProjects.styled.ts index fac54f15..4d1144f0 100644 --- a/src/components/user/mypage/joinedProject/MyJoinProjects.styled.ts +++ b/src/components/user/mypage/joinedProject/MyJoinProjects.styled.ts @@ -1,14 +1,18 @@ -import styled from 'styled-components'; +import styled, { css } from 'styled-components'; import { WrapperNoContent } from '../notifications/all/All.styled'; export const Container = styled.section<{ $isNoContent: boolean }>` width: 100%; height: 85%; - min-height: 100%; - display: flex; - justify-content: center; - align-items: center; + ${({ $isNoContent }) => + $isNoContent && + css` + min-height: 100%; + display: flex; + justify-content: center; + align-items: center; + `} `; export const FilterWrapper = styled.div` From 98575cd855d449ae288649d4a977443c5c0aeb02 Mon Sep 17 00:00:00 2001 From: YouD0313 <102004480+YouD0313@users.noreply.github.com> Date: Thu, 22 May 2025 15:10:57 +0900 Subject: [PATCH 13/27] =?UTF-8?q?design:=20FAQ=20content=20=EB=82=B4?= =?UTF-8?q?=EB=A6=B4=EB=95=8C=20=EB=B6=80=EB=93=9C=EB=9F=BD=EA=B2=8C=20?= =?UTF-8?q?=EB=82=98=ED=83=80=EB=82=98=EA=B2=8C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../customerService/faq/FAQContent.styled.ts | 34 +++++++++++++++---- .../user/customerService/faq/FAQContent.tsx | 14 ++++---- .../commentsActivity/CommentsActivity.tsx | 2 +- .../activityLog/inquiries/Inquiries.tsx | 2 +- .../joinedProject/MyJoinProjects.styled.ts | 2 +- .../user/mypage/notifications/all/All.tsx | 2 +- .../appliedProjects/AppliedProjects.tsx | 4 +-- .../user/userPage/userProfile/UserProfile.tsx | 2 +- 8 files changed, 40 insertions(+), 22 deletions(-) diff --git a/src/components/user/customerService/faq/FAQContent.styled.ts b/src/components/user/customerService/faq/FAQContent.styled.ts index ae35aeab..2d7026f5 100644 --- a/src/components/user/customerService/faq/FAQContent.styled.ts +++ b/src/components/user/customerService/faq/FAQContent.styled.ts @@ -32,12 +32,34 @@ export const ListPlusIcon = styled.div<{ $isOpen: boolean }>` } `; -export const ListContentWrapper = styled.div` - cursor: auto; - background: ${({ theme }) => theme.color.lightgrey}; - padding: 1.5rem 1rem; - display: flex; - gap: 0.5rem; +export const ListContentWrapper = styled.div<{ $isShowContent: boolean }>` + max-height: 0; + overflow: hidden; + + @keyframes slice-show { + 0% { + opacity: 0; + } + 50% { + opacity: 0.5; + } + 100% { + opacity: 1; + } + } + + ${({ $isShowContent }) => + $isShowContent && + css` + max-height: 100vh; + opacity: 1; + cursor: auto; + background: ${({ theme }) => theme.color.lightgrey}; + padding: 1.5rem 1rem; + display: flex; + gap: 0.5rem; + animation: slice-show 300ms; + `} `; export const ListButtonWrapper = styled.div` diff --git a/src/components/user/customerService/faq/FAQContent.tsx b/src/components/user/customerService/faq/FAQContent.tsx index 9df54089..0286bb27 100644 --- a/src/components/user/customerService/faq/FAQContent.tsx +++ b/src/components/user/customerService/faq/FAQContent.tsx @@ -21,14 +21,12 @@ export default function FAQContent({ list }: FAQContentProps) { - {isFAQContentOpen && ( - - - - - {list.content} - - )} + + + + + {list.content} + ); } diff --git a/src/components/user/mypage/activityLog/commentsActivity/CommentsActivity.tsx b/src/components/user/mypage/activityLog/commentsActivity/CommentsActivity.tsx index b5a34e29..2b7ad066 100644 --- a/src/components/user/mypage/activityLog/commentsActivity/CommentsActivity.tsx +++ b/src/components/user/mypage/activityLog/commentsActivity/CommentsActivity.tsx @@ -11,7 +11,7 @@ export default function CommentsActivity() { if (isLoading) { return ( - + ); } diff --git a/src/components/user/mypage/activityLog/inquiries/Inquiries.tsx b/src/components/user/mypage/activityLog/inquiries/Inquiries.tsx index 1bc1c918..338eaa9e 100644 --- a/src/components/user/mypage/activityLog/inquiries/Inquiries.tsx +++ b/src/components/user/mypage/activityLog/inquiries/Inquiries.tsx @@ -11,7 +11,7 @@ export default function Inquiries() { if (isLoading) { return ( - + ); } diff --git a/src/components/user/mypage/joinedProject/MyJoinProjects.styled.ts b/src/components/user/mypage/joinedProject/MyJoinProjects.styled.ts index 4d1144f0..91178669 100644 --- a/src/components/user/mypage/joinedProject/MyJoinProjects.styled.ts +++ b/src/components/user/mypage/joinedProject/MyJoinProjects.styled.ts @@ -1,7 +1,7 @@ import styled, { css } from 'styled-components'; import { WrapperNoContent } from '../notifications/all/All.styled'; -export const Container = styled.section<{ $isNoContent: boolean }>` +export const Container = styled.section<{ $isNoContent?: boolean }>` width: 100%; height: 85%; diff --git a/src/components/user/mypage/notifications/all/All.tsx b/src/components/user/mypage/notifications/all/All.tsx index f0b713c7..2855a368 100644 --- a/src/components/user/mypage/notifications/all/All.tsx +++ b/src/components/user/mypage/notifications/all/All.tsx @@ -31,7 +31,7 @@ export default function All() { if (isLoading) { return ( - + ); } diff --git a/src/components/user/mypage/notifications/appliedProjects/AppliedProjects.tsx b/src/components/user/mypage/notifications/appliedProjects/AppliedProjects.tsx index 65854817..f84c37eb 100644 --- a/src/components/user/mypage/notifications/appliedProjects/AppliedProjects.tsx +++ b/src/components/user/mypage/notifications/appliedProjects/AppliedProjects.tsx @@ -8,18 +8,16 @@ import { ROUTES } from '../../../../../constants/user/routes'; export default function AppliedProjects() { const { myAppliedStatusListData, isLoading } = useMyAppliedStatusList(); - console.log(myAppliedStatusListData); if (isLoading) { return ( - + ); } if (!myAppliedStatusListData || myAppliedStatusListData.length === 0) { - console.log(myAppliedStatusListData); return ( diff --git a/src/components/user/userPage/userProfile/UserProfile.tsx b/src/components/user/userPage/userProfile/UserProfile.tsx index fb30315d..86c14ffe 100644 --- a/src/components/user/userPage/userProfile/UserProfile.tsx +++ b/src/components/user/userPage/userProfile/UserProfile.tsx @@ -15,7 +15,7 @@ const UserProfile = () => { const scrollRef = useRef(null); if (isLoading) { - return ; + return ; } if (!userData) { From 2b3cd229657f8985cf6d1e9b24c95707243e2918 Mon Sep 17 00:00:00 2001 From: YouD0313 <102004480+YouD0313@users.noreply.github.com> Date: Thu, 22 May 2025 16:07:57 +0900 Subject: [PATCH 14/27] =?UTF-8?q?refactor:=20authStore=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20=ED=9B=84=20=EA=B5=AC=EC=A1=B0=EB=B3=80=EA=B2=BD?= =?UTF-8?q?=EC=97=90=20=EB=94=B0=EB=A5=B8=20=EC=9E=84=ED=8F=AC=ED=8A=B8=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=EB=A7=88=EB=8B=A4=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/ProtectRoute.tsx | 2 +- src/components/common/header/Header.tsx | 2 +- src/components/common/sidebar/Sidebar.tsx | 2 +- src/hooks/user/useAlarmDelete.ts | 2 +- src/hooks/user/useAlarmList.ts | 2 +- src/hooks/user/useAlarmPatch.ts | 2 +- src/hooks/user/useGetMyComments.ts | 2 +- src/hooks/user/useGetMyInquiries.ts | 2 +- src/hooks/user/useMyInfo.ts | 6 +++--- src/hooks/user/useNotification.ts | 2 +- src/hooks/user/useUserInfo.ts | 2 +- src/pages/user/apply/Apply.tsx | 2 +- src/pages/user/apply/ApplyStep.tsx | 2 +- src/pages/user/projectDetail/ProjectDetail.tsx | 2 +- src/routes/AppRoutes.tsx | 2 +- 15 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/components/common/ProtectRoute.tsx b/src/components/common/ProtectRoute.tsx index 2767d52e..4825737c 100644 --- a/src/components/common/ProtectRoute.tsx +++ b/src/components/common/ProtectRoute.tsx @@ -9,7 +9,7 @@ interface ProtectRouteProps extends PropsWithChildren { } const ProtectRoute = ({ children, redirectUrl }: ProtectRouteProps) => { - const isLoggedIn = useAuthStore((state) => state.isLoggedIn); + const isLoggedIn = useAuthStore.getState().isLoggedIn; const { isOpen, message, handleModalOpen, handleModalClose } = useModal(); const [shouldRedirect, setShouldRedirect] = useState(false); diff --git a/src/components/common/header/Header.tsx b/src/components/common/header/Header.tsx index c2dc1aaf..770bbe29 100644 --- a/src/components/common/header/Header.tsx +++ b/src/components/common/header/Header.tsx @@ -23,7 +23,7 @@ function Header() { const location = useLocation(); const { isOpen, message, handleModalOpen, handleModalClose } = useModal(); const { userLogout } = useAuth(handleModalOpen); - const isLoggedIn = useAuthStore((state) => state.isLoggedIn); + const isLoggedIn = useAuthStore.getState().isLoggedIn; const { myData, isLoading } = useMyProfileInfo(); // const { signalData, setSignalData } = useNotification(); diff --git a/src/components/common/sidebar/Sidebar.tsx b/src/components/common/sidebar/Sidebar.tsx index 6a42d0e9..31c04982 100644 --- a/src/components/common/sidebar/Sidebar.tsx +++ b/src/components/common/sidebar/Sidebar.tsx @@ -20,7 +20,7 @@ interface SidebarProps { } const Sidebar = ({ menuItems, profileImage, nickname }: SidebarProps) => { - const isLoggedIn = useAuthStore((state) => state.isLoggedIn); + const isLoggedIn = useAuthStore.getState().isLoggedIn; const location = useLocation(); const isUserPage = location.pathname.includes('/user'); const isManagePage = location.pathname.includes('/manage'); diff --git a/src/hooks/user/useAlarmDelete.ts b/src/hooks/user/useAlarmDelete.ts index 16f437f7..cefa4a5c 100644 --- a/src/hooks/user/useAlarmDelete.ts +++ b/src/hooks/user/useAlarmDelete.ts @@ -4,7 +4,7 @@ import { AlarmList } from '../queries/user/keys'; import useAuthStore from '../../store/authStore'; export const useAlarmDelete = () => { - const userId = useAuthStore((state) => state.userData?.id); + const userId = useAuthStore.getState().userData?.id; const queryClient = useQueryClient(); const mutation = useMutation({ diff --git a/src/hooks/user/useAlarmList.ts b/src/hooks/user/useAlarmList.ts index c0a5a33b..19f4241a 100644 --- a/src/hooks/user/useAlarmList.ts +++ b/src/hooks/user/useAlarmList.ts @@ -4,7 +4,7 @@ import { getAlarmList } from '../../api/alarm.api'; import useAuthStore from '../../store/authStore'; const useAlarmList = () => { - const userId = useAuthStore((state) => state.userData?.id); + const userId = useAuthStore.getState().userData?.id; const { data: alarmListData, diff --git a/src/hooks/user/useAlarmPatch.ts b/src/hooks/user/useAlarmPatch.ts index e7e5cafc..d063a40b 100644 --- a/src/hooks/user/useAlarmPatch.ts +++ b/src/hooks/user/useAlarmPatch.ts @@ -4,7 +4,7 @@ import { AlarmList } from '../queries/user/keys'; import useAuthStore from '../../store/authStore'; export const useAlarmPatch = () => { - const userId = useAuthStore((state) => state.userData?.id); + const userId = useAuthStore.getState().userData?.id; const queryClient = useQueryClient(); const mutation = useMutation({ diff --git a/src/hooks/user/useGetMyComments.ts b/src/hooks/user/useGetMyComments.ts index 59d8b83e..188b7e8a 100644 --- a/src/hooks/user/useGetMyComments.ts +++ b/src/hooks/user/useGetMyComments.ts @@ -4,7 +4,7 @@ import useAuthStore from '../../store/authStore'; import { ActivityLog } from '../queries/user/keys'; export const useGetMyComments = () => { - const userId = useAuthStore((state) => state.userData?.id); + const userId = useAuthStore.getState().userData?.id; const { data: myCommentsData, isLoading } = useQuery({ queryKey: [ActivityLog.myComments, userId], diff --git a/src/hooks/user/useGetMyInquiries.ts b/src/hooks/user/useGetMyInquiries.ts index d7d0de9b..ec38dc8d 100644 --- a/src/hooks/user/useGetMyInquiries.ts +++ b/src/hooks/user/useGetMyInquiries.ts @@ -4,7 +4,7 @@ import useAuthStore from '../../store/authStore'; import { ActivityLog } from '../queries/user/keys'; export const useGetMyInquiries = () => { - const userId = useAuthStore((state) => state.userData?.id); + const userId = useAuthStore.getState().userData?.id; const { data: myInquiriesData, isLoading } = useQuery({ queryKey: [ActivityLog.myInquiries, userId], diff --git a/src/hooks/user/useMyInfo.ts b/src/hooks/user/useMyInfo.ts index 43df84e4..5073a196 100644 --- a/src/hooks/user/useMyInfo.ts +++ b/src/hooks/user/useMyInfo.ts @@ -16,7 +16,7 @@ import { ROUTES } from '../../constants/user/routes'; import { ApiAppliedProject, ApiJoinedProject } from '../../models/userProject'; export const useMyProfileInfo = () => { - const isLoggedIn = useAuthStore((state) => state.isLoggedIn); + const isLoggedIn = useAuthStore.getState().isLoggedIn; const { data, isLoading } = useQuery({ queryKey: myInfoKey.myProfile, @@ -84,7 +84,7 @@ export const useUploadProfileImg = ( }; export const useMyJoinedProjectList = () => { - const isLoggedIn = useAuthStore((state) => state.isLoggedIn); + const isLoggedIn = useAuthStore.getState().isLoggedIn; const { data, isLoading } = useQuery({ queryKey: ProjectListKey.myJoinedList, @@ -96,7 +96,7 @@ export const useMyJoinedProjectList = () => { }; export const useMyAppliedStatusList = () => { - const isLoggedIn = useAuthStore((state) => state.isLoggedIn); + const isLoggedIn = useAuthStore.getState().isLoggedIn; const { data, isLoading } = useQuery({ queryKey: ProjectListKey.myAppliedStatusList, diff --git a/src/hooks/user/useNotification.ts b/src/hooks/user/useNotification.ts index 1a70e2d1..a1f3a3f1 100644 --- a/src/hooks/user/useNotification.ts +++ b/src/hooks/user/useNotification.ts @@ -10,7 +10,7 @@ const useNotification = () => { const [signalData, setSignalData] = useState(null); const queryClient = useQueryClient(); const accessToken = useAuthStore.getState().accessToken; - const userId = useAuthStore((state) => state.userData?.id); + const userId = useAuthStore.getState().userData?.id; const { showToast } = useToast(); const eventSourceRef = useRef(null); diff --git a/src/hooks/user/useUserInfo.ts b/src/hooks/user/useUserInfo.ts index 61c5bcf8..99139a14 100644 --- a/src/hooks/user/useUserInfo.ts +++ b/src/hooks/user/useUserInfo.ts @@ -5,7 +5,7 @@ import { ApiUserInfo } from '../../models/userInfo'; import { getUserInfo } from '../../api/userpage.api'; export const useUserProfileInfo = (id: number) => { - const isLoggedIn = useAuthStore((state) => state.isLoggedIn); + const isLoggedIn = useAuthStore.getState().isLoggedIn; const { data, isLoading } = useQuery({ queryKey: [userInfoKey.userProfile, id], diff --git a/src/pages/user/apply/Apply.tsx b/src/pages/user/apply/Apply.tsx index 35c1c48f..193cbbcd 100644 --- a/src/pages/user/apply/Apply.tsx +++ b/src/pages/user/apply/Apply.tsx @@ -22,7 +22,7 @@ const Apply = () => { const { isOpen, handleModalOpen, handleModalClose, message } = useModal(); const { data: projectData, isLoading, isFetching } = useGetProjectData(id); const { applyProject } = useApplyProject({ id, handleModalOpen }); - const userEmail = useAuthStore((state) => state.userData?.email); + const userEmail = useAuthStore.getState().userData?.email; const { handleSubmit: onSubmitHandler, formState: { errors }, diff --git a/src/pages/user/apply/ApplyStep.tsx b/src/pages/user/apply/ApplyStep.tsx index 29f9f963..d3c7f0b5 100644 --- a/src/pages/user/apply/ApplyStep.tsx +++ b/src/pages/user/apply/ApplyStep.tsx @@ -29,7 +29,7 @@ const Apply = () => { useModal(); const { data: projectData, isLoading, isFetching } = useGetProjectData(id); const { applyProject } = useApplyProject({ id, handleModalOpen }); - const userData = useAuthStore((state) => state.userData); + const userData = useAuthStore.getState().userData; const { handleSubmit: onSubmitHandler, formState: { errors }, diff --git a/src/pages/user/projectDetail/ProjectDetail.tsx b/src/pages/user/projectDetail/ProjectDetail.tsx index 6da5faa7..f817c605 100644 --- a/src/pages/user/projectDetail/ProjectDetail.tsx +++ b/src/pages/user/projectDetail/ProjectDetail.tsx @@ -22,7 +22,7 @@ const ProjectDetail = () => { const navigate = useNavigate(); const { isOpen, message, handleModalClose, handleModalOpen } = useModal(); const { data, isLoading, isFetching } = useGetProjectData(id); - const { userData } = useAuthStore((state) => state); + const userData = useAuthStore.getState().userData; useEffect(() => { if (!data) { diff --git a/src/routes/AppRoutes.tsx b/src/routes/AppRoutes.tsx index 2f4b65ca..e8bb3709 100644 --- a/src/routes/AppRoutes.tsx +++ b/src/routes/AppRoutes.tsx @@ -101,7 +101,7 @@ const ModifyProject = lazy( const Evaluation = lazy(() => import('../pages/user/evaluation/Evaluation')); const AppRoutes = () => { - const isLoggedIn = useAuthStore((state) => state.isLoggedIn); + const isLoggedIn = useAuthStore.getState().isLoggedIn; const routeList = [ { From 4927479d6439fd3899a8655c13aa3c9834a55710 Mon Sep 17 00:00:00 2001 From: YouD0313 <102004480+YouD0313@users.noreply.github.com> Date: Thu, 22 May 2025 17:42:18 +0900 Subject: [PATCH 15/27] =?UTF-8?q?refacctor:=20=EA=B3=B5=EA=B3=A0=EA=B4=80?= =?UTF-8?q?=EB=A6=AC=20=EC=8A=A4=ED=94=BC=EB=84=88=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/user/usePostInquiry.ts | 2 +- .../user/manage/myProjectList/MyProjectList.styled.ts | 6 ++++++ src/pages/user/manage/myProjectList/MyProjectList.tsx | 11 ++++++++++- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/hooks/user/usePostInquiry.ts b/src/hooks/user/usePostInquiry.ts index 6a38f521..bca5d3a0 100644 --- a/src/hooks/user/usePostInquiry.ts +++ b/src/hooks/user/usePostInquiry.ts @@ -10,7 +10,7 @@ export const usePostInquiry = ( handleModalOpen: (message: string) => void, pathname: string = '' ) => { - const userId = useAuthStore((state) => state.userData?.id); + const userId = useAuthStore.getState().userData?.id; const navigate = useNavigate(); const queryClient = useQueryClient(); diff --git a/src/pages/user/manage/myProjectList/MyProjectList.styled.ts b/src/pages/user/manage/myProjectList/MyProjectList.styled.ts index 1a7ba734..55d9d393 100644 --- a/src/pages/user/manage/myProjectList/MyProjectList.styled.ts +++ b/src/pages/user/manage/myProjectList/MyProjectList.styled.ts @@ -1,4 +1,10 @@ import styled from 'styled-components'; +import { WrapperNoContent } from '../../../../components/user/mypage/notifications/all/All.styled'; + +export const WrapperNoContentMyProjectList = styled(WrapperNoContent)` + height: 80vh; + justify-content: center; +`; export const ManageProjectsContainer = styled.div` width: 100%; diff --git a/src/pages/user/manage/myProjectList/MyProjectList.tsx b/src/pages/user/manage/myProjectList/MyProjectList.tsx index 08945980..77c1384e 100644 --- a/src/pages/user/manage/myProjectList/MyProjectList.tsx +++ b/src/pages/user/manage/myProjectList/MyProjectList.tsx @@ -1,10 +1,19 @@ +import { Spinner } from '../../../../components/common/loadingSpinner/LoadingSpinner.styled'; import Title from '../../../../components/common/title/Title'; import CardList from '../../../../components/user/manageProjects/CardList'; import { useManagedProjects } from '../../../../hooks/user/useManagedProjects'; import * as S from './MyProjectList.styled'; const MyProjectList = () => { - const { managedProjects } = useManagedProjects(); + const { managedProjects, isLoading } = useManagedProjects(); + + if (!isLoading) { + return ( + + + + ); + } return ( From 6e52ba2c21de805b3e09de03962b26eeb07cefbb Mon Sep 17 00:00:00 2001 From: YouD0313 <102004480+YouD0313@users.noreply.github.com> Date: Thu, 22 May 2025 17:43:40 +0900 Subject: [PATCH 16/27] =?UTF-8?q?fix:=20=EB=A1=9C=EB=94=A9=20=EC=A1=B0?= =?UTF-8?q?=EA=B1=B4=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/user/manage/myProjectList/MyProjectList.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/user/manage/myProjectList/MyProjectList.tsx b/src/pages/user/manage/myProjectList/MyProjectList.tsx index 77c1384e..2a234b15 100644 --- a/src/pages/user/manage/myProjectList/MyProjectList.tsx +++ b/src/pages/user/manage/myProjectList/MyProjectList.tsx @@ -7,7 +7,7 @@ import * as S from './MyProjectList.styled'; const MyProjectList = () => { const { managedProjects, isLoading } = useManagedProjects(); - if (!isLoading) { + if (isLoading) { return ( From 51a9c74e695e7701da5fa18067bd98d884de5177 Mon Sep 17 00:00:00 2001 From: YouD0313 <102004480+YouD0313@users.noreply.github.com> Date: Mon, 26 May 2025 05:09:09 +0900 Subject: [PATCH 17/27] =?UTF-8?q?feat:=20=EB=AC=B8=EC=9D=98=ED=95=98?= =?UTF-8?q?=EA=B8=B0=20=EC=9D=B4=EB=AF=B8=EC=A7=80=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EC=B5=9C=EB=8C=80=203=EA=B0=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/auth.api.ts | 14 +- .../customerService/inquiry/Inquiry.styled.ts | 62 +++++++-- .../user/customerService/inquiry/Inquiry.tsx | 128 ++++++++++++++---- src/constants/user/customerService.ts | 3 +- src/constants/user/routes.ts | 2 +- src/hooks/useOauth.ts | 9 ++ src/models/auth.ts | 5 + src/pages/login/LoginApi.tsx | 43 ++++++ src/pages/login/LoginSuccess.tsx | 3 +- src/routes/AppRoutes.tsx | 3 +- 10 files changed, 226 insertions(+), 46 deletions(-) create mode 100644 src/hooks/useOauth.ts create mode 100644 src/pages/login/LoginApi.tsx diff --git a/src/api/auth.api.ts b/src/api/auth.api.ts index 317d3a4a..970c83ae 100644 --- a/src/api/auth.api.ts +++ b/src/api/auth.api.ts @@ -1,9 +1,8 @@ -import { ApiVerifyNickname, VerifyEmail } from '../models/auth'; +import { ApiOauth, ApiVerifyNickname, VerifyEmail } from '../models/auth'; import { httpClient } from './http.api'; import { loginFormValues } from '../pages/login/Login'; import { registerFormValues } from '../pages/user/register/Register'; import { changePasswordFormValues } from '../pages/user/changePassword/ChangePassword'; -import useAuthStore from '../store/authStore'; export const postVerificationEmail = async (email: string) => { try { @@ -86,3 +85,14 @@ export const postRefresh = async () => { throw e; } }; + +export const getOauthLogin = async () => { + try { + const response = await httpClient.get(`/auth/oauth-login`); + + return response.data; + } catch (e) { + console.error(e); + throw e; + } +}; diff --git a/src/components/user/customerService/inquiry/Inquiry.styled.ts b/src/components/user/customerService/inquiry/Inquiry.styled.ts index b63e2fdb..2a7d2d31 100644 --- a/src/components/user/customerService/inquiry/Inquiry.styled.ts +++ b/src/components/user/customerService/inquiry/Inquiry.styled.ts @@ -112,11 +112,41 @@ export const Content = styled.textarea` font-size: 1rem; `; +export const InquiryFileContainer = styled.div` + width: 100%; + display: flex; + flex-direction: column; + gap: 1rem; + min-height: 50px; + position: relative; +`; + export const InquiryFileWrapper = styled.div` display: flex; height: 40px; `; +export const InquirySelectFile = styled(InquiryFileWrapper)` + position: absolute; + right: 0; +`; + +export const InquiryShowFile = styled.span` + display: flex; + justify-content: start; + align-items: center; + overflow: hidden; + padding: 0.5rem; + border: 1px solid ${({ theme }) => theme.color.border}; + width: 50%; + color: ${({ theme }) => theme.color.navy}; + border-radius: ${({ theme }) => theme.borderRadius.primary}; +`; + +export const InquiryDefault = styled(InquiryShowFile)` + padding: 0; +`; + export const InquiryFileLabel = styled.label` display: flex; justify-content: center; @@ -127,8 +157,7 @@ export const InquiryFileLabel = styled.label` background: ${({ theme }) => theme.color.navy}; color: ${({ theme }) => theme.color.white}; border: 1px solid ${({ theme }) => theme.color.navy}; - border-radius: ${({ theme }) => theme.borderRadius.primary} 0 0 - ${({ theme }) => theme.borderRadius.primary}; + border-radius: ${({ theme }) => theme.borderRadius.primary}; &:hover { background: ${({ theme }) => theme.color.lightgrey}; @@ -138,19 +167,6 @@ export const InquiryFileLabel = styled.label` } `; -export const InquiryShowFile = styled.span` - display: flex; - justify-content: start; - align-items: center; - overflow: hidden; - padding: 0.5rem; - border: 1px solid ${({ theme }) => theme.color.border}; - width: 50%; - color: ${({ theme }) => theme.color.navy}; - border-radius: 0 ${({ theme }) => theme.borderRadius.primary} - ${({ theme }) => theme.borderRadius.primary} 0; -`; - export const InquiryFile = styled.input` position: absolute; width: 0; @@ -164,6 +180,22 @@ export const FileImg = styled.img` height: 40px; `; +export const FileDeleteXButton = styled.button` + position: relative; + color: ${({ theme }) => theme.color.navy}; + z-index: 1; + + svg { + border-radius: 50%; + background: ${({ theme }) => theme.color.white}; + border: 1px solid ${({ theme }) => theme.color.navy}; + top: -0.2rem; + left: -0.5rem; + position: absolute; + width: 1rem; + } +`; + export const SendButtonWrapper = styled.div` width: 100%; display: flex; diff --git a/src/components/user/customerService/inquiry/Inquiry.tsx b/src/components/user/customerService/inquiry/Inquiry.tsx index e0982b51..66903565 100644 --- a/src/components/user/customerService/inquiry/Inquiry.tsx +++ b/src/components/user/customerService/inquiry/Inquiry.tsx @@ -5,7 +5,7 @@ import { My_INQUIRIES_MESSAGE, } from '../../../../constants/user/customerService'; import * as S from './Inquiry.styled'; -import { ChevronDownIcon } from '@heroicons/react/24/outline'; +import { ChevronDownIcon, XMarkIcon } from '@heroicons/react/24/outline'; import React, { useEffect, useState } from 'react'; import type { InquiryFormData } from '../../../../models/inquiry'; import { usePostInquiry } from '../../../../hooks/user/usePostInquiry'; @@ -17,8 +17,7 @@ interface FormStateType { category: string; title: string; content: string; - fileValue: string; - fileImage: string | null; + images: File | null; } export default function Inquiry() { @@ -34,13 +33,18 @@ export default function Inquiry() { location.state.from || '' ); const [isCategoryOpen, setIsCategoryOpen] = useState(false); + const [imageFiles, setImageFiles] = useState< + { fileValue: string; preview: string; image: File | null }[] + >([ + { fileValue: My_INQUIRIES_MESSAGE.fileDefault, preview: '', image: null }, + ]); const [form, setForm] = useState({ category: My_INQUIRIES_MESSAGE.categoryDefault, title: '', content: '', - fileValue: My_INQUIRIES_MESSAGE.fileDefault, - fileImage: null, + images: null, }); + const MAX_FILE_COUNT = 3; const handleSubmitInquiry = (e: React.FormEvent) => { e.preventDefault(); @@ -65,6 +69,21 @@ export default function Inquiry() { content: form.content.trim() !== '', }; + imageFiles.forEach((file) => { + if ( + file.fileValue === My_INQUIRIES_MESSAGE.fileDefault || + file.image === null + ) { + return; + } else { + formData.append('images', file.image); + } + }); + + for (const entries of formData) { + console.log(entries); + } + if (!isValid.category) { return handleModalOpen(INQUIRY_MESSAGE.selectCategory); } @@ -80,8 +99,7 @@ export default function Inquiry() { category: My_INQUIRIES_MESSAGE.categoryDefault, title: '', content: '', - fileValue: My_INQUIRIES_MESSAGE.fileDefault, - fileImage: null, + images: null, }); }; @@ -89,9 +107,10 @@ export default function Inquiry() { setForm((prev) => ({ ...prev, category })); setIsCategoryOpen((prev) => !prev); }; + const handleChangeFile = (e: React.ChangeEvent) => { const fileValue = e.target.value; - const image = e.target.files?.[0]; + const image = e.target.files?.[0] ?? null; const MAX_FILE_SIZE = 5 * 1024 * 1024; if (image && image.size > MAX_FILE_SIZE) { @@ -100,17 +119,58 @@ export default function Inquiry() { return; } - const fileImage = image ? URL.createObjectURL(image) : null; - setForm((prev) => ({ ...prev, fileValue, fileImage })); + if (imageFiles.length >= MAX_FILE_COUNT) { + handleModalOpen(INQUIRY_MESSAGE.maxFileCount); + e.target.value = ''; + return; + } + + const preview = image ? URL.createObjectURL(image) : null; + setImageFiles((prev) => { + if ( + fileValue.trim() === '' || + prev.some((file) => file.fileValue === fileValue) || + preview === null + ) + return prev; + if ( + prev.some((file) => file.fileValue === My_INQUIRIES_MESSAGE.fileDefault) + ) { + const removeDefault = prev.filter( + (file) => file.fileValue !== My_INQUIRIES_MESSAGE.fileDefault + ); + + return [...removeDefault, { fileValue, preview, image }]; + } + return [...prev, { fileValue, preview, image }]; + }); + + e.target.value = ''; + }; + + const handleDeleteFile = (e: React.MouseEvent) => { + const deleteFileValue = e.currentTarget.id; + setImageFiles((prev) => { + if (prev.length === 1) { + return [ + { + fileValue: My_INQUIRIES_MESSAGE.fileDefault, + preview: '', + image: null, + }, + ]; + } + return prev.filter((file) => file.fileValue !== deleteFileValue); + }); }; useEffect(() => { return () => { - if (form.fileImage) { - URL.revokeObjectURL(form.fileImage); + if (imageFiles.filter((file) => file.preview !== null).length > 0) { + imageFiles.forEach((file) => URL.revokeObjectURL(file.preview)); } }; - }, [form.fileImage]); + }, [form.images, imageFiles]); return ( @@ -174,18 +234,36 @@ export default function Inquiry() { setForm((prev) => ({ ...prev, content: e.target.value })) } > - - 파일찾기 - {form.fileValue} - handleChangeFile(e)} - /> - {form.fileImage && } - + + + + 파일찾기 + + handleChangeFile(e)} + /> + + {imageFiles.map((list) => ( + + {list.fileValue} + {list.preview && } + {list.preview && ( + + + + )} + + ))} + 제출 diff --git a/src/constants/user/customerService.ts b/src/constants/user/customerService.ts index 63545a92..039f5f1a 100644 --- a/src/constants/user/customerService.ts +++ b/src/constants/user/customerService.ts @@ -14,7 +14,7 @@ export const MODAL_MESSAGE_CUSTOMER_SERVICE = { export const My_INQUIRIES_MESSAGE = { categoryDefault: '카테고리', - fileDefault: '선택된 파일이 없습니다.', + fileDefault: '파일을 선택해 주세요. (최대 3개)', blowUpMessage: '클릭하면 이미지를 크게 볼 수 있습니다.', isImageOpenMessage: '이미지를 클릭하면 사라집니다.', }; @@ -26,4 +26,5 @@ export const INQUIRY_MESSAGE = { inquiredSuccess: '문의글이 작성되었습니다.', inquiredError: '문의글 작성에 실패하였습니다.', validationFile: '파일 크기는 5MB 이하만 가능합니다.', + maxFileCount: '최대 3개까지만 업로드 할 수 있습니다.', }; diff --git a/src/constants/user/routes.ts b/src/constants/user/routes.ts index cbb668d8..020f9f6e 100644 --- a/src/constants/user/routes.ts +++ b/src/constants/user/routes.ts @@ -28,5 +28,5 @@ export const ROUTES = { noticeDetail: 'notice-detail', inquiry: '/inquiry', evaluation: '/evaluation', - loginSuccess: '/login/oauth2/code', + loginSuccess: '/oauth-redirect', } as const; diff --git a/src/hooks/useOauth.ts b/src/hooks/useOauth.ts new file mode 100644 index 00000000..5c615298 --- /dev/null +++ b/src/hooks/useOauth.ts @@ -0,0 +1,9 @@ +import { useQuery } from '@tanstack/react-query'; +import { getOauthLogin } from '../api/auth.api'; + +export const useOauth = () => { + const { data, isLoading, isError } = useQuery({ + queryKey: [], + queryFn: () => getOauthLogin(), + }); +}; diff --git a/src/models/auth.ts b/src/models/auth.ts index 0a70de2a..458676e5 100644 --- a/src/models/auth.ts +++ b/src/models/auth.ts @@ -21,3 +21,8 @@ export interface UserData { nickname: string; admin: boolean; } + +export interface ApiOauth extends ApiCommonType { + data: Pick; + user: UserData; +} diff --git a/src/pages/login/LoginApi.tsx b/src/pages/login/LoginApi.tsx new file mode 100644 index 00000000..a51f3586 --- /dev/null +++ b/src/pages/login/LoginApi.tsx @@ -0,0 +1,43 @@ +import { useEffect, useState } from 'react'; +import { useNavigate } from 'react-router-dom'; +import useAuthStore from '../../store/authStore'; +import { ROUTES } from '../../constants/user/routes'; +import * as S from './Login.styled'; +import { Spinner } from '../../components/common/loadingSpinner/LoadingSpinner.styled'; +import Modal from '../../components/common/modal/Modal'; +import { useModal } from '../../hooks/useModal'; +import { AUTH_MESSAGE } from '../../constants/user/authConstants'; +import { getOauthLogin } from '../../api/auth.api'; + +export default function LoginApi() { + const login = useAuthStore.getState().login; + const navigate = useNavigate(); + const { isOpen, message, handleModalOpen, handleModalClose } = useModal(); + + useEffect(() => { + (async () => { + const result = await getOauthLogin(); + const { data, user } = result; + const { accessToken } = data; + + if (accessToken) { + login(accessToken, user); + navigate(ROUTES.main); + } else { + handleModalOpen(AUTH_MESSAGE.isNotToken); + setTimeout(() => { + navigate(ROUTES.login); + }, 1000); + } + })(); + }, [login, handleModalOpen, navigate]); + + return ( + + + + {message} + + + ); +} diff --git a/src/pages/login/LoginSuccess.tsx b/src/pages/login/LoginSuccess.tsx index 130eae07..d6f92459 100644 --- a/src/pages/login/LoginSuccess.tsx +++ b/src/pages/login/LoginSuccess.tsx @@ -10,12 +10,13 @@ import { AUTH_MESSAGE } from '../../constants/user/authConstants'; function LoginSuccess() { const [searchParams] = useSearchParams(); - const { login } = useAuthStore.getState(); + const login = useAuthStore.getState().login; const navigate = useNavigate(); const { isOpen, message, handleModalOpen, handleModalClose } = useModal(); useEffect(() => { const accessToken = searchParams.get('accessToken'); + console.log('accessToken', accessToken); if (accessToken) { login(accessToken, null); diff --git a/src/routes/AppRoutes.tsx b/src/routes/AppRoutes.tsx index e8bb3709..e4b68e29 100644 --- a/src/routes/AppRoutes.tsx +++ b/src/routes/AppRoutes.tsx @@ -15,6 +15,7 @@ import { ToastProvider } from '../components/common/Toast/ToastProvider'; import { ROUTES } from '../constants/user/routes'; const Login = lazy(() => import('../pages/login/Login')); const LoginSuccess = lazy(() => import('../pages/login/LoginSuccess')); +const LoginApi = lazy(() => import('../pages/login/LoginApi')); const Register = lazy(() => import('../pages/user/register/Register')); const ChangePassword = lazy( () => import('../pages/user/changePassword/ChangePassword') @@ -114,7 +115,7 @@ const AppRoutes = () => { }, { path: ROUTES.loginSuccess, - element: , + element: , }, { path: ROUTES.signup, From 42b174d60a353166f42e605e0c87c4ea3aab9346 Mon Sep 17 00:00:00 2001 From: YouD0313 <102004480+YouD0313@users.noreply.github.com> Date: Mon, 26 May 2025 05:36:56 +0900 Subject: [PATCH 18/27] =?UTF-8?q?design:=20=EB=AC=B8=EC=9D=98=ED=95=98?= =?UTF-8?q?=EA=B8=B0=20=EC=B2=A8=EB=B6=80=ED=8C=8C=EC=9D=BC=20=EC=B5=9C?= =?UTF-8?q?=EB=8C=80=20=EB=86=92=EC=9D=B4,=EB=84=88=EB=B9=84=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mypage/activityLog/inquiries/inquiry/Inquiry.styled.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/user/mypage/activityLog/inquiries/inquiry/Inquiry.styled.ts b/src/components/user/mypage/activityLog/inquiries/inquiry/Inquiry.styled.ts index ab572644..b9312cf9 100644 --- a/src/components/user/mypage/activityLog/inquiries/inquiry/Inquiry.styled.ts +++ b/src/components/user/mypage/activityLog/inquiries/inquiry/Inquiry.styled.ts @@ -91,4 +91,7 @@ export const ModalImgMessageWrapper = styled.div` padding: 0.2rem; `; -export const ModalImg = styled.img``; +export const ModalImg = styled.img` + max-width: 90vw; + max-height: 90vh; +`; From e6fedbb3115ef3bbafc74c6ff00eadb2ddff3192 Mon Sep 17 00:00:00 2001 From: YouD0313 <102004480+YouD0313@users.noreply.github.com> Date: Mon, 26 May 2025 22:58:01 +0900 Subject: [PATCH 19/27] =?UTF-8?q?refactor:=20=EC=97=90=EB=9F=AC=EB=B0=94?= =?UTF-8?q?=EC=9A=B4=EB=8D=94=EB=A6=AC=20=ED=8E=98=EC=9D=B4=EC=A7=80=20?= =?UTF-8?q?=EB=9D=BC=EC=9A=B0=ED=84=B0=20=EB=B3=80=EA=B2=BD=EC=8B=9C=20?= =?UTF-8?q?=ED=95=B4=EB=8B=B9=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8?= =?UTF-8?q?=EB=A1=9C=20=EC=83=88=EB=A1=9C=20=EB=A0=8C=EB=8D=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/error/QueryErrorBoundary.tsx | 3 +++ .../user/mypage/joinedProject/Project.styled.ts | 11 ++++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/components/common/error/QueryErrorBoundary.tsx b/src/components/common/error/QueryErrorBoundary.tsx index 38e70e22..62e08ba3 100644 --- a/src/components/common/error/QueryErrorBoundary.tsx +++ b/src/components/common/error/QueryErrorBoundary.tsx @@ -2,9 +2,11 @@ import { useQueryErrorResetBoundary } from '@tanstack/react-query'; import type { PropsWithChildren } from 'react'; import ErrorBoundary from './ErrorBoundary'; import ErrorFallback from './ErrorFallback'; +import { useLocation } from 'react-router-dom'; export default function QueryErrorBoundary({ children }: PropsWithChildren) { const { reset } = useQueryErrorResetBoundary(); + const location = useLocation(); return ( ; }} + key={location.pathname} > {children} diff --git a/src/components/user/mypage/joinedProject/Project.styled.ts b/src/components/user/mypage/joinedProject/Project.styled.ts index 0c7e22aa..db2726d1 100644 --- a/src/components/user/mypage/joinedProject/Project.styled.ts +++ b/src/components/user/mypage/joinedProject/Project.styled.ts @@ -115,11 +115,14 @@ export const State = styled.span` export const Skill = styled.div` display: flex; - flex-wrap: wrap; - justify-content: space-between; align-items: center; - gap: 0.6rem; + justify-content: space-between; +`; +export const SkillArea = styled.div` + display: flex; + flex-wrap: wrap; + gap: 0.6rem; @media ${({ theme }) => theme.mediaQuery.tablet} { gap: 0.2rem; } @@ -141,8 +144,6 @@ export const Skill = styled.div` } `; -export const SkillArea = styled.div``; - export const EvaluateButton = styled(Link)` display: inline-flex; flex-shrink: 0; From 2fd083731c8464a6afff08a4edd1cc0ac00705e9 Mon Sep 17 00:00:00 2001 From: YouD0313 <102004480+YouD0313@users.noreply.github.com> Date: Tue, 27 May 2025 19:43:07 +0900 Subject: [PATCH 20/27] =?UTF-8?q?refactor:=20oauth=20=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=EC=9D=B8=EC=8B=9C=20userData=20=EB=B0=9B=EA=B8=B0=EC=9C=84?= =?UTF-8?q?=ED=95=B4=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/auth.api.ts | 8 ++++++-- src/pages/login/LoginApi.tsx | 15 +++++++++------ 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/api/auth.api.ts b/src/api/auth.api.ts index 73c883e9..0bc320ea 100644 --- a/src/api/auth.api.ts +++ b/src/api/auth.api.ts @@ -86,9 +86,13 @@ export const postRefresh = async () => { } }; -export const getOauthLogin = async () => { +export const getOauthLogin = async (oauthAccessToken: string) => { try { - const response = await httpClient.get(`/auth/oauth-login`); + const response = await httpClient.get(`/auth/oauth-login`, { + headers: { + Authorization: `Bearer ${oauthAccessToken}`, + }, + }); return response.data; } catch (e) { diff --git a/src/pages/login/LoginApi.tsx b/src/pages/login/LoginApi.tsx index a51f3586..319990c9 100644 --- a/src/pages/login/LoginApi.tsx +++ b/src/pages/login/LoginApi.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from 'react'; -import { useNavigate } from 'react-router-dom'; +import { useNavigate, useSearchParams } from 'react-router-dom'; import useAuthStore from '../../store/authStore'; import { ROUTES } from '../../constants/user/routes'; import * as S from './Login.styled'; @@ -11,16 +11,19 @@ import { getOauthLogin } from '../../api/auth.api'; export default function LoginApi() { const login = useAuthStore.getState().login; + const [searchParams] = useSearchParams(); const navigate = useNavigate(); const { isOpen, message, handleModalOpen, handleModalClose } = useModal(); useEffect(() => { (async () => { - const result = await getOauthLogin(); - const { data, user } = result; - const { accessToken } = data; + const oauthAccessToken = searchParams.get('accessToken'); + + if (oauthAccessToken) { + const result = await getOauthLogin(oauthAccessToken); + const { data, user } = result; + const { accessToken } = data; - if (accessToken) { login(accessToken, user); navigate(ROUTES.main); } else { @@ -30,7 +33,7 @@ export default function LoginApi() { }, 1000); } })(); - }, [login, handleModalOpen, navigate]); + }, [searchParams, login, handleModalOpen, navigate]); return ( From c08274f0303ed47d2a1b33b64675ce6c1c401760 Mon Sep 17 00:00:00 2001 From: YouD0313 <102004480+YouD0313@users.noreply.github.com> Date: Tue, 27 May 2025 20:02:10 +0900 Subject: [PATCH 21/27] =?UTF-8?q?design:=20=EC=B0=B8=EC=97=AC=ED=95=9C=20?= =?UTF-8?q?=ED=94=84=EB=A1=9C=EC=A0=9D=ED=8A=B8=20=EB=A6=AC=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20noContent=20=EC=A4=91=EA=B0=84=EC=A0=95=EB=A0=AC=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../joinedProject/MyJoinProjects.styled.ts | 7 +++---- .../mypage/joinedProject/MyJoinProjects.tsx | 18 ++++++++++-------- .../mypage/notifications/all/All.styled.ts | 1 + 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/components/user/mypage/joinedProject/MyJoinProjects.styled.ts b/src/components/user/mypage/joinedProject/MyJoinProjects.styled.ts index 5f394c0c..3d0051e2 100644 --- a/src/components/user/mypage/joinedProject/MyJoinProjects.styled.ts +++ b/src/components/user/mypage/joinedProject/MyJoinProjects.styled.ts @@ -4,12 +4,9 @@ import { WrapperNoContent } from '../notifications/all/All.styled'; export const Container = styled.section<{ $isNoContent?: boolean }>` width: 100%; height: 85%; - ${({ $isNoContent }) => $isNoContent && css` - min-height: 100%; - display: flex; justify-content: center; align-items: center; `} @@ -30,7 +27,9 @@ export const Section = styled.div` flex-direction: column; `; -export const WrapperNoContentMyJoinedProjects = styled(WrapperNoContent)``; +export const ContainerNoContentMyJoinedProjects = styled(WrapperNoContent)``; + +export const WrapperNoContentMyJoinedProjects = styled.div``; export const Wrapper = styled.div` display: flex; diff --git a/src/components/user/mypage/joinedProject/MyJoinProjects.tsx b/src/components/user/mypage/joinedProject/MyJoinProjects.tsx index 8d976105..cb541cc5 100644 --- a/src/components/user/mypage/joinedProject/MyJoinProjects.tsx +++ b/src/components/user/mypage/joinedProject/MyJoinProjects.tsx @@ -22,8 +22,8 @@ const MyJoinProjects = () => { 참여한 프로젝트 리스트 - {myJoinedProjectListData && myJoinedProjectListData?.length > 0 ? ( - + + {myJoinedProjectListData && myJoinedProjectListData?.length > 0 ? ( {myJoinedProjectListData?.map((project) => ( { ))} - - ) : ( - - - - )} + ) : ( + + + + + + )} + ); diff --git a/src/components/user/mypage/notifications/all/All.styled.ts b/src/components/user/mypage/notifications/all/All.styled.ts index 547fbadc..43762987 100644 --- a/src/components/user/mypage/notifications/all/All.styled.ts +++ b/src/components/user/mypage/notifications/all/All.styled.ts @@ -4,6 +4,7 @@ export const WrapperNoContent = styled.div` height: 100%; display: flex; align-items: center; + justify-content: center; `; export const container = styled.section` From 489571b60673b2928a61924d33751ce73487a069 Mon Sep 17 00:00:00 2001 From: YouD0313 <102004480+YouD0313@users.noreply.github.com> Date: Tue, 27 May 2025 20:10:27 +0900 Subject: [PATCH 22/27] =?UTF-8?q?design:=20=EC=9C=A0=EC=A0=80=20=EC=BB=A8?= =?UTF-8?q?=ED=85=90=ED=8A=B8=EC=97=90=EC=84=9C=EB=8F=84=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../userProjectList/UserProjectList.tsx | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/components/user/userPage/userProjectList/UserProjectList.tsx b/src/components/user/userPage/userProjectList/UserProjectList.tsx index d356a3d8..9742d612 100644 --- a/src/components/user/userPage/userProjectList/UserProjectList.tsx +++ b/src/components/user/userPage/userProjectList/UserProjectList.tsx @@ -19,8 +19,8 @@ export default function UserProjects() { {title} - {userProjectData && userProjectData.length > 0 ? ( - + + {userProjectData && userProjectData.length > 0 ? ( {userProjectData?.map((project) => ( ))} - - ) : ( - - - - )} + ) : ( + + + + + + )} + ); } From de8597f49355cf2e5b4e55d9cee62b5bedd64355 Mon Sep 17 00:00:00 2001 From: YouD0313 <102004480+YouD0313@users.noreply.github.com> Date: Tue, 27 May 2025 20:52:50 +0900 Subject: [PATCH 23/27] =?UTF-8?q?fix:=20=EC=86=8C=EB=AC=B8=EC=9E=90?= =?UTF-8?q?=EB=A1=9C=20=EB=90=9C=20=ED=8C=8C=EC=9D=BC=EB=AA=85=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...{editProfile.styled.ts => EditProfile.styled.ts} | 0 .../mypage/myProfile/editProfile/EditProfile.tsx | 13 ++++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) rename src/components/user/mypage/myProfile/editProfile/{editProfile.styled.ts => EditProfile.styled.ts} (100%) diff --git a/src/components/user/mypage/myProfile/editProfile/editProfile.styled.ts b/src/components/user/mypage/myProfile/editProfile/EditProfile.styled.ts similarity index 100% rename from src/components/user/mypage/myProfile/editProfile/editProfile.styled.ts rename to src/components/user/mypage/myProfile/editProfile/EditProfile.styled.ts diff --git a/src/components/user/mypage/myProfile/editProfile/EditProfile.tsx b/src/components/user/mypage/myProfile/editProfile/EditProfile.tsx index 8b73349e..e425270c 100644 --- a/src/components/user/mypage/myProfile/editProfile/EditProfile.tsx +++ b/src/components/user/mypage/myProfile/editProfile/EditProfile.tsx @@ -1,4 +1,4 @@ -import * as S from './editProfile.styled'; +import * as S from './EditProfile.styled'; import OptionBox from './../OptionBox'; import { Controller, useFieldArray, useForm } from 'react-hook-form'; import { useEffect, useState } from 'react'; @@ -264,6 +264,17 @@ export default function EditProfile() { {errors.github && ( {errors.github.message} )} + )} /> From 74041a304a5d06d57c1c0f3c0ff3056830c43728 Mon Sep 17 00:00:00 2001 From: YouD0313 <102004480+YouD0313@users.noreply.github.com> Date: Tue, 27 May 2025 22:24:31 +0900 Subject: [PATCH 24/27] =?UTF-8?q?feat:=20=EA=B9=83=ED=97=88=EB=B8=8C=20?= =?UTF-8?q?=EB=88=84=EB=81=BC=EB=94=B4=20svg=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?=EB=B2=84=ED=8A=BC=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/githubIcon.svg | 21 +++++++++++++++++++ .../editProfile/EditProfile.styled.ts | 10 +++++---- .../myProfile/editProfile/EditProfile.tsx | 19 +++++++++++++---- 3 files changed, 42 insertions(+), 8 deletions(-) create mode 100644 src/assets/githubIcon.svg diff --git a/src/assets/githubIcon.svg b/src/assets/githubIcon.svg new file mode 100644 index 00000000..190d1ba7 --- /dev/null +++ b/src/assets/githubIcon.svg @@ -0,0 +1,21 @@ + + + + + + + + diff --git a/src/components/user/mypage/myProfile/editProfile/EditProfile.styled.ts b/src/components/user/mypage/myProfile/editProfile/EditProfile.styled.ts index 2ff92941..4761f6fd 100644 --- a/src/components/user/mypage/myProfile/editProfile/EditProfile.styled.ts +++ b/src/components/user/mypage/myProfile/editProfile/EditProfile.styled.ts @@ -44,11 +44,13 @@ export const InputBeginner = styled.input` `; export const InputTextGithub = styled.div` - width: 100%; + width: 70%; +`; - @media ${({ theme }) => theme.mediaQuery.tablet} { - width: 100%; - } +export const GithubImg = styled.img` + width: 1.5rem; + margin-right: 0.3rem; + filter: invert(1); `; export const InputTextCareer = styled.div` diff --git a/src/components/user/mypage/myProfile/editProfile/EditProfile.tsx b/src/components/user/mypage/myProfile/editProfile/EditProfile.tsx index e425270c..6ebceb14 100644 --- a/src/components/user/mypage/myProfile/editProfile/EditProfile.tsx +++ b/src/components/user/mypage/myProfile/editProfile/EditProfile.tsx @@ -15,7 +15,11 @@ import { useEditMyProfileInfo } from '../../../../../hooks/user/useMyInfo'; import useNickNameVerification from '../../../../../hooks/user/useNicknameVerification'; import { ROUTES } from '../../../../../constants/user/routes'; import Button from '../../../../common/Button/Button'; -import { ERROR_MESSAGES } from '../../../../../constants/user/authConstants'; +import { + ERROR_MESSAGES, + OAUTH_PROVIDERS, +} from '../../../../../constants/user/authConstants'; +import githubIcon from '../../../../../assets/githubIcon.svg'; type ProfileFormData = z.infer; @@ -35,6 +39,14 @@ export default function EditProfile() { const { nicknameMessage, handleDuplicationNickname } = useNickNameVerification(); const navigate = useNavigate(); + const BASE_URL = import.meta.env.VITE_APP_API_BASE_URL; + const github = { + ...OAUTH_PROVIDERS.filter((oauth) => oauth.name.includes('github'))[0], + }; + + const handleClickGithubValidation = () => { + window.location.href = `${BASE_URL}/${github.url}`; + }; const { control, @@ -269,10 +281,9 @@ export default function EditProfile() { schema='primary' radius='large' type='button' - onClick={() => { - handleDuplicationNickname(nickname); - }} + onClick={handleClickGithubValidation} > + 인증 From 5e9f9769ba2b3521f8a97a2c59f8639011f32ee1 Mon Sep 17 00:00:00 2001 From: YouD0313 <102004480+YouD0313@users.noreply.github.com> Date: Tue, 27 May 2025 22:35:35 +0900 Subject: [PATCH 25/27] =?UTF-8?q?refactor:=20=ED=95=84=EC=9A=94=EC=97=86?= =?UTF-8?q?=EC=96=B4=EC=A7=84=20=EC=BD=94=EB=93=9C=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/mypage/joinedProject/MyJoinProjects.styled.ts | 10 ++-------- .../user/mypage/joinedProject/MyJoinProjects.tsx | 4 +--- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/components/user/mypage/joinedProject/MyJoinProjects.styled.ts b/src/components/user/mypage/joinedProject/MyJoinProjects.styled.ts index 3d0051e2..d3adc831 100644 --- a/src/components/user/mypage/joinedProject/MyJoinProjects.styled.ts +++ b/src/components/user/mypage/joinedProject/MyJoinProjects.styled.ts @@ -1,15 +1,9 @@ -import styled, { css } from 'styled-components'; +import styled from 'styled-components'; import { WrapperNoContent } from '../notifications/all/All.styled'; -export const Container = styled.section<{ $isNoContent?: boolean }>` +export const Container = styled.section` width: 100%; height: 85%; - ${({ $isNoContent }) => - $isNoContent && - css` - justify-content: center; - align-items: center; - `} `; export const FilterWrapper = styled.div` diff --git a/src/components/user/mypage/joinedProject/MyJoinProjects.tsx b/src/components/user/mypage/joinedProject/MyJoinProjects.tsx index cb541cc5..4774c168 100644 --- a/src/components/user/mypage/joinedProject/MyJoinProjects.tsx +++ b/src/components/user/mypage/joinedProject/MyJoinProjects.tsx @@ -16,9 +16,7 @@ const MyJoinProjects = () => { return ( <> - + 참여한 프로젝트 리스트 From a34a1c3c56c8cc63932d644157b4a638db80e259 Mon Sep 17 00:00:00 2001 From: YouD0313 <102004480+YouD0313@users.noreply.github.com> Date: Tue, 27 May 2025 23:17:52 +0900 Subject: [PATCH 26/27] =?UTF-8?q?refactor:=20=EB=A6=AC=EB=B7=B0=EB=B0=98?= =?UTF-8?q?=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/ProtectRoute.tsx | 2 +- src/components/common/header/Header.tsx | 2 +- src/components/common/sidebar/Sidebar.tsx | 2 +- .../user/customerService/inquiry/Inquiry.tsx | 27 +++++++++---------- .../noticeDetail/NoticeDetailBundle.tsx | 2 +- src/pages/login/LoginApi.tsx | 4 +-- src/pages/login/LoginSuccess.tsx | 2 +- src/pages/user/apply/Apply.tsx | 3 ++- src/pages/user/apply/ApplyStep.tsx | 2 +- .../user/projectDetail/ProjectDetail.tsx | 2 +- src/routes/AppRoutes.tsx | 2 +- 11 files changed, 24 insertions(+), 26 deletions(-) diff --git a/src/components/common/ProtectRoute.tsx b/src/components/common/ProtectRoute.tsx index 4825737c..2767d52e 100644 --- a/src/components/common/ProtectRoute.tsx +++ b/src/components/common/ProtectRoute.tsx @@ -9,7 +9,7 @@ interface ProtectRouteProps extends PropsWithChildren { } const ProtectRoute = ({ children, redirectUrl }: ProtectRouteProps) => { - const isLoggedIn = useAuthStore.getState().isLoggedIn; + const isLoggedIn = useAuthStore((state) => state.isLoggedIn); const { isOpen, message, handleModalOpen, handleModalClose } = useModal(); const [shouldRedirect, setShouldRedirect] = useState(false); diff --git a/src/components/common/header/Header.tsx b/src/components/common/header/Header.tsx index e28df938..a8c6c482 100644 --- a/src/components/common/header/Header.tsx +++ b/src/components/common/header/Header.tsx @@ -23,7 +23,7 @@ function Header() { const location = useLocation(); const { isOpen, message, handleModalOpen, handleModalClose } = useModal(); const { userLogout } = useAuth(handleModalOpen); - const isLoggedIn = useAuthStore.getState().isLoggedIn; + const isLoggedIn = useAuthStore((state) => state.isLoggedIn); const { myData, isLoading } = useMyProfileInfo(); // const { signalData, setSignalData } = useNotification(); diff --git a/src/components/common/sidebar/Sidebar.tsx b/src/components/common/sidebar/Sidebar.tsx index 31c04982..6a42d0e9 100644 --- a/src/components/common/sidebar/Sidebar.tsx +++ b/src/components/common/sidebar/Sidebar.tsx @@ -20,7 +20,7 @@ interface SidebarProps { } const Sidebar = ({ menuItems, profileImage, nickname }: SidebarProps) => { - const isLoggedIn = useAuthStore.getState().isLoggedIn; + const isLoggedIn = useAuthStore((state) => state.isLoggedIn); const location = useLocation(); const isUserPage = location.pathname.includes('/user'); const isManagePage = location.pathname.includes('/manage'); diff --git a/src/components/user/customerService/inquiry/Inquiry.tsx b/src/components/user/customerService/inquiry/Inquiry.tsx index 66903565..f4ba22f2 100644 --- a/src/components/user/customerService/inquiry/Inquiry.tsx +++ b/src/components/user/customerService/inquiry/Inquiry.tsx @@ -17,7 +17,6 @@ interface FormStateType { category: string; title: string; content: string; - images: File | null; } export default function Inquiry() { @@ -42,7 +41,6 @@ export default function Inquiry() { category: My_INQUIRIES_MESSAGE.categoryDefault, title: '', content: '', - images: null, }); const MAX_FILE_COUNT = 3; @@ -80,10 +78,6 @@ export default function Inquiry() { } }); - for (const entries of formData) { - console.log(entries); - } - if (!isValid.category) { return handleModalOpen(INQUIRY_MESSAGE.selectCategory); } @@ -99,7 +93,6 @@ export default function Inquiry() { category: My_INQUIRIES_MESSAGE.categoryDefault, title: '', content: '', - images: null, }); }; @@ -119,18 +112,21 @@ export default function Inquiry() { return; } - if (imageFiles.length >= MAX_FILE_COUNT) { + const actualFileCount = imageFiles.filter( + (file) => file.fileValue !== My_INQUIRIES_MESSAGE.fileDefault + ).length; + if (actualFileCount >= MAX_FILE_COUNT) { handleModalOpen(INQUIRY_MESSAGE.maxFileCount); e.target.value = ''; return; } - const preview = image ? URL.createObjectURL(image) : null; + const preview = image ? URL.createObjectURL(image) : ''; setImageFiles((prev) => { if ( fileValue.trim() === '' || prev.some((file) => file.fileValue === fileValue) || - preview === null + preview === '' ) return prev; if ( @@ -166,11 +162,13 @@ export default function Inquiry() { useEffect(() => { return () => { - if (imageFiles.filter((file) => file.preview !== null).length > 0) { - imageFiles.forEach((file) => URL.revokeObjectURL(file.preview)); - } + imageFiles.forEach((file) => { + if (file.preview && file.preview !== '') { + URL.revokeObjectURL(file.preview); + } + }); }; - }, [form.images, imageFiles]); + }, [imageFiles]); return ( @@ -244,7 +242,6 @@ export default function Inquiry() { type='file' accept='.jpg, .jpeg, .png' id='upload' - multiple onChange={(e) => handleChangeFile(e)} /> diff --git a/src/components/user/customerService/noticeDetail/NoticeDetailBundle.tsx b/src/components/user/customerService/noticeDetail/NoticeDetailBundle.tsx index 5ec216b9..dd171d3b 100644 --- a/src/components/user/customerService/noticeDetail/NoticeDetailBundle.tsx +++ b/src/components/user/customerService/noticeDetail/NoticeDetailBundle.tsx @@ -11,7 +11,7 @@ export default function NoticeDetailBundle() { const location = useLocation(); const { noticeId } = useParams(); const id = noticeId || String(location.state.id); - const keyword = location.state.keyword; + const keyword = location.state.keyword ?? ''; const { noticeDetail: noticeDetailData, isLoading } = useGetNoticeDetail(id); diff --git a/src/pages/login/LoginApi.tsx b/src/pages/login/LoginApi.tsx index 319990c9..502dd79a 100644 --- a/src/pages/login/LoginApi.tsx +++ b/src/pages/login/LoginApi.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from 'react'; +import { useEffect } from 'react'; import { useNavigate, useSearchParams } from 'react-router-dom'; import useAuthStore from '../../store/authStore'; import { ROUTES } from '../../constants/user/routes'; @@ -10,7 +10,7 @@ import { AUTH_MESSAGE } from '../../constants/user/authConstants'; import { getOauthLogin } from '../../api/auth.api'; export default function LoginApi() { - const login = useAuthStore.getState().login; + const login = useAuthStore((state) => state.login); const [searchParams] = useSearchParams(); const navigate = useNavigate(); const { isOpen, message, handleModalOpen, handleModalClose } = useModal(); diff --git a/src/pages/login/LoginSuccess.tsx b/src/pages/login/LoginSuccess.tsx index d6f92459..9bc05d1d 100644 --- a/src/pages/login/LoginSuccess.tsx +++ b/src/pages/login/LoginSuccess.tsx @@ -10,7 +10,7 @@ import { AUTH_MESSAGE } from '../../constants/user/authConstants'; function LoginSuccess() { const [searchParams] = useSearchParams(); - const login = useAuthStore.getState().login; + const login = useAuthStore((state) => state.login); const navigate = useNavigate(); const { isOpen, message, handleModalOpen, handleModalClose } = useModal(); diff --git a/src/pages/user/apply/Apply.tsx b/src/pages/user/apply/Apply.tsx index 2dec0b96..043074c4 100644 --- a/src/pages/user/apply/Apply.tsx +++ b/src/pages/user/apply/Apply.tsx @@ -22,7 +22,8 @@ const Apply = () => { const { isOpen, handleModalOpen, handleModalClose, message } = useModal(); const { data: projectData, isLoading, isFetching } = useGetProjectData(id); const { applyProject } = useApplyProject({ id, handleModalOpen }); - const userEmail = useAuthStore.getState().userData?.email; + const userEmail = useAuthStore((state) => state.userData?.email); + const { handleSubmit: onSubmitHandler, formState: { errors }, diff --git a/src/pages/user/apply/ApplyStep.tsx b/src/pages/user/apply/ApplyStep.tsx index 4aac084f..b049956c 100644 --- a/src/pages/user/apply/ApplyStep.tsx +++ b/src/pages/user/apply/ApplyStep.tsx @@ -29,7 +29,7 @@ const Apply = () => { useModal(); const { data: projectData, isLoading, isFetching } = useGetProjectData(id); const { applyProject } = useApplyProject({ id, handleModalOpen }); - const userData = useAuthStore.getState().userData; + const userData = useAuthStore((state) => state.userData); const { handleSubmit: onSubmitHandler, formState: { errors }, diff --git a/src/pages/user/projectDetail/ProjectDetail.tsx b/src/pages/user/projectDetail/ProjectDetail.tsx index 6e3dfe03..95efed20 100644 --- a/src/pages/user/projectDetail/ProjectDetail.tsx +++ b/src/pages/user/projectDetail/ProjectDetail.tsx @@ -23,7 +23,7 @@ const ProjectDetail = () => { const { isOpen, message, handleModalClose, handleModalOpen, handleConfirm } = useModal(); const { data, isLoading, isFetching } = useGetProjectData(id); - const userData = useAuthStore.getState().userData; + const userData = useAuthStore((state) => state.userData); useEffect(() => { if (!isLoading && !isFetching && !data) { diff --git a/src/routes/AppRoutes.tsx b/src/routes/AppRoutes.tsx index e4b68e29..12365b63 100644 --- a/src/routes/AppRoutes.tsx +++ b/src/routes/AppRoutes.tsx @@ -102,7 +102,7 @@ const ModifyProject = lazy( const Evaluation = lazy(() => import('../pages/user/evaluation/Evaluation')); const AppRoutes = () => { - const isLoggedIn = useAuthStore.getState().isLoggedIn; + const isLoggedIn = useAuthStore((state) => state.isLoggedIn); const routeList = [ { From a9640b60e1ba5478fefc6aa75c5c3fb74ded4d64 Mon Sep 17 00:00:00 2001 From: YouD0313 <102004480+YouD0313@users.noreply.github.com> Date: Tue, 27 May 2025 23:22:12 +0900 Subject: [PATCH 27/27] =?UTF-8?q?refactor:=20=EB=A6=AC=EB=B7=B0=EB=B0=98?= =?UTF-8?q?=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/customerService/noticeDetail/NoticeDetailBundle.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/user/customerService/noticeDetail/NoticeDetailBundle.tsx b/src/components/user/customerService/noticeDetail/NoticeDetailBundle.tsx index dd171d3b..cf77fa0b 100644 --- a/src/components/user/customerService/noticeDetail/NoticeDetailBundle.tsx +++ b/src/components/user/customerService/noticeDetail/NoticeDetailBundle.tsx @@ -11,7 +11,7 @@ export default function NoticeDetailBundle() { const location = useLocation(); const { noticeId } = useParams(); const id = noticeId || String(location.state.id); - const keyword = location.state.keyword ?? ''; + const keyword = location.state?.keyword ?? ''; const { noticeDetail: noticeDetailData, isLoading } = useGetNoticeDetail(id);