From 0e0a5249ce9070760649fa9e70f261ef694b447f Mon Sep 17 00:00:00 2001 From: yoonyesol Date: Sun, 6 Oct 2024 15:42:59 +0900 Subject: [PATCH 1/7] =?UTF-8?q?Feat:=20#192=20=EB=A7=81=ED=81=AC=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/auth-form/LinkContainer.tsx | 32 ++++++++++++++++++- src/hooks/query/useUserQuery.ts | 23 +++++++++++-- src/mocks/services/userServiceHandler.ts | 31 +++++++++++++++++- src/pages/setting/UserSettingPage.tsx | 2 +- src/pages/user/SignUpPage.tsx | 2 +- src/services/userService.ts | 15 ++++++++- src/stores/useStore.ts | 6 ++-- src/types/UserType.tsx | 1 + src/utils/queryKeyGenerator.ts | 11 +++++++ 9 files changed, 112 insertions(+), 11 deletions(-) diff --git a/src/components/user/auth-form/LinkContainer.tsx b/src/components/user/auth-form/LinkContainer.tsx index e912fcf6..d448dadd 100644 --- a/src/components/user/auth-form/LinkContainer.tsx +++ b/src/components/user/auth-form/LinkContainer.tsx @@ -3,24 +3,42 @@ import { FaPlus, FaMinus } from 'react-icons/fa6'; import { useFormContext } from 'react-hook-form'; import { USER_SETTINGS } from '@constants/settings'; import useToast from '@hooks/useToast'; +import { useUpdateLinks } from '@hooks/query/useUserQuery'; +import useStore from '@stores/useStore'; +import { EditUserLinksForm } from '@/types/UserType'; type LinkContainerProps = { initialLinks: string[]; + page: 'SignUp' | 'UserSetting'; }; -export default function LinkContainer({ initialLinks }: LinkContainerProps) { +export default function LinkContainer({ initialLinks, page }: LinkContainerProps) { const { setValue } = useFormContext(); + const { editUserInfo } = useStore(); const [link, setLink] = useState(''); const [links, setLinks] = useState(initialLinks); const [isFocused, setIsFocused] = useState(false); const { toastWarn } = useToast(); + const { mutate: updateLinksMutate } = useUpdateLinks(); + const handleFocus = () => setIsFocused(true); const handleBlur = () => setIsFocused(false); const handleLinkChange = (e: ChangeEvent) => setLink(e.target.value); + const handleUpdateLinks = (userLinks: EditUserLinksForm) => { + updateLinksMutate(userLinks, { + onSuccess: () => { + setLinks(userLinks.links); + setValue('links', userLinks.links); + setLink(''); + }, + }); + editUserInfo(userLinks); + }; + const handleAddLink = (newLink: string) => { if (newLink.trim() === '') return; if (links.length === USER_SETTINGS.MAX_LINK_COUNT) { @@ -32,6 +50,12 @@ export default function LinkContainer({ initialLinks }: LinkContainerProps) { if (isIncludedLink) return toastWarn('이미 등록된 링크입니다.'); const updatedLinks = [...links, newLink.trim()]; + + if (page === 'UserSetting') { + handleUpdateLinks({ links: updatedLinks }); + return; + } + setLinks(updatedLinks); setValue('links', updatedLinks); setLink(''); @@ -39,6 +63,12 @@ export default function LinkContainer({ initialLinks }: LinkContainerProps) { const handleRemoveLink = (removeLink: string) => { const filteredData = links.filter((linkItem) => linkItem !== removeLink); + + if (page === 'UserSetting') { + handleUpdateLinks({ links: filteredData }); + return; + } + setLinks(filteredData); setValue('links', filteredData); }; diff --git a/src/hooks/query/useUserQuery.ts b/src/hooks/query/useUserQuery.ts index 79c17a7d..3d957546 100644 --- a/src/hooks/query/useUserQuery.ts +++ b/src/hooks/query/useUserQuery.ts @@ -1,8 +1,8 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; import useToast from '@hooks/useToast'; -import { updateUserInfo } from '@services/userService'; -import { generateUserInfoQueryKey } from '@/utils/queryKeyGenerator'; -import type { EditUserInfoRequest } from '@/types/UserType'; +import { updateLinks, updateUserInfo } from '@services/userService'; +import { generateLinksQueryKey, generateUserInfoQueryKey } from '@utils/queryKeyGenerator'; +import type { EditUserInfoRequest, EditUserLinksForm } from '@/types/UserType'; export function useUpdateUserInfo() { const queryClient = useQueryClient(); @@ -20,3 +20,20 @@ export function useUpdateUserInfo() { return mutation; } + +export function useUpdateLinks() { + const queryClient = useQueryClient(); + const { toastSuccess, toastError } = useToast(); + const linksQueryKey = generateLinksQueryKey(); + + const mutation = useMutation({ + mutationFn: (data: EditUserLinksForm) => updateLinks(data), + onError: () => toastError('링크 수정에 실패했습니다. 다시 시도해 주세요.'), + onSuccess: () => { + toastSuccess('링크가 수정되었습니다.'); + queryClient.invalidateQueries({ queryKey: linksQueryKey }); + }, + }); + + return mutation; +} diff --git a/src/mocks/services/userServiceHandler.ts b/src/mocks/services/userServiceHandler.ts index 1228b52d..1b21392d 100644 --- a/src/mocks/services/userServiceHandler.ts +++ b/src/mocks/services/userServiceHandler.ts @@ -4,7 +4,7 @@ import { NICKNAME_REGEX } from '@constants/regex'; import { convertTokenToUserId } from '@utils/converter'; import type { Team } from '@/types/TeamType'; import type { Role } from '@/types/RoleType'; -import type { EditUserInfoForm, User } from '@/types/UserType'; +import type { EditUserInfoForm, EditUserLinksForm, User } from '@/types/UserType'; const BASE_URL = import.meta.env.VITE_BASE_URL; @@ -51,6 +51,35 @@ const userServiceHandler = [ return HttpResponse.json(userInfo, { status: 200 }); }), + // 링크 변경 API + http.patch(`${BASE_URL}/user/linkss`, async ({ request }) => { + const accessToken = request.headers.get('Authorization'); + if (!accessToken) return new HttpResponse(null, { status: 401 }); + + const { links } = (await request.json()) as EditUserLinksForm; + + let userId; + // ToDo: 추후 삭제 + if (accessToken === JWT_TOKEN_DUMMY) { + const payload = JWT_TOKEN_DUMMY.split('.')[1]; + userId = Number(payload.replace('mocked-payload-', '')); + } else { + // 토큰에서 userId 추출 + userId = convertTokenToUserId(accessToken); + } + + const userIndex = userId ? USER_DUMMY.findIndex((user) => user.userId === userId) : -1; + + if (!userId || userIndex === -1) { + return HttpResponse.json( + { message: '해당 사용자를 찾을 수 없습니다. 입력 정보를 확인해 주세요.' }, + { status: 401 }, + ); + } + USER_DUMMY[userIndex].links = links; + + return HttpResponse.json(null, { status: 200 }); + }), // 유저 검색 API http.get(`${BASE_URL}/user/search`, ({ request }) => { const url = new URL(request.url); diff --git a/src/pages/setting/UserSettingPage.tsx b/src/pages/setting/UserSettingPage.tsx index 7bf329c1..bc6fe221 100644 --- a/src/pages/setting/UserSettingPage.tsx +++ b/src/pages/setting/UserSettingPage.tsx @@ -113,7 +113,7 @@ export default function UserSettingPage() {
{/* 링크 */} - + diff --git a/src/pages/user/SignUpPage.tsx b/src/pages/user/SignUpPage.tsx index 637683d8..78cc4956 100644 --- a/src/pages/user/SignUpPage.tsx +++ b/src/pages/user/SignUpPage.tsx @@ -133,7 +133,7 @@ export default function SignUpPage() { {/* 링크 */} - + {/* 인증 요청 및 확인 버튼 */}
diff --git a/src/services/userService.ts b/src/services/userService.ts index fd812f24..dff2a00b 100644 --- a/src/services/userService.ts +++ b/src/services/userService.ts @@ -1,6 +1,6 @@ import { authAxios } from '@services/axiosProvider'; import type { AxiosRequestConfig } from 'axios'; -import type { EditUserInfoRequest, EditUserInfoResponse, SearchUser } from '@/types/UserType'; +import type { EditUserInfoRequest, EditUserInfoResponse, EditUserLinksForm, SearchUser } from '@/types/UserType'; import type { TeamListWithApproval } from '@/types/TeamType'; /** @@ -16,6 +16,19 @@ export async function updateUserInfo(userInfoForm: EditUserInfoRequest, axiosCon return authAxios.patch('/user', userInfoForm, axiosConfig); } +/** + * 링크 변경 API + * + * @export + * @async + * @param {EditUserLinksForm} links - 링크 리스트 + * @param {AxiosRequestConfig} [axiosConfig={}] - axios 요청 옵션 설정 객체 + * @returns {Promise} + */ +export async function updateLinks(links: EditUserLinksForm, axiosConfig: AxiosRequestConfig = {}) { + return authAxios.patch('/user/links', links, axiosConfig); +} + /** * 유저 목록을 검색하는 API * diff --git a/src/stores/useStore.ts b/src/stores/useStore.ts index 8f203065..867fb990 100644 --- a/src/stores/useStore.ts +++ b/src/stores/useStore.ts @@ -2,7 +2,7 @@ import { create, StateCreator } from 'zustand'; import { persist, createJSONStorage } from 'zustand/middleware'; import { AUTH_SETTINGS } from '@constants/settings'; import { decrypt, encrypt } from '@utils/cryptoHelper'; -import { EditUserInfoRequest, User } from '@/types/UserType'; +import { EditUserInfoRequest, EditUserLinksForm, User } from '@/types/UserType'; // Auth Slice type AuthStore = { @@ -20,7 +20,7 @@ type AuthStore = { type UserStore = { userInfo: User; setUserInfo: (newUserInfo: User) => void; - editUserInfo: (newUserInfo: EditUserInfoRequest) => void; + editUserInfo: (newUserInfo: EditUserInfoRequest | EditUserLinksForm) => void; clearUserInfo: () => void; }; @@ -90,7 +90,7 @@ const createUserSlice: StateCreator = (set) => ({ userInfo: newUserInfo, }), - editUserInfo: (newUserInfo: EditUserInfoRequest) => + editUserInfo: (newUserInfo: EditUserInfoRequest | EditUserLinksForm) => set((state) => ({ userInfo: { ...state.userInfo, ...newUserInfo }, })), diff --git a/src/types/UserType.tsx b/src/types/UserType.tsx index 9112280e..9e375d96 100644 --- a/src/types/UserType.tsx +++ b/src/types/UserType.tsx @@ -22,6 +22,7 @@ export type UserWithRole = SearchUser & Pick; export type EditUserInfoForm = Omit; export type EditUserInfoResponse = Pick; export type EditUserInfoRequest = Omit; +export type EditUserLinksForm = Pick; export type UserSignUpForm = Omit & { verificationCode: string; diff --git a/src/utils/queryKeyGenerator.ts b/src/utils/queryKeyGenerator.ts index c35b60ee..5db1ecda 100644 --- a/src/utils/queryKeyGenerator.ts +++ b/src/utils/queryKeyGenerator.ts @@ -4,6 +4,7 @@ import type { Project } from '@/types/ProjectType'; export const queryKeys = { userInfo: 'userInfo', + links: 'links', users: 'users', teams: 'teams', projects: 'projects', @@ -23,6 +24,16 @@ export function generateUserInfoQueryKey() { return [queryKeys.userInfo]; } +/** + * 유저 링크 queryKey 생성 함수 + * + * @export + * @returns {(string | number)[]} + */ +export function generateLinksQueryKey() { + return [queryKeys.links]; +} + /** * 유저의 팀 목록 queryKey 생성 함수 * From e6eb4e404c7a8c88b5e675f52c439130098fdeed Mon Sep 17 00:00:00 2001 From: yoonyesol Date: Sun, 6 Oct 2024 16:08:22 +0900 Subject: [PATCH 2/7] =?UTF-8?q?UI:=20#192=20=EB=A7=81=ED=81=AC=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20=EB=84=A4=ED=8A=B8=EC=9B=8C=ED=81=AC=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=20=EC=A4=91=20=EB=A1=9C=EB=94=A9=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/auth-form/LinkContainer.tsx | 20 +++++++++++++++++-- src/mocks/services/userServiceHandler.ts | 2 +- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/components/user/auth-form/LinkContainer.tsx b/src/components/user/auth-form/LinkContainer.tsx index d448dadd..de76b84c 100644 --- a/src/components/user/auth-form/LinkContainer.tsx +++ b/src/components/user/auth-form/LinkContainer.tsx @@ -2,6 +2,7 @@ import { ChangeEvent, useState } from 'react'; import { FaPlus, FaMinus } from 'react-icons/fa6'; import { useFormContext } from 'react-hook-form'; import { USER_SETTINGS } from '@constants/settings'; +import Spinner from '@components/common/Spinner'; import useToast from '@hooks/useToast'; import { useUpdateLinks } from '@hooks/query/useUserQuery'; import useStore from '@stores/useStore'; @@ -19,6 +20,7 @@ export default function LinkContainer({ initialLinks, page }: LinkContainerProps const [links, setLinks] = useState(initialLinks); const [isFocused, setIsFocused] = useState(false); const { toastWarn } = useToast(); + const [isLoading, setIsLoading] = useState(false); // Loading state const { mutate: updateLinksMutate } = useUpdateLinks(); @@ -29,13 +31,19 @@ export default function LinkContainer({ initialLinks, page }: LinkContainerProps const handleLinkChange = (e: ChangeEvent) => setLink(e.target.value); const handleUpdateLinks = (userLinks: EditUserLinksForm) => { + setIsLoading(true); + updateLinksMutate(userLinks, { onSuccess: () => { setLinks(userLinks.links); setValue('links', userLinks.links); setLink(''); }, + onSettled: () => { + setIsLoading(false); + }, }); + editUserInfo(userLinks); }; @@ -74,7 +82,14 @@ export default function LinkContainer({ initialLinks, page }: LinkContainerProps }; return ( -
+
+ {isLoading && ( +
+ + + +
+ )} @@ -111,7 +126,7 @@ export default function LinkContainer({ initialLinks, page }: LinkContainerProps onBlur={handleBlur} onChange={handleLinkChange} type="text" - // TODO: 전체적으로 인풋 관련 스타일링 수정 필요, div 전체를 input이 덮을 수 있도록 수정... + disabled={isLoading} className="h-full grow bg-inherit outline-none placeholder:text-emphasis" /> diff --git a/src/mocks/services/userServiceHandler.ts b/src/mocks/services/userServiceHandler.ts index 1b21392d..31a1e0e3 100644 --- a/src/mocks/services/userServiceHandler.ts +++ b/src/mocks/services/userServiceHandler.ts @@ -52,7 +52,7 @@ const userServiceHandler = [ return HttpResponse.json(userInfo, { status: 200 }); }), // 링크 변경 API - http.patch(`${BASE_URL}/user/linkss`, async ({ request }) => { + http.patch(`${BASE_URL}/user/links`, async ({ request }) => { const accessToken = request.headers.get('Authorization'); if (!accessToken) return new HttpResponse(null, { status: 401 }); From 3f7cf1b1ac5ca9b7d2179195bc4d2d585e92475f Mon Sep 17 00:00:00 2001 From: yoonyesol Date: Sun, 6 Oct 2024 16:24:57 +0900 Subject: [PATCH 3/7] =?UTF-8?q?Comment:=20#192=20=EC=82=AD=EC=A0=9C?= =?UTF-8?q?=EB=90=9C=20=EC=A3=BC=EC=84=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/user/auth-form/LinkContainer.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/user/auth-form/LinkContainer.tsx b/src/components/user/auth-form/LinkContainer.tsx index de76b84c..f5c286e2 100644 --- a/src/components/user/auth-form/LinkContainer.tsx +++ b/src/components/user/auth-form/LinkContainer.tsx @@ -126,6 +126,7 @@ export default function LinkContainer({ initialLinks, page }: LinkContainerProps onBlur={handleBlur} onChange={handleLinkChange} type="text" + // TODO: 전체적으로 인풋 관련 스타일링 수정 필요, div 전체를 input이 덮을 수 있도록 수정... disabled={isLoading} className="h-full grow bg-inherit outline-none placeholder:text-emphasis" /> From 871bbf464e910227b1d5e5ced2fab6242d0e0f95 Mon Sep 17 00:00:00 2001 From: yoonyesol Date: Sun, 6 Oct 2024 17:08:42 +0900 Subject: [PATCH 4/7] =?UTF-8?q?Refactor:=20#192=20=EC=BD=94=EB=93=9C?= =?UTF-8?q?=EB=A6=AC=EB=B7=B0=20=EB=B0=98=EC=98=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/auth-form/LinkContainer.tsx | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/components/user/auth-form/LinkContainer.tsx b/src/components/user/auth-form/LinkContainer.tsx index f5c286e2..cb27416b 100644 --- a/src/components/user/auth-form/LinkContainer.tsx +++ b/src/components/user/auth-form/LinkContainer.tsx @@ -20,10 +20,12 @@ export default function LinkContainer({ initialLinks, page }: LinkContainerProps const [links, setLinks] = useState(initialLinks); const [isFocused, setIsFocused] = useState(false); const { toastWarn } = useToast(); - const [isLoading, setIsLoading] = useState(false); // Loading state + const [isLoading, setIsLoading] = useState(false); const { mutate: updateLinksMutate } = useUpdateLinks(); + const isUserSettingPage = page === 'UserSetting'; + const handleFocus = () => setIsFocused(true); const handleBlur = () => setIsFocused(false); @@ -38,13 +40,12 @@ export default function LinkContainer({ initialLinks, page }: LinkContainerProps setLinks(userLinks.links); setValue('links', userLinks.links); setLink(''); + editUserInfo(userLinks); }, onSettled: () => { setIsLoading(false); }, }); - - editUserInfo(userLinks); }; const handleAddLink = (newLink: string) => { @@ -59,10 +60,7 @@ export default function LinkContainer({ initialLinks, page }: LinkContainerProps const updatedLinks = [...links, newLink.trim()]; - if (page === 'UserSetting') { - handleUpdateLinks({ links: updatedLinks }); - return; - } + if (isUserSettingPage) return handleUpdateLinks({ links: updatedLinks }); setLinks(updatedLinks); setValue('links', updatedLinks); @@ -72,10 +70,7 @@ export default function LinkContainer({ initialLinks, page }: LinkContainerProps const handleRemoveLink = (removeLink: string) => { const filteredData = links.filter((linkItem) => linkItem !== removeLink); - if (page === 'UserSetting') { - handleUpdateLinks({ links: filteredData }); - return; - } + if (isUserSettingPage) return handleUpdateLinks({ links: filteredData }); setLinks(filteredData); setValue('links', filteredData); @@ -126,7 +121,7 @@ export default function LinkContainer({ initialLinks, page }: LinkContainerProps onBlur={handleBlur} onChange={handleLinkChange} type="text" - // TODO: 전체적으로 인풋 관련 스타일링 수정 필요, div 전체를 input이 덮을 수 있도록 수정... + // TODO: 전체적으로 인풋 관련 스타일링 수정 필요, div 전체를 input이 덮을 수 있도록 수정 disabled={isLoading} className="h-full grow bg-inherit outline-none placeholder:text-emphasis" /> From e34d598b2c449337ecef0030d14fe97a6916479b Mon Sep 17 00:00:00 2001 From: yoonyesol Date: Wed, 9 Oct 2024 16:28:23 +0900 Subject: [PATCH 5/7] =?UTF-8?q?Chore:=20#192=20=EC=BD=94=EB=93=9C=EB=A6=AC?= =?UTF-8?q?=EB=B7=B0=20=EB=B0=98=EC=98=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/auth-form/LinkContainer.tsx | 24 +++++++------------ src/mocks/services/userServiceHandler.ts | 2 +- src/pages/setting/UserSettingPage.tsx | 2 +- src/pages/user/SignUpPage.tsx | 2 +- 4 files changed, 11 insertions(+), 19 deletions(-) diff --git a/src/components/user/auth-form/LinkContainer.tsx b/src/components/user/auth-form/LinkContainer.tsx index cb27416b..f8dd87d4 100644 --- a/src/components/user/auth-form/LinkContainer.tsx +++ b/src/components/user/auth-form/LinkContainer.tsx @@ -10,21 +10,18 @@ import { EditUserLinksForm } from '@/types/UserType'; type LinkContainerProps = { initialLinks: string[]; - page: 'SignUp' | 'UserSetting'; + isImmediateUpdate: boolean; }; -export default function LinkContainer({ initialLinks, page }: LinkContainerProps) { +export default function LinkContainer({ initialLinks, isImmediateUpdate }: LinkContainerProps) { const { setValue } = useFormContext(); const { editUserInfo } = useStore(); const [link, setLink] = useState(''); const [links, setLinks] = useState(initialLinks); const [isFocused, setIsFocused] = useState(false); const { toastWarn } = useToast(); - const [isLoading, setIsLoading] = useState(false); - const { mutate: updateLinksMutate } = useUpdateLinks(); - - const isUserSettingPage = page === 'UserSetting'; + const { mutate: updateLinksMutate, isPending: updateLinksIsPending } = useUpdateLinks(); const handleFocus = () => setIsFocused(true); @@ -33,8 +30,6 @@ export default function LinkContainer({ initialLinks, page }: LinkContainerProps const handleLinkChange = (e: ChangeEvent) => setLink(e.target.value); const handleUpdateLinks = (userLinks: EditUserLinksForm) => { - setIsLoading(true); - updateLinksMutate(userLinks, { onSuccess: () => { setLinks(userLinks.links); @@ -42,9 +37,6 @@ export default function LinkContainer({ initialLinks, page }: LinkContainerProps setLink(''); editUserInfo(userLinks); }, - onSettled: () => { - setIsLoading(false); - }, }); }; @@ -60,7 +52,7 @@ export default function LinkContainer({ initialLinks, page }: LinkContainerProps const updatedLinks = [...links, newLink.trim()]; - if (isUserSettingPage) return handleUpdateLinks({ links: updatedLinks }); + if (isImmediateUpdate) return handleUpdateLinks({ links: updatedLinks }); setLinks(updatedLinks); setValue('links', updatedLinks); @@ -70,7 +62,7 @@ export default function LinkContainer({ initialLinks, page }: LinkContainerProps const handleRemoveLink = (removeLink: string) => { const filteredData = links.filter((linkItem) => linkItem !== removeLink); - if (isUserSettingPage) return handleUpdateLinks({ links: filteredData }); + if (isImmediateUpdate) return handleUpdateLinks({ links: filteredData }); setLinks(filteredData); setValue('links', filteredData); @@ -78,7 +70,7 @@ export default function LinkContainer({ initialLinks, page }: LinkContainerProps return (
- {isLoading && ( + {updateLinksIsPending && (
@@ -122,7 +114,7 @@ export default function LinkContainer({ initialLinks, page }: LinkContainerProps onChange={handleLinkChange} type="text" // TODO: 전체적으로 인풋 관련 스타일링 수정 필요, div 전체를 input이 덮을 수 있도록 수정 - disabled={isLoading} + disabled={updateLinksIsPending} className="h-full grow bg-inherit outline-none placeholder:text-emphasis" /> diff --git a/src/mocks/services/userServiceHandler.ts b/src/mocks/services/userServiceHandler.ts index 31a1e0e3..f00ea5e8 100644 --- a/src/mocks/services/userServiceHandler.ts +++ b/src/mocks/services/userServiceHandler.ts @@ -70,7 +70,7 @@ const userServiceHandler = [ const userIndex = userId ? USER_DUMMY.findIndex((user) => user.userId === userId) : -1; - if (!userId || userIndex === -1) { + if (userIndex === -1) { return HttpResponse.json( { message: '해당 사용자를 찾을 수 없습니다. 입력 정보를 확인해 주세요.' }, { status: 401 }, diff --git a/src/pages/setting/UserSettingPage.tsx b/src/pages/setting/UserSettingPage.tsx index bc6fe221..449be7bb 100644 --- a/src/pages/setting/UserSettingPage.tsx +++ b/src/pages/setting/UserSettingPage.tsx @@ -113,7 +113,7 @@ export default function UserSettingPage() {
{/* 링크 */} - +
diff --git a/src/pages/user/SignUpPage.tsx b/src/pages/user/SignUpPage.tsx index 78cc4956..94bb0553 100644 --- a/src/pages/user/SignUpPage.tsx +++ b/src/pages/user/SignUpPage.tsx @@ -133,7 +133,7 @@ export default function SignUpPage() { {/* 링크 */} - + {/* 인증 요청 및 확인 버튼 */}
From c2937a9dea4dca8ff2bab3b17a0dbdb51861b20c Mon Sep 17 00:00:00 2001 From: yoonyesol Date: Wed, 9 Oct 2024 16:42:28 +0900 Subject: [PATCH 6/7] =?UTF-8?q?Feat:=20#192=20=EB=A1=9C=EA=B7=B8=EC=95=84?= =?UTF-8?q?=EC=9B=83=20=EC=8B=9C=20=EC=9C=A0=EC=A0=80=20=EB=A7=81=ED=81=AC?= =?UTF-8?q?=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=B4=88=EA=B8=B0=ED=99=94?= =?UTF-8?q?=EB=A5=BC=20=EC=9C=84=ED=95=B4=20=EC=BF=BC=EB=A6=AC=ED=82=A4?= =?UTF-8?q?=EC=97=90=20=EC=9C=A0=EC=A0=80=20ID=20=EB=93=B1=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/query/useUserQuery.ts | 4 +++- src/utils/queryKeyGenerator.ts | 5 +++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/hooks/query/useUserQuery.ts b/src/hooks/query/useUserQuery.ts index 3d957546..499c3002 100644 --- a/src/hooks/query/useUserQuery.ts +++ b/src/hooks/query/useUserQuery.ts @@ -2,6 +2,7 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; import useToast from '@hooks/useToast'; import { updateLinks, updateUserInfo } from '@services/userService'; import { generateLinksQueryKey, generateUserInfoQueryKey } from '@utils/queryKeyGenerator'; +import useStore from '@stores/useStore'; import type { EditUserInfoRequest, EditUserLinksForm } from '@/types/UserType'; export function useUpdateUserInfo() { @@ -22,9 +23,10 @@ export function useUpdateUserInfo() { } export function useUpdateLinks() { + const { userInfo } = useStore(); const queryClient = useQueryClient(); const { toastSuccess, toastError } = useToast(); - const linksQueryKey = generateLinksQueryKey(); + const linksQueryKey = generateLinksQueryKey(userInfo.userId); const mutation = useMutation({ mutationFn: (data: EditUserLinksForm) => updateLinks(data), diff --git a/src/utils/queryKeyGenerator.ts b/src/utils/queryKeyGenerator.ts index 5db1ecda..b7bc42e9 100644 --- a/src/utils/queryKeyGenerator.ts +++ b/src/utils/queryKeyGenerator.ts @@ -28,10 +28,11 @@ export function generateUserInfoQueryKey() { * 유저 링크 queryKey 생성 함수 * * @export + * @param {number} userId - 유저의 고유 ID * @returns {(string | number)[]} */ -export function generateLinksQueryKey() { - return [queryKeys.links]; +export function generateLinksQueryKey(userId: number) { + return [queryKeys.links, userId]; } /** From fb5a6e041f7f72387cad587337ef7778c55616de Mon Sep 17 00:00:00 2001 From: yoonyesol Date: Sat, 12 Oct 2024 03:17:49 +0900 Subject: [PATCH 7/7] =?UTF-8?q?Refactor:=20#172=20=EC=9D=B4=EC=A4=91=20?= =?UTF-8?q?=EA=B4=80=EB=A6=AC=20=EB=B0=A9=EC=A7=80=EB=A5=BC=20=EC=9C=84?= =?UTF-8?q?=ED=95=9C=20=EC=A0=84=EC=B2=B4=20=EB=A7=81=ED=81=AC=20=EB=B3=80?= =?UTF-8?q?=EC=88=98=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/auth-form/LinkContainer.tsx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/components/user/auth-form/LinkContainer.tsx b/src/components/user/auth-form/LinkContainer.tsx index f8dd87d4..60194979 100644 --- a/src/components/user/auth-form/LinkContainer.tsx +++ b/src/components/user/auth-form/LinkContainer.tsx @@ -14,13 +14,14 @@ type LinkContainerProps = { }; export default function LinkContainer({ initialLinks, isImmediateUpdate }: LinkContainerProps) { - const { setValue } = useFormContext(); + const { setValue, watch } = useFormContext(); const { editUserInfo } = useStore(); const [link, setLink] = useState(''); - const [links, setLinks] = useState(initialLinks); const [isFocused, setIsFocused] = useState(false); const { toastWarn } = useToast(); + const links: string[] = watch('links', initialLinks); + const { mutate: updateLinksMutate, isPending: updateLinksIsPending } = useUpdateLinks(); const handleFocus = () => setIsFocused(true); @@ -29,10 +30,10 @@ export default function LinkContainer({ initialLinks, isImmediateUpdate }: LinkC const handleLinkChange = (e: ChangeEvent) => setLink(e.target.value); + // TODO: 링크 업데이트 후작업 처리 방법 고민해 보기 const handleUpdateLinks = (userLinks: EditUserLinksForm) => { updateLinksMutate(userLinks, { onSuccess: () => { - setLinks(userLinks.links); setValue('links', userLinks.links); setLink(''); editUserInfo(userLinks); @@ -54,7 +55,6 @@ export default function LinkContainer({ initialLinks, isImmediateUpdate }: LinkC if (isImmediateUpdate) return handleUpdateLinks({ links: updatedLinks }); - setLinks(updatedLinks); setValue('links', updatedLinks); setLink(''); }; @@ -64,7 +64,6 @@ export default function LinkContainer({ initialLinks, isImmediateUpdate }: LinkC if (isImmediateUpdate) return handleUpdateLinks({ links: filteredData }); - setLinks(filteredData); setValue('links', filteredData); };