From 3a9167484d15a48f77969d53c48cea86a206d403 Mon Sep 17 00:00:00 2001 From: Cola Date: Tue, 22 Nov 2022 00:07:28 +0900 Subject: [PATCH 001/121] =?UTF-8?q?refactor:=20features=20->=20layouts=20?= =?UTF-8?q?=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/layouts/Sidebar/index.tsx | 4 ++-- client/src/pages/Friends/index.tsx | 2 +- client/src/pages/Home/index.tsx | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/client/src/layouts/Sidebar/index.tsx b/client/src/layouts/Sidebar/index.tsx index 1d436ad9..82a9583b 100644 --- a/client/src/layouts/Sidebar/index.tsx +++ b/client/src/layouts/Sidebar/index.tsx @@ -1,7 +1,7 @@ import UserProfile from '@components/UserProfile'; -import CommunityNav from '@features/CommunityNav'; -import DmNav from '@features/DmNav'; import { Cog6ToothIcon } from '@heroicons/react/20/solid'; +import CommunityNav from '@layouts/CommunityNav'; +import DmNav from '@layouts/DmNav'; import { useQuery } from '@tanstack/react-query'; import axios from 'axios'; import React from 'react'; diff --git a/client/src/pages/Friends/index.tsx b/client/src/pages/Friends/index.tsx index 61faf47e..1a0a32a6 100644 --- a/client/src/pages/Friends/index.tsx +++ b/client/src/pages/Friends/index.tsx @@ -1,4 +1,4 @@ -import FollowingTab from '@features/FollowingTab'; +import FollowingTab from '@layouts/FollowingTab'; import Followers from '@pages/Followers'; import UserSearch from '@pages/UserSearch'; import React, { useState } from 'react'; diff --git a/client/src/pages/Home/index.tsx b/client/src/pages/Home/index.tsx index bac9f50a..f7281be6 100644 --- a/client/src/pages/Home/index.tsx +++ b/client/src/pages/Home/index.tsx @@ -1,5 +1,5 @@ -import Gnb from '@features/Gnb'; -import Sidebar from '@features/Sidebar'; +import Gnb from '@layouts/Gnb'; +import Sidebar from '@layouts/Sidebar'; import React from 'react'; import { Outlet } from 'react-router-dom'; From 9cbe8614458669708021585a75b89bf8ee8ce06b Mon Sep 17 00:00:00 2001 From: Cola Date: Tue, 22 Nov 2022 00:15:02 +0900 Subject: [PATCH 002/121] =?UTF-8?q?feat:=20queryKeyCreator=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/queryKeyCreator.ts | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 client/src/queryKeyCreator.ts diff --git a/client/src/queryKeyCreator.ts b/client/src/queryKeyCreator.ts new file mode 100644 index 00000000..5d6d54e0 --- /dev/null +++ b/client/src/queryKeyCreator.ts @@ -0,0 +1,5 @@ +const queryKeyCreator = { + me: () => ['me'], +} as const; + +export default queryKeyCreator; From be31f92b71fc9ca41c7c80b414437b418fb277ca Mon Sep 17 00:00:00 2001 From: Cola Date: Tue, 22 Nov 2022 04:17:53 +0900 Subject: [PATCH 003/121] =?UTF-8?q?refactor:=20refactor=ED=95=A0=20?= =?UTF-8?q?=EB=82=B4=EC=9A=A9=EB=93=A4=20=EC=A3=BC=EC=84=9D=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/UserProfile/index.tsx | 10 +++------- .../layouts/FollowingTab/components/searchInput.tsx | 5 +++++ .../layouts/FollowingTab/hooks/useFollowingsQuery.ts | 11 ++++++++++- client/src/layouts/FollowingTab/index.tsx | 7 ++++++- client/src/layouts/Sidebar/index.tsx | 7 ++++++- client/src/pages/Friends/index.tsx | 11 ++++++++--- shared/lib/user.ts | 4 +++- 7 files changed, 41 insertions(+), 14 deletions(-) diff --git a/client/src/components/UserProfile/index.tsx b/client/src/components/UserProfile/index.tsx index f86de791..e777b2a7 100644 --- a/client/src/components/UserProfile/index.tsx +++ b/client/src/components/UserProfile/index.tsx @@ -11,17 +11,13 @@ const USER_STATUS = { OFFLINE: 'offline', ONLINE: 'online', AFK: 'afk', -}; - -type UserStatus = typeof USER_STATUS[keyof typeof USER_STATUS]; +} as const; -const statusColor: { - [key: UserStatus]: 'default' | 'success' | 'error'; -} = { +const statusColor = { [USER_STATUS.OFFLINE]: 'default', [USER_STATUS.ONLINE]: 'success', [USER_STATUS.AFK]: 'error', -}; +} as const; const UserProfile: React.FC = ({ user: { nickname, profileUrl, status }, diff --git a/client/src/layouts/FollowingTab/components/searchInput.tsx b/client/src/layouts/FollowingTab/components/searchInput.tsx index 8865bdb6..3d3c8450 100644 --- a/client/src/layouts/FollowingTab/components/searchInput.tsx +++ b/client/src/layouts/FollowingTab/components/searchInput.tsx @@ -1,6 +1,9 @@ import { MagnifyingGlassIcon } from '@heroicons/react/20/solid'; import React from 'react'; +// TODO: ComponentPropsWithoutRef<'input'>을 Extends하는 인터페이스로 작성해도 됩니다 +// TODO: 그런데 @typescript-eslint/no-empty-interface룰 때문에, 빈 인터페이스는 타입으로 바뀌네요. +// TODO: 마지막으로, 모든 Props에 공통되는 사항인데 해당 컴포넌트의 Props는 네이밍을 XXXProps가 아닌, Props로 줄여서 작성해도 좋을것 같아요. type SearchInputProps = React.InputHTMLAttributes; const SearchInput: React.FC = ({ @@ -11,6 +14,7 @@ const SearchInput: React.FC = ({ return (
+ {/* TODO: 이쪽도 아이콘의 의미에 맞는 설명을 넣어주면 좋을 것 같아요. */}
= ({ ); }; +// TODO: displayName 없애도 데브툴엔 제대로 표기되는거로 확인되었는데, 문제 생기는 부분이 있는걸까요? SearchInput.displayName = 'SearchInput'; export default SearchInput; diff --git a/client/src/layouts/FollowingTab/hooks/useFollowingsQuery.ts b/client/src/layouts/FollowingTab/hooks/useFollowingsQuery.ts index 9cb25d2d..7a8063bc 100644 --- a/client/src/layouts/FollowingTab/hooks/useFollowingsQuery.ts +++ b/client/src/layouts/FollowingTab/hooks/useFollowingsQuery.ts @@ -1,8 +1,17 @@ +import type { UseQueryOptions } from '@tanstack/react-query'; + import { useQuery } from '@tanstack/react-query'; import getFollowings from '../apis/getFollowings'; -const useFollowingsQuery = (search: string, options?: Record) => { +type QueryOptions = Omit< + UseQueryOptions<{ s: string }, unknown, { s: string }, string[]>, + 'queryKey' | 'queryFn' | 'initialData' +>; + +// TODO: useQuery<응답 데이터> 제네릭 활용해서 타이핑이 가능합니다. +// TODO: 옵션 타이핑 방법은 더 찾아봐야 알겠지만 위와 같이 가능한 것 같기도. +const useFollowingsQuery = (search: string, options?: QueryOptions) => { const query = useQuery( ['followings', search], () => getFollowings(search), diff --git a/client/src/layouts/FollowingTab/index.tsx b/client/src/layouts/FollowingTab/index.tsx index 8660f4d3..0c825f48 100644 --- a/client/src/layouts/FollowingTab/index.tsx +++ b/client/src/layouts/FollowingTab/index.tsx @@ -9,7 +9,12 @@ const FollowingTab = () => { const DEBOUNCE_DELAY = 500; const [filter, setFilter] = useState(''); const debouncedFilter = useDebouncedValue(filter, DEBOUNCE_DELAY); - const { data } = useFollowingsQuery(debouncedFilter, { suspense: true }); + + // TODO: Suspense는 모든 쿼리 인스턴스에 사용할 것인가요? + // TODO: Suspense가 사용되는 쿼리와 그렇지 않은 쿼리는 어떤 차이를 두고 사용하시나요? + const { data } = useFollowingsQuery(debouncedFilter, { + suspense: true, + }); return (
diff --git a/client/src/layouts/Sidebar/index.tsx b/client/src/layouts/Sidebar/index.tsx index 82a9583b..e02b607b 100644 --- a/client/src/layouts/Sidebar/index.tsx +++ b/client/src/layouts/Sidebar/index.tsx @@ -11,17 +11,22 @@ const getMyInfo = () => axios.get('/api/user/auth/me').then((res) => res.data); const Sidebar = () => { const { pathname } = useLocation(); + + // TODO: 쿼리 컨벤션으로 바꾸기! const { isLoading, data } = useQuery(['me'], getMyInfo); + // TODO: DMNav와 CommunityNav가 좀 더 정확한 의미를 갖도록 바꾸기! return (
+ {/* TODO: ...Query.isLoading ? ... 로 바꾸기! */} {isLoading ? 'loading' : }
diff --git a/client/src/pages/Friends/index.tsx b/client/src/pages/Friends/index.tsx index 1a0a32a6..a30f5422 100644 --- a/client/src/pages/Friends/index.tsx +++ b/client/src/pages/Friends/index.tsx @@ -3,12 +3,14 @@ import Followers from '@pages/Followers'; import UserSearch from '@pages/UserSearch'; import React, { useState } from 'react'; +// TODO: 네이밍 생각해보기 const TAB = { FOLLOWINGS: 'followings', FOLLOWERS: 'followers', USER_SEARCH: 'user-search', -}; +} as const; +// TODO: 필드 이름 수정하기 const tabs = [ { name: '팔로잉', @@ -22,8 +24,9 @@ const tabs = [ name: '사용자 검색', tab: 'user-search', }, -]; +] as const; +// TODO: 컴포넌트 이름 수정하기 (FollowingTab -> Followings) const TabPanel: Record = { [TAB.FOLLOWINGS]: , [TAB.FOLLOWERS]: , @@ -33,7 +36,9 @@ const TabPanel: Record = { const DEFAULT_TAB = TAB.FOLLOWINGS; const Friends = () => { - const [tab, setTab] = useState(DEFAULT_TAB); + const [tab, setTab] = useState<'followings' | 'followers' | 'user-search'>( + DEFAULT_TAB, + ); return (
diff --git a/shared/lib/user.ts b/shared/lib/user.ts index 2b1bf864..ed44d02c 100644 --- a/shared/lib/user.ts +++ b/shared/lib/user.ts @@ -1,8 +1,10 @@ +export type UserStatus = 'online' | 'offline' | 'afk'; + export interface User { _id: string; id: string; nickname: string; - status: string; + status: UserStatus; profileUrl: string; descrption: string; } From 6fb931afd93cb39a425edb869b29fec859ac1e28 Mon Sep 17 00:00:00 2001 From: Cola Date: Tue, 22 Nov 2022 16:04:32 +0900 Subject: [PATCH 004/121] =?UTF-8?q?refactor:=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20apis=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/apis/auth.ts | 23 +++++++++++++++++++++++ client/src/pages/SignUp/index.tsx | 7 +++---- 2 files changed, 26 insertions(+), 4 deletions(-) create mode 100644 client/src/apis/auth.ts diff --git a/client/src/apis/auth.ts b/client/src/apis/auth.ts new file mode 100644 index 00000000..b543367f --- /dev/null +++ b/client/src/apis/auth.ts @@ -0,0 +1,23 @@ +import { SuccessResponse } from '@@types/apis/response'; +import { API_URL } from '@constants/url'; +import axios from 'axios'; + +export interface SignUpRequest { + id: string; + nickname: string; + password: string; +} + +export interface SignUpResult { + message: string; +} + +type SignUp = (fields: SignUpRequest) => Promise>; + +export const signUp: SignUp = ({ id, nickname, password }) => { + const endPoint = `${API_URL}/api/user/auth/signup`; + + return axios + .post(endPoint, { id, nickname, password }) + .then((response) => response.data); +}; diff --git a/client/src/pages/SignUp/index.tsx b/client/src/pages/SignUp/index.tsx index 00c1b267..c99d0f34 100644 --- a/client/src/pages/SignUp/index.tsx +++ b/client/src/pages/SignUp/index.tsx @@ -1,3 +1,5 @@ +import type { SignUpRequest } from '@apis/auth'; + import AuthInput from '@components/AuthInput'; import Button from '@components/Button'; import ErrorMessage from '@components/ErrorMessage'; @@ -12,10 +14,7 @@ import { useForm, Controller } from 'react-hook-form'; import { useNavigate } from 'react-router-dom'; import { toast } from 'react-toastify'; -interface SignUpFields { - id: string; - nickname: string; - password: string; +interface SignUpFormFields extends SignUpRequest { passwordCheck: string; } From 9edc09c98a992ef6fe5b1498d4bb0606d859e6c1 Mon Sep 17 00:00:00 2001 From: Cola Date: Tue, 22 Nov 2022 16:26:37 +0900 Subject: [PATCH 005/121] =?UTF-8?q?refactor:=20useSignUpMutation=20?= =?UTF-8?q?=ED=9B=85=EC=9C=BC=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/hooks/useSignUpMutation.ts | 25 +++++++++++++++++++++++++ client/src/pages/SignUp/index.tsx | 16 +++++++--------- client/src/queryKeyCreator.ts | 1 + 3 files changed, 33 insertions(+), 9 deletions(-) create mode 100644 client/src/hooks/useSignUpMutation.ts diff --git a/client/src/hooks/useSignUpMutation.ts b/client/src/hooks/useSignUpMutation.ts new file mode 100644 index 00000000..eceb2fef --- /dev/null +++ b/client/src/hooks/useSignUpMutation.ts @@ -0,0 +1,25 @@ +import type { SuccessResponse } from '@@types/apis/response'; +import type { SignUpRequest, SignUpResult } from '@apis/auth'; +import type { UseMutationOptions } from '@tanstack/react-query'; + +import { signUp } from '@apis/auth'; +import { useMutation } from '@tanstack/react-query'; + +import queryKeyCreator from '@/queryKeyCreator'; + +const useSignUpMutation = ( + options: UseMutationOptions< + SuccessResponse, + unknown, + SignUpRequest + >, +) => { + const key = queryKeyCreator.signUp(); + const mutation = useMutation(key, signUp, { + ...options, + }); + + return mutation; +}; + +export default useSignUpMutation; diff --git a/client/src/pages/SignUp/index.tsx b/client/src/pages/SignUp/index.tsx index c99d0f34..92580d31 100644 --- a/client/src/pages/SignUp/index.tsx +++ b/client/src/pages/SignUp/index.tsx @@ -6,9 +6,9 @@ import ErrorMessage from '@components/ErrorMessage'; import Logo from '@components/Logo'; import SuccessMessage from '@components/SuccessMessage'; import TextButton from '@components/TextButton'; -import { API_URL } from '@constants/url'; -import { useMutation } from '@tanstack/react-query'; -import axios, { AxiosError } from 'axios'; +import REGEX from '@constants/regex'; +import defaultErrorHandler from '@errors/defaultErrorHandler'; +import useSignUpMutation from '@hooks/useSignUpMutation'; import React from 'react'; import { useForm, Controller } from 'react-hook-form'; import { useNavigate } from 'react-router-dom'; @@ -49,7 +49,7 @@ const SignUp = () => { const navigate = useNavigate(); - const signUpMutate = useMutation(['signUp'], signUpApi, { + const signUpMutation = useSignUpMutation({ onSuccess: () => { toast.success('회원가입에 성공했습니다.'); reset(); @@ -74,10 +74,8 @@ const SignUp = () => { }, }); - const password = watch('password'); - - const handleSubmitSignUpForm = (fields: SignUpFields) => { - signUpMutate.mutate(fields); + const handleSubmitSignUpForm = (fields: SignUpFormFields) => { + signUpMutation.mutate(fields); }; const handleNavigateSignInPage = () => { @@ -219,7 +217,7 @@ const SignUp = () => { size="md" type="submit" minWidth={340} - disabled={signUpMutate.isLoading} + disabled={signUpMutation.isLoading} > 회원가입 diff --git a/client/src/queryKeyCreator.ts b/client/src/queryKeyCreator.ts index 5d6d54e0..2f538399 100644 --- a/client/src/queryKeyCreator.ts +++ b/client/src/queryKeyCreator.ts @@ -1,5 +1,6 @@ const queryKeyCreator = { me: () => ['me'], + signUp: () => ['signUp'], } as const; export default queryKeyCreator; From 8e1fb065064c853cb81377c1ff448568dc0e665b Mon Sep 17 00:00:00 2001 From: Cola Date: Tue, 22 Nov 2022 16:27:16 +0900 Subject: [PATCH 006/121] =?UTF-8?q?refactor:=20REGEX=20=EC=83=81=EC=88=98?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/constants/regex.ts | 5 +++++ client/src/pages/SignUp/index.tsx | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 client/src/constants/regex.ts diff --git a/client/src/constants/regex.ts b/client/src/constants/regex.ts new file mode 100644 index 00000000..e34c7302 --- /dev/null +++ b/client/src/constants/regex.ts @@ -0,0 +1,5 @@ +const REGEX = { + EMAIL: new RegExp('^\\w+([.-]?\\w+)*@\\w+([.-]?\\w+)*(\\.\\w{2,3})+$'), +}; + +export default REGEX; diff --git a/client/src/pages/SignUp/index.tsx b/client/src/pages/SignUp/index.tsx index 92580d31..c2596306 100644 --- a/client/src/pages/SignUp/index.tsx +++ b/client/src/pages/SignUp/index.tsx @@ -98,7 +98,7 @@ const SignUp = () => { control={control} rules={{ pattern: { - value: /^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/, + value: REGEX.EMAIL, message: '아이디는 이메일 형식으로 입력해야 합니다!', }, required: '필수 요소입니다!', From c6557b57d37506ac490c91befc7d53bd404f2260 Mon Sep 17 00:00:00 2001 From: Cola Date: Tue, 22 Nov 2022 16:27:46 +0900 Subject: [PATCH 007/121] =?UTF-8?q?refactor:=20defaultErrorHandler?= =?UTF-8?q?=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/errors/defaultErrorHandler.ts | 23 +++++++++++ client/src/pages/SignUp/index.tsx | 49 +++++------------------- 2 files changed, 33 insertions(+), 39 deletions(-) create mode 100644 client/src/errors/defaultErrorHandler.ts diff --git a/client/src/errors/defaultErrorHandler.ts b/client/src/errors/defaultErrorHandler.ts new file mode 100644 index 00000000..6d58ef12 --- /dev/null +++ b/client/src/errors/defaultErrorHandler.ts @@ -0,0 +1,23 @@ +import { AxiosError } from 'axios'; +import { toast } from 'react-toastify'; + +const defaultErrorHandler = (error: unknown) => { + if (error instanceof AxiosError) { + const errorMessage = + error?.response?.data?.message || '에러가 발생했습니다!'; + + if (Array.isArray(errorMessage)) { + errorMessage.forEach((message) => { + toast.error(message); + }); + return; + } + + toast.error(errorMessage); + return; + } + + toast.error('Unknown Error'); +}; + +export default defaultErrorHandler; diff --git a/client/src/pages/SignUp/index.tsx b/client/src/pages/SignUp/index.tsx index c2596306..59163f27 100644 --- a/client/src/pages/SignUp/index.tsx +++ b/client/src/pages/SignUp/index.tsx @@ -18,35 +18,21 @@ interface SignUpFormFields extends SignUpRequest { passwordCheck: string; } -interface SuccessResponse { - statusCode: number; - result: T; -} - -type SignUpApi = ( - fields: Omit, -) => Promise>; - -const endPoint = `${API_URL}/api/user/auth/signup`; - -const signUpApi: SignUpApi = ({ id, nickname, password }) => { - return axios - .post(endPoint, { id, nickname, password }) - .then((response) => response.data); +const signUpFormDefaultValues = { + id: '', + nickname: '', + password: '', + passwordCheck: '', }; const SignUp = () => { - // TODO: 리팩토링 하자 - const { control, handleSubmit, watch, reset } = useForm({ + const { control, handleSubmit, watch, reset } = useForm({ mode: 'all', - defaultValues: { - id: '', - nickname: '', - password: '', - passwordCheck: '', - }, + defaultValues: signUpFormDefaultValues, }); + const password = watch('password'); + const navigate = useNavigate(); const signUpMutation = useSignUpMutation({ @@ -55,22 +41,7 @@ const SignUp = () => { reset(); }, onError: (error) => { - if (error instanceof AxiosError) { - const errorMessage = - error?.response?.data?.message || '에러가 발생했습니다!'; - - if (Array.isArray(errorMessage)) { - errorMessage.forEach((message) => { - toast.error(message); - }); - return; - } - - toast.error(errorMessage); - return; - } - - toast.error('Unknown Error'); + defaultErrorHandler(error); }, }); From 82cd167f9dbb5614879b794a07b616bc000c247d Mon Sep 17 00:00:00 2001 From: Cola Date: Tue, 22 Nov 2022 16:27:55 +0900 Subject: [PATCH 008/121] =?UTF-8?q?refactor:=20response=20type=20=EC=A0=95?= =?UTF-8?q?=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/types/apis/response.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 client/src/types/apis/response.ts diff --git a/client/src/types/apis/response.ts b/client/src/types/apis/response.ts new file mode 100644 index 00000000..4d63b12f --- /dev/null +++ b/client/src/types/apis/response.ts @@ -0,0 +1,10 @@ +export interface SuccessResponse { + statusCode: number; + result: T; +} + +export interface ErrorResponse { + statusCode: number; + message: string | string[]; + error: string; +} From 6d630d99995023518949bd51fe7e061bdd0ee76b Mon Sep 17 00:00:00 2001 From: Cola Date: Tue, 22 Nov 2022 16:28:12 +0900 Subject: [PATCH 009/121] =?UTF-8?q?chore:=20path=20alias=20=EC=97=85?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/tsconfig.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/client/tsconfig.json b/client/tsconfig.json index 929f22a5..602303ad 100644 --- a/client/tsconfig.json +++ b/client/tsconfig.json @@ -6,6 +6,7 @@ "baseUrl": ".", "outDir": "./build", "paths": { + "@/*": ["src/*"], "@pages/*": ["src/pages/*"], "@layouts/*": ["src/layouts/*"], "@components/*": ["src/components/*"], @@ -14,6 +15,9 @@ "@icons/*": ["src/assets/icons/*"], "@constants/*": ["src/constants/*"], "@apis/*": ["src/apis/*"], + "@hooks/*": ["src/hooks/*"], + "@errors/*": ["src/errors/*"], + "@@types/*": ["src/types/*"], } }, "include": ["src", "config"], From 8e8e05a3a68aa732e56ac57aa03bbc1f81c99038 Mon Sep 17 00:00:00 2001 From: Cola Date: Tue, 22 Nov 2022 17:06:16 +0900 Subject: [PATCH 010/121] =?UTF-8?q?refactor:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8?= =?UTF-8?q?=20=EC=9A=94=EC=B2=AD=20=EA=B4=80=EB=A0=A8=20api=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=EB=A5=BC=20useSignInMutation=20=EC=BB=A4=EC=8A=A4?= =?UTF-8?q?=ED=85=80=ED=9B=85=EC=9C=BC=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/hooks/useSignInMutation.ts | 25 +++++++++++++++++++++++++ client/src/queryKeyCreator.ts | 1 + 2 files changed, 26 insertions(+) create mode 100644 client/src/hooks/useSignInMutation.ts diff --git a/client/src/hooks/useSignInMutation.ts b/client/src/hooks/useSignInMutation.ts new file mode 100644 index 00000000..c8b118f4 --- /dev/null +++ b/client/src/hooks/useSignInMutation.ts @@ -0,0 +1,25 @@ +import type { SuccessResponse } from '@@types/apis/response'; +import type { SignInRequest, SignInResult } from '@apis/auth'; +import type { UseMutationOptions } from '@tanstack/react-query'; + +import { signIn } from '@apis/auth'; +import { useMutation } from '@tanstack/react-query'; + +import queryKeyCreator from '@/queryKeyCreator'; + +const useSignInMutation = ( + options: UseMutationOptions< + SuccessResponse, + unknown, + SignInRequest + >, +) => { + const key = queryKeyCreator.signIn(); + const mutation = useMutation(key, signIn, { + ...options, + }); + + return mutation; +}; + +export default useSignInMutation; diff --git a/client/src/queryKeyCreator.ts b/client/src/queryKeyCreator.ts index 2f538399..acd42ac5 100644 --- a/client/src/queryKeyCreator.ts +++ b/client/src/queryKeyCreator.ts @@ -1,6 +1,7 @@ const queryKeyCreator = { me: () => ['me'], signUp: () => ['signUp'], + signIn: () => ['signIn'], } as const; export default queryKeyCreator; From 67fb7ad11f908b893fe86eb89f72e96ba113dfc3 Mon Sep 17 00:00:00 2001 From: Cola Date: Tue, 22 Nov 2022 17:06:54 +0900 Subject: [PATCH 011/121] =?UTF-8?q?refactor:=20api=20=EB=B0=8F=20=ED=83=80?= =?UTF-8?q?=EC=9E=85=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/apis/auth.ts | 22 ++++++++++ client/src/pages/SignIn/index.tsx | 69 ++++++++----------------------- 2 files changed, 39 insertions(+), 52 deletions(-) diff --git a/client/src/apis/auth.ts b/client/src/apis/auth.ts index b543367f..0309dc8c 100644 --- a/client/src/apis/auth.ts +++ b/client/src/apis/auth.ts @@ -21,3 +21,25 @@ export const signUp: SignUp = ({ id, nickname, password }) => { .post(endPoint, { id, nickname, password }) .then((response) => response.data); }; + +export interface SignInRequest { + id: string; + password: string; +} + +export interface SignInResult { + _id: string; + accessToken: string; +} + +type SignIn = (fields: SignInRequest) => Promise>; + +export const signIn: SignIn = ({ id, password }) => { + const endPoint = `${API_URL}/api/user/auth/signin`; + + return axios + .post(endPoint, { id, password }) + .then((response) => response.data); +}; +// 액세스 토큰으로 다시 유저 정보 요청해야함 +// _id, id(이메일), nickname, status, profileUrl, description diff --git a/client/src/pages/SignIn/index.tsx b/client/src/pages/SignIn/index.tsx index 9848110e..e32d0141 100644 --- a/client/src/pages/SignIn/index.tsx +++ b/client/src/pages/SignIn/index.tsx @@ -1,87 +1,52 @@ +import type { SignInRequest } from '@apis/auth'; + import AuthInput from '@components/AuthInput'; import Button from '@components/Button'; import ErrorMessage from '@components/ErrorMessage'; import Logo from '@components/Logo'; import TextButton from '@components/TextButton'; -import { API_URL } from '@constants/url'; +import REGEX from '@constants/regex'; +import defaultErrorHandler from '@errors/defaultErrorHandler'; +import useSignInMutation from '@hooks/useSignInMutation'; import { useTokenStore } from '@stores/tokenStore'; -import { useMutation } from '@tanstack/react-query'; -import axios, { AxiosError } from 'axios'; import React from 'react'; import { Controller, useForm } from 'react-hook-form'; import { Navigate, useNavigate } from 'react-router-dom'; -import { toast } from 'react-toastify'; - -interface SignInFields { - id: string; - password: string; -} - -interface SuccessResponse { - statusCode: number; - result: T; -} - -type SignInApi = ( - fields: SignInFields, -) => Promise>; - -const endPoint = `${API_URL}/api/user/auth/signin`; -const signInApi: SignInApi = ({ id, password }) => { - return axios - .post(endPoint, { id, password }) - .then((response) => response.data); +const signUpFormDefaultValues = { + id: '', + password: '', }; -// 액세스 토큰으로 다시 유저 정보 요청해야함 -// _id, id(이메일), nickname, status, profileUrl, description const SignIn = () => { const accessToken = useTokenStore((state) => state.accessToken); const setAccessToken = useTokenStore((state) => state.setAccessToken); - const { control, handleSubmit, reset } = useForm({ + const { control, handleSubmit, reset } = useForm({ mode: 'all', - defaultValues: { - id: '', - password: '', - }, + defaultValues: signUpFormDefaultValues, }); const navigate = useNavigate(); - const signInMutate = useMutation(['signIn'], signInApi, { + const signInMutation = useSignInMutation({ onSuccess: (data) => { setAccessToken(data.result.accessToken); }, onError: (error) => { reset(); - if (error instanceof AxiosError) { - const errorMessage = - error?.response?.data?.message || '에러가 발생했습니다!'; - - if (Array.isArray(errorMessage)) { - errorMessage.forEach((message) => { - toast.error(message); - }); - return; - } - - toast.error(errorMessage); - return; - } - - toast.error('Unknown Error'); + defaultErrorHandler(error); }, }); - const handleSubmitSignInForm = ({ id, password }: SignInFields) => { - signInMutate.mutate({ id, password }); + const handleSubmitSignInForm = ({ id, password }: SignInRequest) => { + signInMutation.mutate({ id, password }); }; const handleNavigateSignUpPage = () => { navigate('/sign-up'); }; + // TODO: 리다이렉트 조건 다시 생각해보기 if (accessToken) { return ; } @@ -102,7 +67,7 @@ const SignIn = () => { control={control} rules={{ pattern: { - value: /^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/, + value: REGEX.EMAIL, message: '아이디는 이메일 형식으로 입력해야 합니다!', }, }} @@ -149,7 +114,7 @@ const SignIn = () => { size="md" type="submit" minWidth={340} - disabled={signInMutate.isLoading} + disabled={signInMutation.isLoading} > 로그인 From fbb84aca806e9afa83d1a8534e75f1ac73b0322c Mon Sep 17 00:00:00 2001 From: leegwae Date: Tue, 22 Nov 2022 14:40:59 +0900 Subject: [PATCH 012/121] =?UTF-8?q?refactor:=20=EB=94=94=EB=A0=89=ED=86=A0?= =?UTF-8?q?=EB=A6=AC=20=EA=B5=AC=EC=A1=B0=20=EB=B3=80=EA=B2=BD=EC=97=90=20?= =?UTF-8?q?=EB=94=B0=EB=9D=BC=20import=20=EA=B2=BD=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=20#99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/pages/Friends/index.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/client/src/pages/Friends/index.tsx b/client/src/pages/Friends/index.tsx index a30f5422..86715627 100644 --- a/client/src/pages/Friends/index.tsx +++ b/client/src/pages/Friends/index.tsx @@ -47,9 +47,8 @@ const Friends = () => { {tabs.map(({ name, tab: t }) => (
  • diff --git a/client/src/mocks/handlers/Auth.js b/client/src/mocks/handlers/Auth.js index 074d78d5..5470db8b 100644 --- a/client/src/mocks/handlers/Auth.js +++ b/client/src/mocks/handlers/Auth.js @@ -65,17 +65,20 @@ const SignIn = rest.post(`${BASE_URL}/user/auth/signin`, (req, res, ctx) => { return ERROR ? errorResponse : successResponse; }); -export const GetMyInfo = rest.get('/api/user/auth/me', (req, res, ctx) => { - return res( - ctx.delay(), - ctx.status(200), - ctx.json({ - statusCode: 200, - result: { - user: users[0], - }, - }), - ); -}); +export const GetMyInfo = rest.get( + `${BASE_URL}/user/auth/me`, + (req, res, ctx) => { + return res( + ctx.delay(), + ctx.status(200), + ctx.json({ + statusCode: 200, + result: { + user: users[0], + }, + }), + ); + }, +); export default [SignUp, SignIn, GetMyInfo]; From a133c53c1ab63c140f487455652e9c8d0b1baf6b Mon Sep 17 00:00:00 2001 From: leegwae Date: Tue, 22 Nov 2022 15:59:26 +0900 Subject: [PATCH 015/121] =?UTF-8?q?refactor:=20`UserProfile`=20=EB=A6=AC?= =?UTF-8?q?=ED=8C=A9=ED=86=A0=EB=A7=81=20#99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `USER_STATUS`를 상수 파일에 분리 - Props는 `ComponentWithoutRef`를 extends하여 사용 --- client/src/components/UserProfile/index.tsx | 19 ++++++------------- client/src/constants/user.ts | 5 +++++ shared/lib/user.ts | 7 ------- 3 files changed, 11 insertions(+), 20 deletions(-) create mode 100644 client/src/constants/user.ts diff --git a/client/src/components/UserProfile/index.tsx b/client/src/components/UserProfile/index.tsx index e777b2a7..48572cb4 100644 --- a/client/src/components/UserProfile/index.tsx +++ b/client/src/components/UserProfile/index.tsx @@ -1,30 +1,23 @@ import Avatar from '@components/Avatar'; import Badge from '@components/Badge'; -import React from 'react'; +import { USER_STATUS } from '@constants/user'; +import React, { ComponentPropsWithoutRef } from 'react'; import { User } from 'shared/lib/user'; -interface UserItemProps { +interface Props extends ComponentPropsWithoutRef<'div'> { user: User; } -const USER_STATUS = { - OFFLINE: 'offline', - ONLINE: 'online', - AFK: 'afk', -} as const; - -const statusColor = { +const STATUS_COLOR = { [USER_STATUS.OFFLINE]: 'default', [USER_STATUS.ONLINE]: 'success', [USER_STATUS.AFK]: 'error', } as const; -const UserProfile: React.FC = ({ - user: { nickname, profileUrl, status }, -}) => { +const UserProfile = ({ user: { nickname, profileUrl, status } }: Props) => { return (
    - + Date: Tue, 22 Nov 2022 18:41:34 +0900 Subject: [PATCH 016/121] =?UTF-8?q?remove:=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EC=BB=A4=EB=AE=A4=EB=8B=88?= =?UTF-8?q?=ED=8B=B0=20=EC=95=84=EB=B0=94=ED=83=80,=20=EC=9C=A0=EC=A0=80?= =?UTF-8?q?=20=EC=95=84=EB=B0=94=ED=83=80=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=20=EC=82=AD=EC=A0=9C=20#99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/CommunityAvatar/index.tsx | 13 ------------- client/src/components/UserAvatar/index.tsx | 13 ------------- .../FollowingTab => }/hooks/useDebouncedValue.ts | 0 .../useFollowingMutation.ts} | 0 .../FollowingTab => }/hooks/useFollowingsQuery.ts | 0 5 files changed, 26 deletions(-) delete mode 100644 client/src/components/CommunityAvatar/index.tsx delete mode 100644 client/src/components/UserAvatar/index.tsx rename client/src/{layouts/FollowingTab => }/hooks/useDebouncedValue.ts (100%) rename client/src/{layouts/FollowingTab/hooks/useFollowingsMutation.ts => hooks/useFollowingMutation.ts} (100%) rename client/src/{layouts/FollowingTab => }/hooks/useFollowingsQuery.ts (100%) diff --git a/client/src/components/CommunityAvatar/index.tsx b/client/src/components/CommunityAvatar/index.tsx deleted file mode 100644 index bc0306f7..00000000 --- a/client/src/components/CommunityAvatar/index.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import Avatar, { AvatarProps } from '@components/Avatar'; -import React from 'react'; - -const CommunityAvatar: React.FC = ({ - variant = 'rectangle', - size = 'medium', - name, - url, -}) => { - return ; -}; - -export default CommunityAvatar; diff --git a/client/src/components/UserAvatar/index.tsx b/client/src/components/UserAvatar/index.tsx deleted file mode 100644 index 2f7dbaa4..00000000 --- a/client/src/components/UserAvatar/index.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import Avatar, { AvatarProps } from '@components/Avatar'; -import React from 'react'; - -const UserAvatar: React.FC = ({ - variant = 'circle', - size = 'small', - name, - url, -}) => { - return ; -}; - -export default UserAvatar; diff --git a/client/src/layouts/FollowingTab/hooks/useDebouncedValue.ts b/client/src/hooks/useDebouncedValue.ts similarity index 100% rename from client/src/layouts/FollowingTab/hooks/useDebouncedValue.ts rename to client/src/hooks/useDebouncedValue.ts diff --git a/client/src/layouts/FollowingTab/hooks/useFollowingsMutation.ts b/client/src/hooks/useFollowingMutation.ts similarity index 100% rename from client/src/layouts/FollowingTab/hooks/useFollowingsMutation.ts rename to client/src/hooks/useFollowingMutation.ts diff --git a/client/src/layouts/FollowingTab/hooks/useFollowingsQuery.ts b/client/src/hooks/useFollowingsQuery.ts similarity index 100% rename from client/src/layouts/FollowingTab/hooks/useFollowingsQuery.ts rename to client/src/hooks/useFollowingsQuery.ts From 37e8822bfac45a8ce89f23152688dfd2df5614e5 Mon Sep 17 00:00:00 2001 From: leegwae Date: Tue, 22 Nov 2022 19:09:30 +0900 Subject: [PATCH 017/121] =?UTF-8?q?refactor:=20=ED=8C=94=EB=A1=9C=EC=9E=89?= =?UTF-8?q?=20=EB=AA=A9=EB=A1=9D=20=EA=B0=80=EC=A0=B8=EC=98=A4=EA=B8=B0,?= =?UTF-8?q?=20=ED=8C=94=EB=A1=9C=EC=9A=B0/=EC=96=B8=ED=8C=94=EB=A1=9C?= =?UTF-8?q?=EC=9A=B0=20API=20`@apis/`=EB=A1=9C=20=EB=B6=84=EB=A6=AC=20#99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/apis/user.ts | 23 +++++++++++++++++++ .../FollowingTab/apis/getFollowings.ts | 11 --------- .../FollowingTab/apis/updateFollowing.ts | 9 -------- 3 files changed, 23 insertions(+), 20 deletions(-) create mode 100644 client/src/apis/user.ts delete mode 100644 client/src/layouts/FollowingTab/apis/getFollowings.ts delete mode 100644 client/src/layouts/FollowingTab/apis/updateFollowing.ts diff --git a/client/src/apis/user.ts b/client/src/apis/user.ts new file mode 100644 index 00000000..7968ee68 --- /dev/null +++ b/client/src/apis/user.ts @@ -0,0 +1,23 @@ +import type { User } from 'shared/lib/user'; + +import { SuccessResponse } from '@@types/apis/response'; +import { API_URL } from '@constants/url'; +import axios from 'axios'; + +export interface GetFollowingsResult { + followings: User[]; +} +export type GetFollowingsResponse = SuccessResponse; + +export const getFollowings = (): Promise => + axios.get(`${API_URL}/api/user/followings`).then((res) => res.data); + +export interface UpdateFollowingResult { + message?: string; +} +export type UpdateFollowingResponse = SuccessResponse; + +export const updateFollowing = ( + userId: string, +): Promise => + axios.post(`${API_URL}/api/user/following/${userId}`).then((res) => res.data); diff --git a/client/src/layouts/FollowingTab/apis/getFollowings.ts b/client/src/layouts/FollowingTab/apis/getFollowings.ts deleted file mode 100644 index 2955f518..00000000 --- a/client/src/layouts/FollowingTab/apis/getFollowings.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { API_URL } from '@constants/url'; -import axios from 'axios'; - -const BASE_URL = `${API_URL}/api`; - -const getFollowings = (query: string) => - axios - .get(`${BASE_URL}/user/followings?query=${query}`) - .then((res) => res.data); - -export default getFollowings; diff --git a/client/src/layouts/FollowingTab/apis/updateFollowing.ts b/client/src/layouts/FollowingTab/apis/updateFollowing.ts deleted file mode 100644 index 8b581487..00000000 --- a/client/src/layouts/FollowingTab/apis/updateFollowing.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { API_URL } from '@constants/url'; -import axios from 'axios'; - -const BASE_URL = `${API_URL}/api`; - -const updateFollowing = (userId: string) => - axios.post(`${BASE_URL}/user/following/${userId}`).then((res) => res.data); - -export default updateFollowing; From 593b67e9c5c2e6343306ff159e61b15826752685 Mon Sep 17 00:00:00 2001 From: leegwae Date: Tue, 22 Nov 2022 19:47:15 +0900 Subject: [PATCH 018/121] =?UTF-8?q?refactor:=20=EC=BF=BC=EB=A6=AC=20?= =?UTF-8?q?=ED=82=A4=20=EB=B3=80=EC=88=98=EC=97=90=20=EB=8B=B4=EC=95=84?= =?UTF-8?q?=EC=84=9C=20=ED=8C=8C=EB=9D=BC=EB=AF=B8=ED=84=B0=EC=97=90=20?= =?UTF-8?q?=EC=A0=84=EB=8B=AC=20#99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/hooks/useMyInfoQuery.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/src/hooks/useMyInfoQuery.ts b/client/src/hooks/useMyInfoQuery.ts index b552ce48..f167ebc4 100644 --- a/client/src/hooks/useMyInfoQuery.ts +++ b/client/src/hooks/useMyInfoQuery.ts @@ -3,7 +3,8 @@ import { useQuery } from '@tanstack/react-query'; import queryKeyCreator from 'src/queryKeyCreator'; const useMyInfoQuery = () => { - const query = useQuery(queryKeyCreator.me(), getMyInfo); + const key = queryKeyCreator.me(); + const query = useQuery(key, getMyInfo); return query; }; From b70299b2ff8319ca7b91dccf512f613c58317f7b Mon Sep 17 00:00:00 2001 From: leegwae Date: Tue, 22 Nov 2022 19:55:19 +0900 Subject: [PATCH 019/121] =?UTF-8?q?refactor:=20=ED=8C=94=EB=A1=9C=EC=9E=89?= =?UTF-8?q?=20=EB=AA=A9=EB=A1=9D=20=EA=B0=80=EC=A0=B8=EC=98=A4=EB=8A=94=20?= =?UTF-8?q?=EC=BF=BC=EB=A6=AC=20`useFollowinQuery`=EB=A1=9C=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC=20#99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `useQuery`의 `select` 옵션으로 검색 필터 적용 --- client/src/hooks/useFollowingsQuery.ts | 25 +++++++++-------------- client/src/layouts/FollowingTab/index.tsx | 25 +++++++++++++++-------- client/src/mocks/handlers/Friend.js | 10 ++------- client/src/queryKeyCreator.ts | 1 + 4 files changed, 29 insertions(+), 32 deletions(-) diff --git a/client/src/hooks/useFollowingsQuery.ts b/client/src/hooks/useFollowingsQuery.ts index 7a8063bc..9b8bbd3d 100644 --- a/client/src/hooks/useFollowingsQuery.ts +++ b/client/src/hooks/useFollowingsQuery.ts @@ -1,22 +1,17 @@ import type { UseQueryOptions } from '@tanstack/react-query'; +import { getFollowings, GetFollowingsResponse } from '@apis/user'; import { useQuery } from '@tanstack/react-query'; +import queryKeyCreator from 'src/queryKeyCreator'; -import getFollowings from '../apis/getFollowings'; - -type QueryOptions = Omit< - UseQueryOptions<{ s: string }, unknown, { s: string }, string[]>, - 'queryKey' | 'queryFn' | 'initialData' ->; - -// TODO: useQuery<응답 데이터> 제네릭 활용해서 타이핑이 가능합니다. -// TODO: 옵션 타이핑 방법은 더 찾아봐야 알겠지만 위와 같이 가능한 것 같기도. -const useFollowingsQuery = (search: string, options?: QueryOptions) => { - const query = useQuery( - ['followings', search], - () => getFollowings(search), - options, - ); +const useFollowingsQuery = (options?: { + suspense: boolean; + select: (data: GetFollowingsResponse) => any; +}) => { + const key = queryKeyCreator.followings(); + const query = useQuery(key, getFollowings, { + ...options, + }); return query; }; diff --git a/client/src/layouts/FollowingTab/index.tsx b/client/src/layouts/FollowingTab/index.tsx index 0c825f48..b447d275 100644 --- a/client/src/layouts/FollowingTab/index.tsx +++ b/client/src/layouts/FollowingTab/index.tsx @@ -1,19 +1,26 @@ -import React, { useState, Suspense } from 'react'; +import useDebouncedValue from '@hooks/useDebouncedValue'; +import useFollowingsQuery from '@hooks/useFollowingsQuery'; +import React, { useState, Suspense, useEffect } from 'react'; import FollowingList from './components/list'; import SearchInput from './components/searchInput'; -import useDebouncedValue from './hooks/useDebouncedValue'; -import useFollowingsQuery from './hooks/useFollowingsQuery'; const FollowingTab = () => { const DEBOUNCE_DELAY = 500; const [filter, setFilter] = useState(''); const debouncedFilter = useDebouncedValue(filter, DEBOUNCE_DELAY); - - // TODO: Suspense는 모든 쿼리 인스턴스에 사용할 것인가요? - // TODO: Suspense가 사용되는 쿼리와 그렇지 않은 쿼리는 어떤 차이를 두고 사용하시나요? - const { data } = useFollowingsQuery(debouncedFilter, { + const followingQuery = useFollowingsQuery({ suspense: true, + select: (data) => { + const { result } = data; + const followings = debouncedFilter + ? result.followings.filter(({ nickname }) => + nickname.toUpperCase().includes(filter.toUpperCase()), + ) + : result.followings; + + return { ...data, result: { ...result, followings } }; + }, }); return ( @@ -26,8 +33,8 @@ const FollowingTab = () => { />
    loading...
    }> - {data.result.followings.length ? ( - + {followingQuery.data?.result.followings ? ( + ) : ( '일치하는 사용자가 없습니다.' )} diff --git a/client/src/mocks/handlers/Friend.js b/client/src/mocks/handlers/Friend.js index 8ea10e21..0b0b2ead 100644 --- a/client/src/mocks/handlers/Friend.js +++ b/client/src/mocks/handlers/Friend.js @@ -8,19 +8,13 @@ const BASE_URL = `${API_URL}/api`; const GetFollowings = rest.get( `${BASE_URL}/user/followings`, (req, res, ctx) => { - const query = req.url.searchParams.get('query') ?? ''; - return res( ctx.delay(), ctx.status(200), ctx.json({ statusCode: 200, result: { - followings: query - ? users.filter(({ nickname }) => - nickname.toUpperCase().includes(query.toUpperCase()), - ) - : users, + followings: users, }, }), ); @@ -34,7 +28,7 @@ const UpdateFollowing = rest.post( const idx = users.findIndex((user) => user._id === userId); users.splice(idx, 1); - console.log(users); + return res( ctx.delay(), ctx.status(200), diff --git a/client/src/queryKeyCreator.ts b/client/src/queryKeyCreator.ts index acd42ac5..10451c45 100644 --- a/client/src/queryKeyCreator.ts +++ b/client/src/queryKeyCreator.ts @@ -2,6 +2,7 @@ const queryKeyCreator = { me: () => ['me'], signUp: () => ['signUp'], signIn: () => ['signIn'], + followings: () => ['followings'], } as const; export default queryKeyCreator; From 8562843b664a37390b8f2badbe4a1d4307f4902f Mon Sep 17 00:00:00 2001 From: leegwae Date: Tue, 22 Nov 2022 19:55:48 +0900 Subject: [PATCH 020/121] =?UTF-8?q?refactor:=20=ED=8C=94=EB=A1=9C=EC=9A=B0?= =?UTF-8?q?/=EC=96=B8=ED=8C=94=EB=A1=9C=EC=9A=B0=20=EC=BF=BC=EB=A6=AC=20`u?= =?UTF-8?q?seFollowingMutation`=EC=9C=BC=EB=A1=9C=20=EB=B6=84=EB=A6=AC=20#?= =?UTF-8?q?99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/hooks/useFollowingMutation.ts | 32 +++++++++---------- .../layouts/FollowingTab/components/item.tsx | 5 ++- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/client/src/hooks/useFollowingMutation.ts b/client/src/hooks/useFollowingMutation.ts index 88fec020..530f8bee 100644 --- a/client/src/hooks/useFollowingMutation.ts +++ b/client/src/hooks/useFollowingMutation.ts @@ -1,25 +1,25 @@ +import { GetFollowingsResponse, updateFollowing } from '@apis/user'; import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { GetUsersReponse, User } from 'shared/lib/user'; +import { User } from 'shared/lib/user'; +import queryKeyCreator from 'src/queryKeyCreator'; -import updateFollowing from '../apis/updateFollowing'; - -const useFollowingsMutation = (userId: string) => { +const useFollowingMutation = (userId: string) => { + const key = queryKeyCreator.followings(); const queryClient = useQueryClient(); const mutation = useMutation(() => updateFollowing(userId), { onMutate: async (deleted: User) => { - await queryClient.cancelQueries(['followings']); - const previousFollowings = queryClient.getQueryData([ - 'followings', - ]); + await queryClient.cancelQueries(key); + const previousFollowings = + queryClient.getQueryData(key); if (previousFollowings) { - const { users } = previousFollowings.result; - - queryClient.setQueryData(['followings'], { + queryClient.setQueryData(key, { ...previousFollowings, result: { ...previousFollowings.result, - users: users.filter((user) => user._id !== deleted._id), + followings: previousFollowings.result.followings.filter( + (following) => following._id !== deleted._id, + ), }, }); } @@ -27,17 +27,17 @@ const useFollowingsMutation = (userId: string) => { }, onError: (err, variables, context) => { if (context?.previousFollowings) - queryClient.setQueryData( - ['followings'], + queryClient.setQueryData( + key, context.previousFollowings, ); }, onSettled: () => { - queryClient.invalidateQueries(['followings']); + queryClient.invalidateQueries(key); }, }); return mutation; }; -export default useFollowingsMutation; +export default useFollowingMutation; diff --git a/client/src/layouts/FollowingTab/components/item.tsx b/client/src/layouts/FollowingTab/components/item.tsx index dfdc5cd2..8cda155d 100644 --- a/client/src/layouts/FollowingTab/components/item.tsx +++ b/client/src/layouts/FollowingTab/components/item.tsx @@ -3,19 +3,18 @@ import { EllipsisHorizontalIcon, ChatBubbleLeftIcon, } from '@heroicons/react/20/solid'; +import useFollowingMutation from '@hooks/useFollowingMutation'; import React from 'react'; import { useNavigate } from 'react-router-dom'; import { User } from 'shared/lib/user'; -import useFollowingsMutation from '../hooks/useFollowingsMutation'; - interface FollowingProps { user: User; } const FollowingItem: React.FC = ({ user }) => { const navigate = useNavigate(); - const updateFollowing = useFollowingsMutation(user._id); + const updateFollowing = useFollowingMutation(user._id); const handleChatButtonClick = () => { navigate(`/dms/${user._id}`); From d1a3ef1624a38fe6acb00710aabe1631ab010a5b Mon Sep 17 00:00:00 2001 From: leegwae Date: Tue, 22 Nov 2022 23:01:13 +0900 Subject: [PATCH 021/121] =?UTF-8?q?chore:=20=EC=95=84=EC=9D=B4=EC=BD=98=20?= =?UTF-8?q?`sr-only`=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/layouts/FollowingTab/components/item.tsx | 2 ++ client/src/layouts/FollowingTab/components/searchInput.tsx | 5 +---- client/src/layouts/Sidebar/index.tsx | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/client/src/layouts/FollowingTab/components/item.tsx b/client/src/layouts/FollowingTab/components/item.tsx index 8cda155d..09a74dc0 100644 --- a/client/src/layouts/FollowingTab/components/item.tsx +++ b/client/src/layouts/FollowingTab/components/item.tsx @@ -28,9 +28,11 @@ const FollowingItem: React.FC = ({ user }) => { className="p-2 rounded-full border border-line" onClick={handleChatButtonClick} > + 다이렉트 메시지 From 36e6abbf6f7b20d903c83fe4e7b9f415574bbed2 Mon Sep 17 00:00:00 2001 From: leegwae Date: Wed, 23 Nov 2022 00:55:35 +0900 Subject: [PATCH 022/121] =?UTF-8?q?chore:=20=ED=8C=8C=EC=8A=A4=EC=B9=BC=20?= =?UTF-8?q?=EC=BC=80=EC=9D=B4=EC=8A=A4=20=EC=83=81=EC=88=98=20=EB=8C=80?= =?UTF-8?q?=EB=AC=B8=EC=9E=90=EB=A1=9C=20=EB=B3=80=EA=B2=BD=20#99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/Avatar/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/components/Avatar/index.tsx b/client/src/components/Avatar/index.tsx index 88f4c14e..c40c46e1 100644 --- a/client/src/components/Avatar/index.tsx +++ b/client/src/components/Avatar/index.tsx @@ -12,7 +12,7 @@ const ROUNDED = { circle: 'rounded-full', }; -const WH = { +const SCALE = { small: 'w-[57px] h-[57px]', medium: 'w-[65px] h-[65px]', }; @@ -20,7 +20,7 @@ const WH = { const Avatar: React.FC = ({ name, url, size, variant }) => { return (
    {url ? ( Date: Wed, 23 Nov 2022 02:29:50 +0900 Subject: [PATCH 023/121] =?UTF-8?q?refactor:=20=ED=8C=94=EB=A1=9C=EC=9E=89?= =?UTF-8?q?=20=ED=83=AD=20=EB=82=B4=EB=B6=80=EC=9D=98=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=EB=93=A4=20`@components`=EB=A1=9C=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99=20#99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/FollowerUserItem/index.tsx | 26 ++++++++++ .../components/FollowingUserItem/index.tsx | 49 +++++++++++++++++++ .../SearchInput/index.tsx} | 9 ++-- client/src/components/UserItem/index.tsx | 19 +++++++ client/src/components/UserList/index.tsx | 11 +++++ client/src/hooks/useFollowingMutation.ts | 1 + client/src/hooks/useFollowingsQuery.ts | 37 +++++++++++--- .../layouts/FollowingTab/components/item.tsx | 46 ----------------- .../layouts/FollowingTab/components/list.tsx | 20 -------- client/src/layouts/FollowingTab/index.tsx | 28 +++++------ client/src/queryKeyCreator.ts | 2 +- 11 files changed, 150 insertions(+), 98 deletions(-) create mode 100644 client/src/components/FollowerUserItem/index.tsx create mode 100644 client/src/components/FollowingUserItem/index.tsx rename client/src/{layouts/FollowingTab/components/searchInput.tsx => components/SearchInput/index.tsx} (53%) create mode 100644 client/src/components/UserItem/index.tsx create mode 100644 client/src/components/UserList/index.tsx delete mode 100644 client/src/layouts/FollowingTab/components/item.tsx delete mode 100644 client/src/layouts/FollowingTab/components/list.tsx diff --git a/client/src/components/FollowerUserItem/index.tsx b/client/src/components/FollowerUserItem/index.tsx new file mode 100644 index 00000000..9f6ea116 --- /dev/null +++ b/client/src/components/FollowerUserItem/index.tsx @@ -0,0 +1,26 @@ +import UserItem from '@components/UserItem'; +import { EllipsisHorizontalIcon } from '@heroicons/react/20/solid'; +import React from 'react'; +import { User } from 'shared/lib/user'; + +interface Props { + user: User; +} + +const FollowerUserItem: React.FC = ({ user }) => { + return ( + + +
    + } + /> + ); +}; + +export default FollowerUserItem; diff --git a/client/src/components/FollowingUserItem/index.tsx b/client/src/components/FollowingUserItem/index.tsx new file mode 100644 index 00000000..6eeebb59 --- /dev/null +++ b/client/src/components/FollowingUserItem/index.tsx @@ -0,0 +1,49 @@ +import UserItem from '@components/UserItem'; +import { + EllipsisHorizontalIcon, + ChatBubbleLeftIcon, +} from '@heroicons/react/20/solid'; +import useFollowingMutation from '@hooks/useFollowingMutation'; +import React from 'react'; +import { useNavigate } from 'react-router-dom'; +import { User } from 'shared/lib/user'; + +interface Props { + user: User; +} + +const FollowingUserItem: React.FC = ({ user }) => { + const navigate = useNavigate(); + const followingMutation = useFollowingMutation(user._id); + const { mutate: updateFollowing } = followingMutation; + + const handleChatButtonClick = () => { + navigate(`/dms/${user._id}`); + }; + + return ( + + + + + } + /> + ); +}; + +export default FollowingUserItem; diff --git a/client/src/layouts/FollowingTab/components/searchInput.tsx b/client/src/components/SearchInput/index.tsx similarity index 53% rename from client/src/layouts/FollowingTab/components/searchInput.tsx rename to client/src/components/SearchInput/index.tsx index 200c1d70..a2b59883 100644 --- a/client/src/layouts/FollowingTab/components/searchInput.tsx +++ b/client/src/components/SearchInput/index.tsx @@ -1,10 +1,7 @@ import { MagnifyingGlassIcon } from '@heroicons/react/20/solid'; -import React from 'react'; +import React, { InputHTMLAttributes } from 'react'; -// TODO: ComponentPropsWithoutRef<'input'>을 Extends하는 인터페이스로 작성해도 됩니다 -// TODO: 그런데 @typescript-eslint/no-empty-interface룰 때문에, 빈 인터페이스는 타입으로 바뀌네요. -// TODO: 마지막으로, 모든 Props에 공통되는 사항인데 해당 컴포넌트의 Props는 네이밍을 XXXProps가 아닌, Props로 줄여서 작성해도 좋을것 같아요. -type SearchInputProps = React.InputHTMLAttributes; +type SearchInputProps = InputHTMLAttributes; const SearchInput: React.FC = ({ value, @@ -20,7 +17,7 @@ const SearchInput: React.FC = ({ { + user: User; + right?: ReactNode; +} + +const UserItem: React.FC = ({ user, right }) => { + return ( +
  • + + {right} +
  • + ); +}; + +export default UserItem; diff --git a/client/src/components/UserList/index.tsx b/client/src/components/UserList/index.tsx new file mode 100644 index 00000000..d3c73330 --- /dev/null +++ b/client/src/components/UserList/index.tsx @@ -0,0 +1,11 @@ +import React, { ComponentPropsWithoutRef, ReactNode } from 'react'; + +interface Props extends ComponentPropsWithoutRef<'ul'> { + children?: ReactNode; +} + +const UserList = ({ children }: Props) => { + return
      {children}
    ; +}; + +export default UserList; diff --git a/client/src/hooks/useFollowingMutation.ts b/client/src/hooks/useFollowingMutation.ts index 530f8bee..882d0ba2 100644 --- a/client/src/hooks/useFollowingMutation.ts +++ b/client/src/hooks/useFollowingMutation.ts @@ -9,6 +9,7 @@ const useFollowingMutation = (userId: string) => { const mutation = useMutation(() => updateFollowing(userId), { onMutate: async (deleted: User) => { await queryClient.cancelQueries(key); + const previousFollowings = queryClient.getQueryData(key); diff --git a/client/src/hooks/useFollowingsQuery.ts b/client/src/hooks/useFollowingsQuery.ts index 9b8bbd3d..e2daf1fc 100644 --- a/client/src/hooks/useFollowingsQuery.ts +++ b/client/src/hooks/useFollowingsQuery.ts @@ -1,16 +1,37 @@ -import type { UseQueryOptions } from '@tanstack/react-query'; - -import { getFollowings, GetFollowingsResponse } from '@apis/user'; +import { + getFollowings, + GetFollowingsResponse, + GetFollowingsResult, +} from '@apis/user'; import { useQuery } from '@tanstack/react-query'; import queryKeyCreator from 'src/queryKeyCreator'; -const useFollowingsQuery = (options?: { - suspense: boolean; - select: (data: GetFollowingsResponse) => any; -}) => { +type FollowingQueryData = { + statusCode: number; +} & GetFollowingsResult; + +const useFollowingsQuery = ( + filter: string, + options?: { suspense: boolean }, +) => { const key = queryKeyCreator.followings(); - const query = useQuery(key, getFollowings, { + const query = useQuery< + GetFollowingsResponse, + unknown, + FollowingQueryData, + [string] + >(key, getFollowings, { ...options, + select: (data) => { + const { statusCode, result } = data; + const followings = filter + ? result.followings.filter(({ nickname }) => + nickname.toUpperCase().includes(filter.toUpperCase()), + ) + : result.followings; + + return { statusCode, ...result, followings }; + }, }); return query; diff --git a/client/src/layouts/FollowingTab/components/item.tsx b/client/src/layouts/FollowingTab/components/item.tsx deleted file mode 100644 index 09a74dc0..00000000 --- a/client/src/layouts/FollowingTab/components/item.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import UserProfile from '@components/UserProfile'; -import { - EllipsisHorizontalIcon, - ChatBubbleLeftIcon, -} from '@heroicons/react/20/solid'; -import useFollowingMutation from '@hooks/useFollowingMutation'; -import React from 'react'; -import { useNavigate } from 'react-router-dom'; -import { User } from 'shared/lib/user'; - -interface FollowingProps { - user: User; -} - -const FollowingItem: React.FC = ({ user }) => { - const navigate = useNavigate(); - const updateFollowing = useFollowingMutation(user._id); - - const handleChatButtonClick = () => { - navigate(`/dms/${user._id}`); - }; - - return ( -
  • - -
    - - -
    -
  • - ); -}; - -export default FollowingItem; diff --git a/client/src/layouts/FollowingTab/components/list.tsx b/client/src/layouts/FollowingTab/components/list.tsx deleted file mode 100644 index 9d024caf..00000000 --- a/client/src/layouts/FollowingTab/components/list.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import React from 'react'; -import { User } from 'shared/lib/user'; - -import FollowingItem from './item'; - -interface FollowingListProps { - users: User[]; -} - -const FollowingList: React.FC = ({ users }) => { - return ( -
      - {users.map((user: User) => ( - - ))} -
    - ); -}; - -export default FollowingList; diff --git a/client/src/layouts/FollowingTab/index.tsx b/client/src/layouts/FollowingTab/index.tsx index b447d275..d8811149 100644 --- a/client/src/layouts/FollowingTab/index.tsx +++ b/client/src/layouts/FollowingTab/index.tsx @@ -1,26 +1,16 @@ +import FollowingUserItem from '@components/FollowingUserItem'; +import SearchInput from '@components/searchInput'; +import UserList from '@components/UserList'; import useDebouncedValue from '@hooks/useDebouncedValue'; import useFollowingsQuery from '@hooks/useFollowingsQuery'; -import React, { useState, Suspense, useEffect } from 'react'; - -import FollowingList from './components/list'; -import SearchInput from './components/searchInput'; +import React, { useState, Suspense } from 'react'; const FollowingTab = () => { const DEBOUNCE_DELAY = 500; const [filter, setFilter] = useState(''); const debouncedFilter = useDebouncedValue(filter, DEBOUNCE_DELAY); - const followingQuery = useFollowingsQuery({ + const followingsQuery = useFollowingsQuery(debouncedFilter, { suspense: true, - select: (data) => { - const { result } = data; - const followings = debouncedFilter - ? result.followings.filter(({ nickname }) => - nickname.toUpperCase().includes(filter.toUpperCase()), - ) - : result.followings; - - return { ...data, result: { ...result, followings } }; - }, }); return ( @@ -33,8 +23,12 @@ const FollowingTab = () => { /> loading...}> - {followingQuery.data?.result.followings ? ( - + {followingsQuery.data?.followings.length ? ( + + {followingsQuery.data.followings.map((user) => ( + + ))} + ) : ( '일치하는 사용자가 없습니다.' )} diff --git a/client/src/queryKeyCreator.ts b/client/src/queryKeyCreator.ts index 10451c45..d3762275 100644 --- a/client/src/queryKeyCreator.ts +++ b/client/src/queryKeyCreator.ts @@ -2,7 +2,7 @@ const queryKeyCreator = { me: () => ['me'], signUp: () => ['signUp'], signIn: () => ['signIn'], - followings: () => ['followings'], + followings: (): [string] => ['followings'], } as const; export default queryKeyCreator; From cad4659b10e9f64a892ae0fbb62f748785bdb812 Mon Sep 17 00:00:00 2001 From: leegwae Date: Wed, 23 Nov 2022 03:01:32 +0900 Subject: [PATCH 024/121] =?UTF-8?q?rename:=20=20`FollowingTab`=EC=97=90?= =?UTF-8?q?=EC=84=9C=20`Followings`=EB=A1=9C=20=EC=9D=B4=EB=A6=84=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20#99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/layouts/{FollowingTab => Followings}/index.tsx | 4 ++-- client/src/pages/Friends/index.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) rename client/src/layouts/{FollowingTab => Followings}/index.tsx (95%) diff --git a/client/src/layouts/FollowingTab/index.tsx b/client/src/layouts/Followings/index.tsx similarity index 95% rename from client/src/layouts/FollowingTab/index.tsx rename to client/src/layouts/Followings/index.tsx index d8811149..3bc4ccc9 100644 --- a/client/src/layouts/FollowingTab/index.tsx +++ b/client/src/layouts/Followings/index.tsx @@ -5,7 +5,7 @@ import useDebouncedValue from '@hooks/useDebouncedValue'; import useFollowingsQuery from '@hooks/useFollowingsQuery'; import React, { useState, Suspense } from 'react'; -const FollowingTab = () => { +const Followings = () => { const DEBOUNCE_DELAY = 500; const [filter, setFilter] = useState(''); const debouncedFilter = useDebouncedValue(filter, DEBOUNCE_DELAY); @@ -37,4 +37,4 @@ const FollowingTab = () => { ); }; -export default FollowingTab; +export default Followings; diff --git a/client/src/pages/Friends/index.tsx b/client/src/pages/Friends/index.tsx index 86715627..97fbfcdc 100644 --- a/client/src/pages/Friends/index.tsx +++ b/client/src/pages/Friends/index.tsx @@ -1,4 +1,4 @@ -import FollowingTab from '@layouts/FollowingTab'; +import Followings from '@layouts/Followings'; import Followers from '@pages/Followers'; import UserSearch from '@pages/UserSearch'; import React, { useState } from 'react'; @@ -28,7 +28,7 @@ const tabs = [ // TODO: 컴포넌트 이름 수정하기 (FollowingTab -> Followings) const TabPanel: Record = { - [TAB.FOLLOWINGS]: , + [TAB.FOLLOWINGS]: , [TAB.FOLLOWERS]: , [TAB.USER_SEARCH]: , }; From fc5afa3e5a9c77f16c9800473ae6875312406a72 Mon Sep 17 00:00:00 2001 From: leegwae Date: Wed, 23 Nov 2022 13:17:28 +0900 Subject: [PATCH 025/121] =?UTF-8?q?refactor:=20import=20=EB=AC=B8=20?= =?UTF-8?q?=EC=9D=BC=EA=B4=80=EC=84=B1=20=EC=9E=88=EA=B2=8C=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 - type만 불러오는 경우 `import type`문 사용 - `src/`에 있는 파일들은 `@/`로 alias 사용 --- client/src/components/FollowerUserItem/index.tsx | 3 ++- client/src/components/SearchInput/index.tsx | 4 +++- client/src/components/UserList/index.tsx | 4 +++- client/src/hooks/useFollowingMutation.ts | 6 ++++-- client/src/hooks/useFollowingsQuery.ts | 3 ++- client/src/layouts/Sidebar/index.tsx | 2 +- client/src/pages/Friends/index.tsx | 4 +++- 7 files changed, 18 insertions(+), 8 deletions(-) diff --git a/client/src/components/FollowerUserItem/index.tsx b/client/src/components/FollowerUserItem/index.tsx index 9f6ea116..655f736a 100644 --- a/client/src/components/FollowerUserItem/index.tsx +++ b/client/src/components/FollowerUserItem/index.tsx @@ -1,7 +1,8 @@ +import type { User } from 'shared/lib/user'; + import UserItem from '@components/UserItem'; import { EllipsisHorizontalIcon } from '@heroicons/react/20/solid'; import React from 'react'; -import { User } from 'shared/lib/user'; interface Props { user: User; diff --git a/client/src/components/SearchInput/index.tsx b/client/src/components/SearchInput/index.tsx index a2b59883..4eda7eb9 100644 --- a/client/src/components/SearchInput/index.tsx +++ b/client/src/components/SearchInput/index.tsx @@ -1,5 +1,7 @@ +import type { InputHTMLAttributes } from 'react'; + import { MagnifyingGlassIcon } from '@heroicons/react/20/solid'; -import React, { InputHTMLAttributes } from 'react'; +import React from 'react'; type SearchInputProps = InputHTMLAttributes; diff --git a/client/src/components/UserList/index.tsx b/client/src/components/UserList/index.tsx index d3c73330..bb7f2e40 100644 --- a/client/src/components/UserList/index.tsx +++ b/client/src/components/UserList/index.tsx @@ -1,4 +1,6 @@ -import React, { ComponentPropsWithoutRef, ReactNode } from 'react'; +import type { ComponentPropsWithoutRef, ReactNode } from 'react'; + +import React from 'react'; interface Props extends ComponentPropsWithoutRef<'ul'> { children?: ReactNode; diff --git a/client/src/hooks/useFollowingMutation.ts b/client/src/hooks/useFollowingMutation.ts index 882d0ba2..a6a65544 100644 --- a/client/src/hooks/useFollowingMutation.ts +++ b/client/src/hooks/useFollowingMutation.ts @@ -1,7 +1,9 @@ +import type { User } from 'shared/lib/user'; + import { GetFollowingsResponse, updateFollowing } from '@apis/user'; import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { User } from 'shared/lib/user'; -import queryKeyCreator from 'src/queryKeyCreator'; + +import queryKeyCreator from '@/queryKeyCreator'; const useFollowingMutation = (userId: string) => { const key = queryKeyCreator.followings(); diff --git a/client/src/hooks/useFollowingsQuery.ts b/client/src/hooks/useFollowingsQuery.ts index e2daf1fc..3fc1e4f6 100644 --- a/client/src/hooks/useFollowingsQuery.ts +++ b/client/src/hooks/useFollowingsQuery.ts @@ -4,7 +4,8 @@ import { GetFollowingsResult, } from '@apis/user'; import { useQuery } from '@tanstack/react-query'; -import queryKeyCreator from 'src/queryKeyCreator'; + +import queryKeyCreator from '@/queryKeyCreator'; type FollowingQueryData = { statusCode: number; diff --git a/client/src/layouts/Sidebar/index.tsx b/client/src/layouts/Sidebar/index.tsx index dfbf93da..68074884 100644 --- a/client/src/layouts/Sidebar/index.tsx +++ b/client/src/layouts/Sidebar/index.tsx @@ -1,10 +1,10 @@ import UserProfile from '@components/UserProfile'; import { Cog6ToothIcon } from '@heroicons/react/20/solid'; +import useMyInfoQuery from '@hooks/useMyInfoQuery'; import CommunityNav from '@layouts/CommunityNav'; import DmNav from '@layouts/DmNav'; import React from 'react'; import { useLocation } from 'react-router-dom'; -import useMyInfoQuery from 'src/hooks/useMyInfoQuery'; const Sidebar = () => { const { pathname } = useLocation(); diff --git a/client/src/pages/Friends/index.tsx b/client/src/pages/Friends/index.tsx index 97fbfcdc..8a2628d3 100644 --- a/client/src/pages/Friends/index.tsx +++ b/client/src/pages/Friends/index.tsx @@ -1,3 +1,5 @@ +import type { ReactNode } from 'react'; + import Followings from '@layouts/Followings'; import Followers from '@pages/Followers'; import UserSearch from '@pages/UserSearch'; @@ -27,7 +29,7 @@ const tabs = [ ] as const; // TODO: 컴포넌트 이름 수정하기 (FollowingTab -> Followings) -const TabPanel: Record = { +const TabPanel: Record = { [TAB.FOLLOWINGS]: , [TAB.FOLLOWERS]: , [TAB.USER_SEARCH]: , From b626ae13f64036c8bd659b42df927b427270c5f9 Mon Sep 17 00:00:00 2001 From: leegwae Date: Wed, 23 Nov 2022 13:33:47 +0900 Subject: [PATCH 026/121] =?UTF-8?q?chore:=20=EC=9D=BC=EA=B4=80=EC=84=B1=20?= =?UTF-8?q?=EC=9E=88=EB=8A=94=20`import`=EB=AC=B8=20=EC=9E=91=EC=84=B1?= =?UTF-8?q?=EC=9D=84=20=EC=9C=84=ED=95=B4=20eslint=20=EB=A3=B0=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `@typescript-eslint/consistent-type-imports` 룰 추가 --- client/.eslintrc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/.eslintrc b/client/.eslintrc index e8578692..5fa86372 100644 --- a/client/.eslintrc +++ b/client/.eslintrc @@ -26,6 +26,7 @@ ], "@typescript-eslint/no-var-requires": "off", "react/no-unknown-property": "off", - "no-duplicate-imports": "off" + "no-duplicate-imports": "off", + "@typescript-eslint/consistent-type-imports": "error" } } From 345981cb8329a32118a8d92f08a0142eb9ef7e6d Mon Sep 17 00:00:00 2001 From: leegwae Date: Wed, 23 Nov 2022 16:20:37 +0900 Subject: [PATCH 027/121] =?UTF-8?q?rename:=20`Followers`=EB=A5=BC=20`@page?= =?UTF-8?q?s/`=EC=97=90=EC=84=9C=20`@layouts`=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=98=AE=EA=B9=80=20#66?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/{pages => layouts}/Followers/index.tsx | 0 client/src/pages/Friends/index.tsx | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename client/src/{pages => layouts}/Followers/index.tsx (100%) diff --git a/client/src/pages/Followers/index.tsx b/client/src/layouts/Followers/index.tsx similarity index 100% rename from client/src/pages/Followers/index.tsx rename to client/src/layouts/Followers/index.tsx diff --git a/client/src/pages/Friends/index.tsx b/client/src/pages/Friends/index.tsx index 8a2628d3..61b8f9aa 100644 --- a/client/src/pages/Friends/index.tsx +++ b/client/src/pages/Friends/index.tsx @@ -1,7 +1,7 @@ import type { ReactNode } from 'react'; +import Followers from '@layouts/Followers'; import Followings from '@layouts/Followings'; -import Followers from '@pages/Followers'; import UserSearch from '@pages/UserSearch'; import React, { useState } from 'react'; From 07d391c43bb71de44ac2bdfbd123aa6f5306acb0 Mon Sep 17 00:00:00 2001 From: leegwae Date: Wed, 23 Nov 2022 17:17:37 +0900 Subject: [PATCH 028/121] =?UTF-8?q?chore:=20eslint=20`no-nested-ternary=20?= =?UTF-8?q?=EA=B7=9C=EC=B9=99=20off?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/.eslintrc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/.eslintrc b/client/.eslintrc index 5fa86372..44939533 100644 --- a/client/.eslintrc +++ b/client/.eslintrc @@ -27,6 +27,7 @@ "@typescript-eslint/no-var-requires": "off", "react/no-unknown-property": "off", "no-duplicate-imports": "off", - "@typescript-eslint/consistent-type-imports": "error" + "@typescript-eslint/consistent-type-imports": "error", + "no-nested-ternary": "off" } } From b9d9ef9cec6c769e2aafd9d5f543cd19d09baf30 Mon Sep 17 00:00:00 2001 From: leegwae Date: Wed, 23 Nov 2022 17:19:58 +0900 Subject: [PATCH 029/121] =?UTF-8?q?fix:=20`Followings`=EC=97=90=EC=84=9C?= =?UTF-8?q?=20`Suspense`=20=EC=A0=9C=EA=B1=B0=20#100?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 다음과 같은 문제가 있음 - `Suspense` 부모 컴포넌트도 렌더링 블록되는 문제 - 같은 레벨의 `Followers`에서 `useQuery`에 `suspense: true` 옵션 주면 다음과 같은 에러 발생 ``` Uncaught Error: A component suspended while responding to synchronous input ``` --- client/src/hooks/useFollowingsQuery.ts | 12 +++++------ client/src/layouts/Followings/index.tsx | 28 ++++++++++++------------- 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/client/src/hooks/useFollowingsQuery.ts b/client/src/hooks/useFollowingsQuery.ts index 3fc1e4f6..1d6cd0af 100644 --- a/client/src/hooks/useFollowingsQuery.ts +++ b/client/src/hooks/useFollowingsQuery.ts @@ -1,13 +1,11 @@ -import { - getFollowings, - GetFollowingsResponse, - GetFollowingsResult, -} from '@apis/user'; +import type { GetFollowingsResponse, GetFollowingsResult } from '@apis/user'; + +import { getFollowings } from '@apis/user'; import { useQuery } from '@tanstack/react-query'; import queryKeyCreator from '@/queryKeyCreator'; -type FollowingQueryData = { +type FollowingsQueryData = { statusCode: number; } & GetFollowingsResult; @@ -19,7 +17,7 @@ const useFollowingsQuery = ( const query = useQuery< GetFollowingsResponse, unknown, - FollowingQueryData, + FollowingsQueryData, [string] >(key, getFollowings, { ...options, diff --git a/client/src/layouts/Followings/index.tsx b/client/src/layouts/Followings/index.tsx index 3bc4ccc9..394e3944 100644 --- a/client/src/layouts/Followings/index.tsx +++ b/client/src/layouts/Followings/index.tsx @@ -3,15 +3,13 @@ import SearchInput from '@components/searchInput'; import UserList from '@components/UserList'; import useDebouncedValue from '@hooks/useDebouncedValue'; import useFollowingsQuery from '@hooks/useFollowingsQuery'; -import React, { useState, Suspense } from 'react'; +import React, { useState } from 'react'; const Followings = () => { const DEBOUNCE_DELAY = 500; const [filter, setFilter] = useState(''); const debouncedFilter = useDebouncedValue(filter, DEBOUNCE_DELAY); - const followingsQuery = useFollowingsQuery(debouncedFilter, { - suspense: true, - }); + const followingsQuery = useFollowingsQuery(debouncedFilter); return (
    @@ -22,17 +20,17 @@ const Followings = () => { placeholder="검색하기" />
    - loading...}> - {followingsQuery.data?.followings.length ? ( - - {followingsQuery.data.followings.map((user) => ( - - ))} - - ) : ( - '일치하는 사용자가 없습니다.' - )} - + {followingsQuery.isLoading ? ( +
    loading...
    + ) : followingsQuery.data?.followings.length ? ( + + {followingsQuery.data.followings.map((user) => ( + + ))} + + ) : ( + '일치하는 사용자가 없습니다.' + )} ); }; From c519dfa97536845224818d1e23a479b5a672eb07 Mon Sep 17 00:00:00 2001 From: leegwae Date: Wed, 23 Nov 2022 17:21:04 +0900 Subject: [PATCH 030/121] =?UTF-8?q?feat:=20/GET=20`/api/user/followers`=20?= =?UTF-8?q?mock=20API=20=EC=9E=91=EC=84=B1=20#66?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/mocks/handlers/Friend.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/client/src/mocks/handlers/Friend.js b/client/src/mocks/handlers/Friend.js index 0b0b2ead..71558100 100644 --- a/client/src/mocks/handlers/Friend.js +++ b/client/src/mocks/handlers/Friend.js @@ -40,6 +40,19 @@ const UpdateFollowing = rest.post( }, ); -const FriendHandlers = [GetFollowings, UpdateFollowing]; +const GetFollowers = rest.get(`${BASE_URL}/user/followers`, (req, res, ctx) => { + return res( + ctx.delay(), + ctx.status(200), + ctx.json({ + statusCode: 200, + result: { + followers: users, + }, + }), + ); +}); + +const FriendHandlers = [GetFollowings, UpdateFollowing, GetFollowers]; export default FriendHandlers; From 0d603931872a2a2ffec88d7714f5a6e970327a88 Mon Sep 17 00:00:00 2001 From: leegwae Date: Wed, 23 Nov 2022 17:22:26 +0900 Subject: [PATCH 031/121] =?UTF-8?q?feat:=20=ED=8C=94=EB=A1=9C=EC=9B=8C=20?= =?UTF-8?q?=EB=AA=A9=EB=A1=9D=20=EA=B0=80=EC=A0=B8=EC=98=A4=EA=B8=B0=20API?= =?UTF-8?q?=20=EC=9E=91=EC=84=B1=20#66?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/apis/user.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/client/src/apis/user.ts b/client/src/apis/user.ts index 7968ee68..2d0d8c4b 100644 --- a/client/src/apis/user.ts +++ b/client/src/apis/user.ts @@ -1,6 +1,6 @@ +import type { SuccessResponse } from '@@types/apis/response'; import type { User } from 'shared/lib/user'; -import { SuccessResponse } from '@@types/apis/response'; import { API_URL } from '@constants/url'; import axios from 'axios'; @@ -21,3 +21,12 @@ export const updateFollowing = ( userId: string, ): Promise => axios.post(`${API_URL}/api/user/following/${userId}`).then((res) => res.data); + +export interface GetFollowersResult { + followers: User[]; +} + +export type GetFollowersResponse = SuccessResponse; + +export const getFollowers = (): Promise => + axios.get(`${API_URL}/api/user/followers`).then((res) => res.data); From cb9a119b88d25e9ddd535fc1e3800587ad65b9fd Mon Sep 17 00:00:00 2001 From: leegwae Date: Wed, 23 Nov 2022 17:22:49 +0900 Subject: [PATCH 032/121] =?UTF-8?q?feat:=20`useFollowersQuery`=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1=20#66?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/hooks/useFollowersQuery.ts | 36 +++++++++++++++++++++++++++ client/src/queryKeyCreator.ts | 1 + 2 files changed, 37 insertions(+) create mode 100644 client/src/hooks/useFollowersQuery.ts diff --git a/client/src/hooks/useFollowersQuery.ts b/client/src/hooks/useFollowersQuery.ts new file mode 100644 index 00000000..a3ff8668 --- /dev/null +++ b/client/src/hooks/useFollowersQuery.ts @@ -0,0 +1,36 @@ +import type { GetFollowersResponse, GetFollowersResult } from '@apis/user'; + +import { getFollowers } from '@apis/user'; +import { useQuery } from '@tanstack/react-query'; + +import queryKeyCreator from '@/queryKeyCreator'; + +type FollowersQueryData = { + statusCode: number; +} & GetFollowersResult; + +const useFollowersQuery = (filter: string, options?: { suspense: boolean }) => { + const key = queryKeyCreator.followers(); + const query = useQuery< + GetFollowersResponse, + unknown, + FollowersQueryData, + [string] + >(key, getFollowers, { + ...options, + select: (data) => { + const { statusCode, result } = data; + const followers = filter + ? result.followers.filter(({ nickname }) => + nickname.toUpperCase().includes(filter.toUpperCase()), + ) + : result.followers; + + return { statusCode, ...result, followers }; + }, + }); + + return query; +}; + +export default useFollowersQuery; diff --git a/client/src/queryKeyCreator.ts b/client/src/queryKeyCreator.ts index d3762275..e563efc0 100644 --- a/client/src/queryKeyCreator.ts +++ b/client/src/queryKeyCreator.ts @@ -3,6 +3,7 @@ const queryKeyCreator = { signUp: () => ['signUp'], signIn: () => ['signIn'], followings: (): [string] => ['followings'], + followers: (): [string] => ['followers'], } as const; export default queryKeyCreator; From aaba8d04a28dadc0c3e9b79949b84803c52bfd07 Mon Sep 17 00:00:00 2001 From: leegwae Date: Wed, 23 Nov 2022 17:27:31 +0900 Subject: [PATCH 033/121] =?UTF-8?q?feat:=20`Followers`=20=EC=B9=9C?= =?UTF-8?q?=EA=B5=AC=20=ED=83=AD=20=EC=9E=91=EC=84=B1=20#66?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/FollowingUserItem/index.tsx | 3 +- client/src/layouts/Followers/index.tsx | 35 +++++++++++++++++-- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/client/src/components/FollowingUserItem/index.tsx b/client/src/components/FollowingUserItem/index.tsx index 6eeebb59..6587262d 100644 --- a/client/src/components/FollowingUserItem/index.tsx +++ b/client/src/components/FollowingUserItem/index.tsx @@ -1,3 +1,5 @@ +import type { User } from 'shared/lib/user'; + import UserItem from '@components/UserItem'; import { EllipsisHorizontalIcon, @@ -6,7 +8,6 @@ import { import useFollowingMutation from '@hooks/useFollowingMutation'; import React from 'react'; import { useNavigate } from 'react-router-dom'; -import { User } from 'shared/lib/user'; interface Props { user: User; diff --git a/client/src/layouts/Followers/index.tsx b/client/src/layouts/Followers/index.tsx index 99df5f18..9f01b5f9 100644 --- a/client/src/layouts/Followers/index.tsx +++ b/client/src/layouts/Followers/index.tsx @@ -1,7 +1,38 @@ -import React from 'react'; +import FollowerUserItem from '@components/FollowerUserItem'; +import SearchInput from '@components/searchInput'; +import UserList from '@components/UserList'; +import useDebouncedValue from '@hooks/useDebouncedValue'; +import useFollowersQuery from '@hooks/useFollowersQuery'; +import React, { useState } from 'react'; const Followers = () => { - return
    Followers
    ; + const DEBOUNCE_DELAY = 500; + const [filter, setFilter] = useState(''); + const debouncedFilter = useDebouncedValue(filter, DEBOUNCE_DELAY); + const followersQuery = useFollowersQuery(debouncedFilter); + + return ( +
    +
    + setFilter(e.target.value)} + placeholder="검색하기" + /> +
    + {followersQuery.isLoading ? ( +
    loading...
    + ) : followersQuery.data?.followers.length ? ( + + {followersQuery.data.followers.map((user) => ( + + ))} + + ) : ( + '일치하는 사용자가 없습니다.' + )} +
    + ); }; export default Followers; From 6f85ee0679df9074a8c14007a9e620ded4bb8b52 Mon Sep 17 00:00:00 2001 From: Cola Date: Wed, 23 Nov 2022 05:02:35 +0900 Subject: [PATCH 034/121] =?UTF-8?q?feat:=20=EB=9D=BC=EC=9A=B0=ED=84=B0=20?= =?UTF-8?q?=EA=B5=AC=EC=A1=B0=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Silent Refresh의 동작이 미세하게 다르기 때문에 변경하였음 --- client/src/App.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/src/App.tsx b/client/src/App.tsx index 072a03b9..36024fde 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -10,6 +10,7 @@ import NotFound from '@pages/NotFound'; import Root from '@pages/Root'; import SignIn from '@pages/SignIn'; import SignUp from '@pages/SignUp'; +import UnknownError from '@pages/UnknownError'; import React from 'react'; import { RouterProvider, @@ -38,7 +39,8 @@ const router = createBrowserRouter( } /> } /> - } /> + } /> + } /> } /> , ), From 9ef75ee52948a0c06db9f8cee4827ddeb91a106b Mon Sep 17 00:00:00 2001 From: Cola Date: Wed, 23 Nov 2022 05:03:04 +0900 Subject: [PATCH 035/121] =?UTF-8?q?feat:=20reissue=20token=20api=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/apis/auth.ts | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/client/src/apis/auth.ts b/client/src/apis/auth.ts index 93e59992..f777eb33 100644 --- a/client/src/apis/auth.ts +++ b/client/src/apis/auth.ts @@ -1,4 +1,5 @@ -import { SuccessResponse } from '@@types/apis/response'; +import type { SuccessResponse } from '@@types/apis/response'; + import { API_URL } from '@constants/url'; import axios from 'axios'; @@ -44,5 +45,22 @@ export const signIn: SignIn = ({ id, password }) => { // 액세스 토큰으로 다시 유저 정보 요청해야함 // _id, id(이메일), nickname, status, profileUrl, description +// TODO: 유저 api로 분리하기 export const getMyInfo = () => axios.get(`${API_URL}/api/user/auth/me`).then((res) => res.data); + +export interface ReissueTokenResult { + accessToken: string; +} + +type ReissueToken = () => Promise>; + +export const reissueToken: ReissueToken = () => { + const endPoint = `${API_URL}/api/user/auth/refresh`; + + return axios + .post(endPoint, {}, { withCredentials: true }) + .then((response) => { + return response.data; + }); +}; From cd2651b13c029f2ff2618aeeb11cdc97e2df5586 Mon Sep 17 00:00:00 2001 From: Cola Date: Wed, 23 Nov 2022 05:05:33 +0900 Subject: [PATCH 036/121] =?UTF-8?q?feat:=20useReissueTokenMutation=20?= =?UTF-8?q?=EC=BB=A4=EC=8A=A4=ED=85=80=20=ED=9B=85=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/AuthorizedLayer/index.tsx | 31 ++++++++- client/src/hooks/useReissueTokenMutation.ts | 68 +++++++++++++++++++ client/src/queryKeyCreator.ts | 11 ++- 3 files changed, 106 insertions(+), 4 deletions(-) create mode 100644 client/src/hooks/useReissueTokenMutation.ts diff --git a/client/src/components/AuthorizedLayer/index.tsx b/client/src/components/AuthorizedLayer/index.tsx index f1d0d205..d473f7e3 100644 --- a/client/src/components/AuthorizedLayer/index.tsx +++ b/client/src/components/AuthorizedLayer/index.tsx @@ -1,7 +1,36 @@ -import React from 'react'; +import useReissueTokenMutation from '@hooks/useReissueTokenMutation'; +import { useTokenStore } from '@stores/tokenStore'; +import React, { useEffect } from 'react'; import { Outlet } from 'react-router-dom'; +// 액세스 토큰은 상태로 저장하고, 초깃값이 null이기 때문에 +// 액세스 토큰이 존재한다는 것 자체가 이미 인증이 된 것과 같다. const AuthorizedLayer = () => { + const user = useTokenStore((state) => state.user); + + const accessToken = useTokenStore((state) => state.accessToken); + + console.log(`[AuthLayer - ${location.pathname}]`); + + // 1-1. 유저가 있는지 없는지 체크 + // 1-2. 유저가 있으면 통과 + // if (user) return + // TODO: 준영님 리팩토링 머지 되면 작업할 예정. + + // [X] 2-1. Silent Refresh + // [X] 2-2. 성공시 통과, 실패시 로그인 페이지로. + // NOTE: /access-denied 페이지로 이동하는게 맞는 것 같기도? + + const reissueTokenMutation = useReissueTokenMutation('/sign-in'); + + useEffect(() => { + if (user) return; + + // Silent Refresh + reissueTokenMutation.mutate(); + }, []); + + if (!user && !accessToken) return
    로딩중...
    ; return ; }; diff --git a/client/src/hooks/useReissueTokenMutation.ts b/client/src/hooks/useReissueTokenMutation.ts new file mode 100644 index 00000000..bfc81951 --- /dev/null +++ b/client/src/hooks/useReissueTokenMutation.ts @@ -0,0 +1,68 @@ +import type { ErrorResponse, SuccessResponse } from '@@types/apis/response'; +import type { ReissueTokenResult } from '@apis/auth'; +import type { UseMutationResult } from '@tanstack/react-query'; + +import { reissueToken } from '@apis/auth'; +import { useTokenStore } from '@stores/tokenStore'; +import { useMutation } from '@tanstack/react-query'; +import { AxiosError } from 'axios'; +import { useNavigate } from 'react-router-dom'; + +import queryKeyCreator from '@/queryKeyCreator'; + +type UseReissueTokenMutationResult = UseMutationResult< + SuccessResponse, + unknown, + void, + unknown +>; + +interface UseReissueTokenMutation { + ( + invalidTokenErrorFallback?: string | (() => void), + unknownErrorFallback?: string | (() => void), + ): UseReissueTokenMutationResult; +} + +/** + * @description 서버에서 401 에러가 발생하는 경우에만 accessToken을 리셋하기 때문에, 그 이외의 에러로 로그인이 풀리지는 않음. + */ +const useReissueTokenMutation: UseReissueTokenMutation = ( + invalidTokenErrorFallback, + unknownErrorFallback, +) => { + const navigate = useNavigate(); + const setAccessToken = useTokenStore((state) => state.setAccessToken); + const key = queryKeyCreator.reissueToken(); + const mutation = useMutation(key, reissueToken, { + onSuccess: (data) => { + setAccessToken(data.result.accessToken); + }, + onError: (error) => { + if (!(error instanceof AxiosError)) { + return; + } + + const errorResponse = error.response?.data as ErrorResponse | undefined; + + /** 유효하지 않은 토큰 */ + if (errorResponse?.statusCode === 401) { + setAccessToken(null); + if (typeof invalidTokenErrorFallback === 'string') + navigate(invalidTokenErrorFallback); + else invalidTokenErrorFallback && invalidTokenErrorFallback(); + + return; + } + + /** 네트워크 오류나 기타 서버 오류 등 */ + if (typeof unknownErrorFallback === 'string') { + navigate(unknownErrorFallback); + } else unknownErrorFallback && unknownErrorFallback(); + }, + }); + + return mutation; +}; + +export default useReissueTokenMutation; diff --git a/client/src/queryKeyCreator.ts b/client/src/queryKeyCreator.ts index e563efc0..dc376636 100644 --- a/client/src/queryKeyCreator.ts +++ b/client/src/queryKeyCreator.ts @@ -1,9 +1,14 @@ const queryKeyCreator = { - me: () => ['me'], - signUp: () => ['signUp'], - signIn: () => ['signIn'], + me: () => ['me'] as const, + signUp: () => ['signUp'] as const, + signIn: () => ['signIn'] as const, followings: (): [string] => ['followings'], followers: (): [string] => ['followers'], + reissueToken: () => ['reissueToken'] as const, } as const; export default queryKeyCreator; + +type QueryKeyCreatorType = typeof queryKeyCreator; +export type QueryKeyCreator = + QueryKeyCreatorType[T]; From 52c10bc4f5078ac2800068614da17a59fc0fe791 Mon Sep 17 00:00:00 2001 From: Cola Date: Wed, 23 Nov 2022 05:06:38 +0900 Subject: [PATCH 037/121] =?UTF-8?q?feat:=20UnknownError=20=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/pages/UnknownError/index.tsx | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 client/src/pages/UnknownError/index.tsx diff --git a/client/src/pages/UnknownError/index.tsx b/client/src/pages/UnknownError/index.tsx new file mode 100644 index 00000000..f7f0485a --- /dev/null +++ b/client/src/pages/UnknownError/index.tsx @@ -0,0 +1,9 @@ +import React from 'react'; + +const UnknownError = () => { + console.log(`[${location.pathname}]`); + + return
    Unknown Error
    ; +}; + +export default UnknownError; From 635d36f8d98706f0aba235f8d0cc5b48a9680888 Mon Sep 17 00:00:00 2001 From: Cola Date: Wed, 23 Nov 2022 05:08:17 +0900 Subject: [PATCH 038/121] =?UTF-8?q?feat:=20Root=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/pages/Root/index.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/client/src/pages/Root/index.tsx b/client/src/pages/Root/index.tsx index 7c44f79c..ea339965 100644 --- a/client/src/pages/Root/index.tsx +++ b/client/src/pages/Root/index.tsx @@ -1,7 +1,15 @@ +import { useTokenStore } from '@stores/tokenStore'; import React from 'react'; +import { Navigate } from 'react-router-dom'; const Root = () => { - return
    ; + const user = useTokenStore((state) => state.user); + const accessToken = useTokenStore((state) => state.accessToken); + + // 로그인 되어있으면 dms, 로그인 되어있지 않으면 /sign-in + // 조건문에 둘 중 하나라도 없으면 /sign-in -> / -> /sign-in ... 무한 루프돕니다. + if (user || accessToken) return ; + return ; }; export default Root; From a57ac09b8648afc491f5354b77e7024b0a25fc10 Mon Sep 17 00:00:00 2001 From: Cola Date: Wed, 23 Nov 2022 05:10:58 +0900 Subject: [PATCH 039/121] =?UTF-8?q?feat:=20UnAuthorized=20Layer=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/UnAuthorizedLayer/index.tsx | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/client/src/components/UnAuthorizedLayer/index.tsx b/client/src/components/UnAuthorizedLayer/index.tsx index 3d9c16f2..4cb8858d 100644 --- a/client/src/components/UnAuthorizedLayer/index.tsx +++ b/client/src/components/UnAuthorizedLayer/index.tsx @@ -1,7 +1,30 @@ -import React from 'react'; -import { Outlet } from 'react-router-dom'; +import useReissueTokenMutation from '@hooks/useReissueTokenMutation'; +import { useTokenStore } from '@stores/tokenStore'; +import React, { useEffect, useState } from 'react'; +import { Outlet, Navigate } from 'react-router-dom'; const UnAuthorizedLayer = () => { + const user = useTokenStore((state) => state.user); + + const accessToken = useTokenStore((state) => state.accessToken); + const [isInProgress, setIsInProgress] = useState(true); + + // Silent Refresh + // 성공(로그인 성공) -> / -> /dms + // 실패(로그인 실패) -> 현재 페이지에 머무름. + + const complete = () => setIsInProgress(false); + + const reissueTokenMutation = useReissueTokenMutation(complete, complete); + + useEffect(() => { + if (user) return; + + reissueTokenMutation.mutate(); + }, []); + + if (user || accessToken) return ; + if (isInProgress) return
    로딩중...
    ; return ; }; From dffe3732660f62dd36d9e9d531a00dc9fe32998a Mon Sep 17 00:00:00 2001 From: Cola Date: Wed, 23 Nov 2022 05:12:16 +0900 Subject: [PATCH 040/121] =?UTF-8?q?feat:=20axios=20utils=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/utils/axios.ts | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 client/src/utils/axios.ts diff --git a/client/src/utils/axios.ts b/client/src/utils/axios.ts new file mode 100644 index 00000000..cce8d391 --- /dev/null +++ b/client/src/utils/axios.ts @@ -0,0 +1,8 @@ +import { tokenStore } from '@stores/tokenStore'; +import axios from 'axios'; + +const { getState } = tokenStore; + +const tokenAxios = axios.create(); + +const publicAxios = axios.create(); From 2c050351a68ff6f1d62333aea974f80c1dfa80a8 Mon Sep 17 00:00:00 2001 From: Cola Date: Wed, 23 Nov 2022 05:13:03 +0900 Subject: [PATCH 041/121] feat: ReissueToken Mock Api --- client/src/mocks/handlers/Auth.js | 49 ++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/client/src/mocks/handlers/Auth.js b/client/src/mocks/handlers/Auth.js index 5470db8b..1f29efbc 100644 --- a/client/src/mocks/handlers/Auth.js +++ b/client/src/mocks/handlers/Auth.js @@ -65,6 +65,53 @@ const SignIn = rest.post(`${BASE_URL}/user/auth/signin`, (req, res, ctx) => { return ERROR ? errorResponse : successResponse; }); +// 토큰 재발급 +const ReissueToken = rest.post( + `${BASE_URL}/user/auth/refresh`, + (req, res, ctx) => { + // 응답 메세지 성공-실패를 토글하려면 이 값을 바꿔주세요. + const ERROR = true; + const isUnknownError = true; + + const successResponse = res( + ctx.status(200), + ctx.delay(1000), + ctx.json({ + statusCode: 200, + result: { + accessToken: 'accessToken', + }, + }), + ); + + const unAuthErrorResponse = res( + ctx.status(400), + ctx.delay(1000), + ctx.json({ + statusCode: 401, + message: 'Unauthorized', + error: '', + }), + ); + + const unknownErrorResponse = res( + ctx.status(400), + ctx.delay(1000), + ctx.json({ + statusCode: 502, + message: 'Unknown', + error: '', + }), + ); + + const errorResponse = isUnknownError + ? unknownErrorResponse + : unAuthErrorResponse; + + return ERROR ? errorResponse : successResponse; + }, +); + export const GetMyInfo = rest.get( `${BASE_URL}/user/auth/me`, (req, res, ctx) => { @@ -81,4 +128,4 @@ export const GetMyInfo = rest.get( }, ); -export default [SignUp, SignIn, GetMyInfo]; +export default [SignUp, SignIn, GetMyInfo, ReissueToken]; From 30f60f5dd1516cf3df5f1e28c50d991f5cd1a6f7 Mon Sep 17 00:00:00 2001 From: Cola Date: Wed, 23 Nov 2022 05:13:42 +0900 Subject: [PATCH 042/121] =?UTF-8?q?feat:=20user=20=EC=83=81=ED=83=9C=20?= =?UTF-8?q?=EC=9E=84=EC=8B=9C=EB=A1=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/stores/tokenStore.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client/src/stores/tokenStore.ts b/client/src/stores/tokenStore.ts index b13ad94a..124652d7 100644 --- a/client/src/stores/tokenStore.ts +++ b/client/src/stores/tokenStore.ts @@ -2,13 +2,16 @@ import { useStore } from 'zustand'; import { devtools } from 'zustand/middleware'; import createVanillaStore from 'zustand/vanilla'; +// NOTE: user는 임시로 넣어둔 상태입니다. type TokenStore = { + user: boolean; accessToken: null | string; setAccessToken: (accessToken: null | string) => void; }; export const tokenStore = createVanillaStore()( devtools((set) => ({ + user: false, accessToken: null, setAccessToken: (newAccessToken) => set(() => ({ accessToken: newAccessToken })), From 49d332ff999cd5af94fb9d69e38b1c2f70ccc190 Mon Sep 17 00:00:00 2001 From: Cola Date: Wed, 23 Nov 2022 05:14:01 +0900 Subject: [PATCH 043/121] =?UTF-8?q?chore:=20no-empty-function=20rule=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/.eslintrc | 1 + 1 file changed, 1 insertion(+) diff --git a/client/.eslintrc b/client/.eslintrc index 44939533..a4598dee 100644 --- a/client/.eslintrc +++ b/client/.eslintrc @@ -27,6 +27,7 @@ "@typescript-eslint/no-var-requires": "off", "react/no-unknown-property": "off", "no-duplicate-imports": "off", + "@typescript-eslint/no-empty-function": "off", "@typescript-eslint/consistent-type-imports": "error", "no-nested-ternary": "off" } From 67f15d99aab63bf68cb9a3c4b175c8796d3f23e7 Mon Sep 17 00:00:00 2001 From: Cola Date: Wed, 23 Nov 2022 11:13:17 +0900 Subject: [PATCH 044/121] =?UTF-8?q?feat:=20AuthorizedLayer=20unknown=20err?= =?UTF-8?q?or=20fallback=20url=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/AuthorizedLayer/index.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/client/src/components/AuthorizedLayer/index.tsx b/client/src/components/AuthorizedLayer/index.tsx index d473f7e3..43a88f84 100644 --- a/client/src/components/AuthorizedLayer/index.tsx +++ b/client/src/components/AuthorizedLayer/index.tsx @@ -21,7 +21,10 @@ const AuthorizedLayer = () => { // [X] 2-2. 성공시 통과, 실패시 로그인 페이지로. // NOTE: /access-denied 페이지로 이동하는게 맞는 것 같기도? - const reissueTokenMutation = useReissueTokenMutation('/sign-in'); + const reissueTokenMutation = useReissueTokenMutation( + '/sign-in', + '/unknown-error', + ); useEffect(() => { if (user) return; From 5fd9a24287559b981bf612fc552e17045616d9ea Mon Sep 17 00:00:00 2001 From: Cola Date: Wed, 23 Nov 2022 11:13:49 +0900 Subject: [PATCH 045/121] =?UTF-8?q?chore:=20ReissueToken=20Mock=20Api=20?= =?UTF-8?q?=EC=9D=91=EB=8B=B5=20Status=20=EC=98=AC=EB=B0=94=EB=A5=B4?= =?UTF-8?q?=EA=B2=8C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/mocks/handlers/Auth.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/mocks/handlers/Auth.js b/client/src/mocks/handlers/Auth.js index 1f29efbc..de528778 100644 --- a/client/src/mocks/handlers/Auth.js +++ b/client/src/mocks/handlers/Auth.js @@ -85,7 +85,7 @@ const ReissueToken = rest.post( ); const unAuthErrorResponse = res( - ctx.status(400), + ctx.status(401), ctx.delay(1000), ctx.json({ statusCode: 401, @@ -95,7 +95,7 @@ const ReissueToken = rest.post( ); const unknownErrorResponse = res( - ctx.status(400), + ctx.status(502), ctx.delay(1000), ctx.json({ statusCode: 502, From dd0fe0c399ca31abb5ed7732cea1accf556c7e12 Mon Sep 17 00:00:00 2001 From: Cola Date: Wed, 23 Nov 2022 16:25:54 +0900 Subject: [PATCH 046/121] =?UTF-8?q?chore:=20=EC=BD=94=EB=93=9C=EB=B8=94?= =?UTF-8?q?=EB=9F=AD=EC=97=90=20=ED=94=84=EB=A6=AC=ED=8B=B0=EC=96=B4=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/pages/Friends/index.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/client/src/pages/Friends/index.tsx b/client/src/pages/Friends/index.tsx index 61b8f9aa..6ad20144 100644 --- a/client/src/pages/Friends/index.tsx +++ b/client/src/pages/Friends/index.tsx @@ -49,8 +49,9 @@ const Friends = () => { {tabs.map(({ name, tab: t }) => (
  • + {usersQuery.data?.users.length ? ( From 7970ab20eaced7e28681c522956f6608f8b90abf Mon Sep 17 00:00:00 2001 From: leegwae Date: Thu, 24 Nov 2022 16:59:40 +0900 Subject: [PATCH 084/121] =?UTF-8?q?fix:=20/GET=20`/api/user/auth/me`=20moc?= =?UTF-8?q?k=20API=20=EB=B0=98=ED=99=98=EA=B0=92=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `result`를 객체가 아니라 값 그대로 넣어주는 것으로 변경 --- client/src/mocks/handlers/Auth.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/client/src/mocks/handlers/Auth.js b/client/src/mocks/handlers/Auth.js index de528778..7bd2af94 100644 --- a/client/src/mocks/handlers/Auth.js +++ b/client/src/mocks/handlers/Auth.js @@ -120,9 +120,7 @@ export const GetMyInfo = rest.get( ctx.status(200), ctx.json({ statusCode: 200, - result: { - user: users[0], - }, + result: users[0], }), ); }, From 4ed11bcaf289726272d246115f1bde796a4690be Mon Sep 17 00:00:00 2001 From: Cola Date: Thu, 24 Nov 2022 21:06:45 +0900 Subject: [PATCH 085/121] =?UTF-8?q?feat:=20wrapper=20=EC=8A=A4=ED=83=80?= =?UTF-8?q?=EC=9D=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/index.css | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/client/src/index.css b/client/src/index.css index ff8c90ab..b39d69f7 100644 --- a/client/src/index.css +++ b/client/src/index.css @@ -10,4 +10,12 @@ #root { width: 100vw; +} + +.wrapper { + position: fixed; + top: 0; + bottom: 0; + left: 0; + right: 0; } \ No newline at end of file From c6e5d3c44fed5b89b6a8fbc613054a48667cb5c0 Mon Sep 17 00:00:00 2001 From: Cola Date: Thu, 24 Nov 2022 21:07:08 +0900 Subject: [PATCH 086/121] =?UTF-8?q?refactor:=20@description=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/utils/axios.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/client/src/utils/axios.ts b/client/src/utils/axios.ts index e622e400..b78d783e 100644 --- a/client/src/utils/axios.ts +++ b/client/src/utils/axios.ts @@ -5,7 +5,6 @@ import axios from 'axios'; const { getState } = tokenStore; /** - * @description * ## Asnity api server 전용 Axios instance * - `baseURL`은 Asnity server 이다. 따라서 엔드포인트 작성시 `baseURL`이후 부분만 적는다. * - Api 요청시 전역 상태에서 관리하는 accessToken을 Authorization header에 삽입하고 보낸다. @@ -17,7 +16,6 @@ export const tokenAxios = axios.create({ }); /** - * @description * ## Asnity api server 전용 Axios instance * - `baseURL`은 Asnity server 이다. 따라서 엔드포인트 작성시 `baseURL`이후 부분만 적는다. * - accessToken이 필요없는 요청을 보낼 때 사용한다. From f4f3372d259b22518dab4f118d94485cf7a40c72 Mon Sep 17 00:00:00 2001 From: Cola Date: Thu, 24 Nov 2022 21:07:47 +0900 Subject: [PATCH 087/121] =?UTF-8?q?refactor:=20=EB=A3=A8=ED=8A=B8=EC=97=90?= =?UTF-8?q?=20wrapper=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/pages/Home/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/pages/Home/index.tsx b/client/src/pages/Home/index.tsx index f7281be6..e3c564a3 100644 --- a/client/src/pages/Home/index.tsx +++ b/client/src/pages/Home/index.tsx @@ -5,8 +5,8 @@ import { Outlet } from 'react-router-dom'; const Home = () => { return ( -
    - +
    +
    From 80271cbcc3ae63e24f882404501e8fc516176832 Mon Sep 17 00:00:00 2001 From: Cola Date: Thu, 24 Nov 2022 21:08:34 +0900 Subject: [PATCH 088/121] =?UTF-8?q?refactor:=20@description=20=EC=A3=BC?= =?UTF-8?q?=EC=84=9D=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/pages/UnAuthorizedLayer/index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/client/src/pages/UnAuthorizedLayer/index.tsx b/client/src/pages/UnAuthorizedLayer/index.tsx index bf17be0a..94963043 100644 --- a/client/src/pages/UnAuthorizedLayer/index.tsx +++ b/client/src/pages/UnAuthorizedLayer/index.tsx @@ -5,7 +5,6 @@ import React, { useEffect, useState } from 'react'; import { Outlet, Navigate, useLocation } from 'react-router-dom'; /** - * @description * ## 로그인 하지 않은 유저들만 머무를 수 있는 페이지. * - 새로고침시 토큰 갱신을 시도하며, 로그인한(유저 상태나 액세스 토큰 상태가 있는) 유저가 접근하면 **`/`** 로 리다이렉트된다. * - 토큰 갱신 요청시, 유효하지 않은 토큰 에러나 알 수 없는 에러가 발생하면 페이지 이동 없이 그대로 유지한다. From 310a6a83d054a875ef994e1411d0c5fde65478c4 Mon Sep 17 00:00:00 2001 From: Cola Date: Thu, 24 Nov 2022 21:10:10 +0900 Subject: [PATCH 089/121] =?UTF-8?q?feat:=20=EC=8A=A4=ED=81=AC=EB=A1=A4=20?= =?UTF-8?q?=EC=8A=A4=ED=83=80=EC=9D=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/layouts/Followers/index.tsx | 28 +++++++++++++------------ client/src/layouts/Followings/index.tsx | 28 +++++++++++++------------ client/src/pages/Friends/index.tsx | 13 ++++++------ client/src/pages/Home/index.tsx | 2 +- 4 files changed, 38 insertions(+), 33 deletions(-) diff --git a/client/src/layouts/Followers/index.tsx b/client/src/layouts/Followers/index.tsx index 9f01b5f9..6b5aec72 100644 --- a/client/src/layouts/Followers/index.tsx +++ b/client/src/layouts/Followers/index.tsx @@ -1,5 +1,5 @@ import FollowerUserItem from '@components/FollowerUserItem'; -import SearchInput from '@components/searchInput'; +import SearchInput from '@components/SearchInput'; import UserList from '@components/UserList'; import useDebouncedValue from '@hooks/useDebouncedValue'; import useFollowersQuery from '@hooks/useFollowersQuery'; @@ -12,7 +12,7 @@ const Followers = () => { const followersQuery = useFollowersQuery(debouncedFilter); return ( -
    +
    { placeholder="검색하기" />
    - {followersQuery.isLoading ? ( -
    loading...
    - ) : followersQuery.data?.followers.length ? ( - - {followersQuery.data.followers.map((user) => ( - - ))} - - ) : ( - '일치하는 사용자가 없습니다.' - )} +
    + {followersQuery.isLoading ? ( +
    loading...
    + ) : followersQuery.data?.followers.length ? ( + + {followersQuery.data.followers.map((user) => ( + + ))} + + ) : ( + '일치하는 사용자가 없습니다.' + )} +
    ); }; diff --git a/client/src/layouts/Followings/index.tsx b/client/src/layouts/Followings/index.tsx index 394e3944..7abdf43b 100644 --- a/client/src/layouts/Followings/index.tsx +++ b/client/src/layouts/Followings/index.tsx @@ -1,5 +1,5 @@ import FollowingUserItem from '@components/FollowingUserItem'; -import SearchInput from '@components/searchInput'; +import SearchInput from '@components/SearchInput'; import UserList from '@components/UserList'; import useDebouncedValue from '@hooks/useDebouncedValue'; import useFollowingsQuery from '@hooks/useFollowingsQuery'; @@ -12,7 +12,7 @@ const Followings = () => { const followingsQuery = useFollowingsQuery(debouncedFilter); return ( -
    +
    { placeholder="검색하기" />
    - {followingsQuery.isLoading ? ( -
    loading...
    - ) : followingsQuery.data?.followings.length ? ( - - {followingsQuery.data.followings.map((user) => ( - - ))} - - ) : ( - '일치하는 사용자가 없습니다.' - )} +
    + {followingsQuery.isLoading ? ( +
    loading...
    + ) : followingsQuery.data?.followings.length ? ( + + {followingsQuery.data.followings.map((user) => ( + + ))} + + ) : ( + '일치하는 사용자가 없습니다.' + )} +
    ); }; diff --git a/client/src/pages/Friends/index.tsx b/client/src/pages/Friends/index.tsx index e7879af6..dd16ff97 100644 --- a/client/src/pages/Friends/index.tsx +++ b/client/src/pages/Friends/index.tsx @@ -43,14 +43,15 @@ const Friends = () => { ); return ( -
    -
    +
    +
      {tabs.map(({ name, tab: t }) => (
    -
    -
    +
    +
    {TabPanel[tab]}
    diff --git a/client/src/pages/Home/index.tsx b/client/src/pages/Home/index.tsx index e3c564a3..6e7bdc60 100644 --- a/client/src/pages/Home/index.tsx +++ b/client/src/pages/Home/index.tsx @@ -6,7 +6,7 @@ import { Outlet } from 'react-router-dom'; const Home = () => { return (
    - +
    From c79f0d80d78261d66419a92b9dd577523f08db7d Mon Sep 17 00:00:00 2001 From: Cola Date: Thu, 24 Nov 2022 21:10:23 +0900 Subject: [PATCH 090/121] =?UTF-8?q?refactor:=20m=ED=81=ACmo=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/FollowingUserItem/index.tsx | 4 ++-- client/src/components/UserItem/index.tsx | 4 ++-- client/src/layouts/UserSearch/index.tsx | 24 ++++++++++--------- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/client/src/components/FollowingUserItem/index.tsx b/client/src/components/FollowingUserItem/index.tsx index cc8c78c2..b8056baf 100644 --- a/client/src/components/FollowingUserItem/index.tsx +++ b/client/src/components/FollowingUserItem/index.tsx @@ -6,7 +6,7 @@ import { ChatBubbleLeftIcon, } from '@heroicons/react/20/solid'; import useFollowingMutation from '@hooks/useFollowingMutation'; -import React from 'react'; +import React, { memo } from 'react'; import { useNavigate } from 'react-router-dom'; interface Props { @@ -47,4 +47,4 @@ const FollowingUserItem: React.FC = ({ user }) => { ); }; -export default FollowingUserItem; +export default memo(FollowingUserItem); diff --git a/client/src/components/UserItem/index.tsx b/client/src/components/UserItem/index.tsx index ae05f7f5..659f951b 100644 --- a/client/src/components/UserItem/index.tsx +++ b/client/src/components/UserItem/index.tsx @@ -2,7 +2,7 @@ import type { User } from '@apis/user'; import type { ComponentPropsWithoutRef, ReactNode } from 'react'; import UserProfile from '@components/UserProfile'; -import React from 'react'; +import React, { memo } from 'react'; interface Props extends ComponentPropsWithoutRef<'li'> { user: User; @@ -18,4 +18,4 @@ const UserItem: React.FC = ({ user, right }) => { ); }; -export default UserItem; +export default memo(UserItem); diff --git a/client/src/layouts/UserSearch/index.tsx b/client/src/layouts/UserSearch/index.tsx index c5b7f5f4..f7184bd1 100644 --- a/client/src/layouts/UserSearch/index.tsx +++ b/client/src/layouts/UserSearch/index.tsx @@ -1,7 +1,7 @@ import type { FormEvent } from 'react'; import FollowerUserItem from '@components/FollowerUserItem'; -import SearchInput from '@components/searchInput'; +import SearchInput from '@components/SearchInput'; import UserList from '@components/UserList'; import useUsersQuery from '@hooks/useUsersQuery'; import React, { useState } from 'react'; @@ -26,7 +26,7 @@ const UserSearch = () => { }; return ( -
    +
    {
    - {usersQuery.data?.users.length ? ( - - {usersQuery.data.users.map((user) => ( - - ))} - - ) : ( -
    검색된 사용자가 없습니다
    - )} +
    + {usersQuery.data?.users.length ? ( + + {usersQuery.data.users.map((user) => ( + + ))} + + ) : ( +
    검색된 사용자가 없습니다
    + )} +
    ); }; From 59a7088205e4eef16681949852b1b72c9d9c92c1 Mon Sep 17 00:00:00 2001 From: leegwae Date: Fri, 25 Nov 2022 17:46:39 +0900 Subject: [PATCH 091/121] =?UTF-8?q?build:=20mock=20up=20=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=84=B0=20=EC=9E=91=EC=84=B1=EC=9D=84=20=EC=9C=84=ED=95=9C=20?= =?UTF-8?q?`faker.js`=20=EC=84=A4=EC=B9=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/package.json | 1 + client/tsconfig.json | 11 +++++------ yarn.lock | 5 +++++ 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/client/package.json b/client/package.json index 118aafc6..1594440c 100644 --- a/client/package.json +++ b/client/package.json @@ -30,6 +30,7 @@ "@babel/preset-env": "^7.20.2", "@babel/preset-react": "^7.18.6", "@babel/preset-typescript": "^7.18.6", + "@faker-js/faker": "^7.6.0", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.9", "@tanstack/react-query-devtools": "^4.16.1", "@testing-library/jest-dom": "^5.16.5", diff --git a/client/tsconfig.json b/client/tsconfig.json index 4eb34214..d7bde1a6 100644 --- a/client/tsconfig.json +++ b/client/tsconfig.json @@ -1,15 +1,13 @@ { "extends": "../tsconfig.json", "compilerOptions": { - "lib": [ - "DOM", - "es2015.iterable" - ], + "esModuleInterop": true, + "moduleResolution": "Node", + "lib": ["DOM", "es2015.iterable"], "jsx": "react-jsx", "baseUrl": ".", "outDir": "./build", "paths": { - "@/*": ["src/*"], "@pages/*": ["src/pages/*"], "@layouts/*": ["src/layouts/*"], "@components/*": ["src/components/*"], @@ -20,7 +18,8 @@ "@apis/*": ["src/apis/*"], "@hooks/*": ["src/hooks/*"], "@errors/*": ["src/errors/*"], - "@@types/*": ["src/types/*"] + "@@types/*": ["src/types/*"], + "@/*": ["src/*"] } }, "include": ["src", "config"], diff --git a/yarn.lock b/yarn.lock index f9ae5416..3a9ca5ed 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1844,6 +1844,11 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" +"@faker-js/faker@^7.6.0": + version "7.6.0" + resolved "https://registry.yarnpkg.com/@faker-js/faker/-/faker-7.6.0.tgz#9ea331766084288634a9247fcd8b84f16ff4ba07" + integrity sha512-XK6BTq1NDMo9Xqw/YkYyGjSsg44fbNwYRx7QK2CuoQgyy+f1rrTDHoExVM5PsyXCtfl2vs2vVJ0MN0yN6LppRw== + "@graphql-tools/merge@8.3.11": version "8.3.11" resolved "https://registry.yarnpkg.com/@graphql-tools/merge/-/merge-8.3.11.tgz#f5eab764e8d7032c1b7e32d5dc6dea5b2f5bb21e" From 857a979a5690477086d43058d5488c9c1b9a5de5 Mon Sep 17 00:00:00 2001 From: leegwae Date: Fri, 25 Nov 2022 17:49:18 +0900 Subject: [PATCH 092/121] =?UTF-8?q?chore:=20`users`=20mock=20=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=20`faker.js`=EB=A1=9C=20=EC=83=9D=EC=84=B1?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/mocks/data/users.js | 78 ++++++---------------------------- 1 file changed, 12 insertions(+), 66 deletions(-) diff --git a/client/src/mocks/data/users.js b/client/src/mocks/data/users.js index 5644bcc8..1990c30d 100644 --- a/client/src/mocks/data/users.js +++ b/client/src/mocks/data/users.js @@ -1,68 +1,14 @@ +import { faker } from '@faker-js/faker'; + import { getRandomInt } from '../utils/rand'; -export const users = [ - { - _id: '6379beb15d4f08bbe0c940e9', - id: 'test@test.com', - nickname: 'test', - status: 'online', - profileUrl: `https://picsum.photos/id/${getRandomInt(500)}/70`, - description: 'default description', - }, - { - _id: '6379c1b25d4f08bbe0c940ef', - id: 'soomanbaek@naver.com', - nickname: 'sooman', - status: '', - profileUrl: `https://picsum.photos/id/${getRandomInt(500)}/70`, - description: 'default description', - }, - { - _id: '637a143c2e0b02d228d9c4fc', - id: 'test999@test.com', - nickname: 'test', - status: 'online', - profileUrl: `https://picsum.photos/id/${getRandomInt(500)}/70`, - description: 'default description', - }, - { - _id: '637a14ea2e0b02d228d9c4fe', - id: 'asnity@asnity.com', - nickname: 'asnity', - status: 'offline', - profileUrl: `https://picsum.photos/id/${getRandomInt(500)}/70`, - description: 'default description', - }, - { - _id: '637b3536c5105b5805888e34', - id: 'sooman@naver.com', - nickname: 'sooman', - status: 'offline', - profileUrl: `https://picsum.photos/id/${getRandomInt(500)}/70`, - description: 'default description', - }, - { - _id: '637b6ad90680fb86893517a5', - id: 'sooman11@naver.com', - nickname: 'sooman', - status: 'afk', - profileUrl: `https://picsum.photos/id/${getRandomInt(500)}/70`, - description: 'default description', - }, - { - _id: '637c510611fd8ffcabe029cd', - id: 'test@naver.com', - nickname: 'asnity', - status: 'offline', - profileUrl: `https://picsum.photos/id/${getRandomInt(500)}/70`, - description: 'i change description3', - }, - { - _id: '637cc581c3801784d5a5f150', - id: 'leegwae@gmail.com', - nickname: '이준영', - status: 'afk', - profileUrl: `https://picsum.photos/id/${getRandomInt(500)}/70`, - description: 'default description', - }, -]; +export const createMockUser = () => ({ + _id: faker.datatype.uuid(), + id: faker.internet.email(), + nickname: faker.name.fullName(), + status: ['online', 'offline', 'afk'][getRandomInt(3)], + profileUrl: faker.image.avatar(), + description: faker.lorem.sentence(), +}); + +export const users = [...Array(30)].map(createMockUser); From 1eae24809e917fc859c3871d5cf361ca3a28f535 Mon Sep 17 00:00:00 2001 From: leegwae Date: Fri, 25 Nov 2022 17:50:13 +0900 Subject: [PATCH 093/121] =?UTF-8?q?feat:=20GET=20`/api/user/dms`=20mock=20?= =?UTF-8?q?API=20=EC=9E=91=EC=84=B1=20#125?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/mocks/handlers/DM.js | 23 +++++++++++++++++++++++ client/src/mocks/handlers/index.js | 8 +++++++- 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 client/src/mocks/handlers/DM.js diff --git a/client/src/mocks/handlers/DM.js b/client/src/mocks/handlers/DM.js new file mode 100644 index 00000000..a8e6b504 --- /dev/null +++ b/client/src/mocks/handlers/DM.js @@ -0,0 +1,23 @@ +import { API_URL } from '@constants/url'; +import { rest } from 'msw'; + +import { users } from '../data/users'; + +const GetDirectMessages = rest.get( + `${API_URL}/api/user/dms`, + (req, res, ctx) => { + return res( + ctx.delay(), + ctx.status(200), + ctx.json({ + statusCode: 200, + result: [...users.slice(0, 5)].map((user, idx) => ({ + _id: idx, + user, + })), + }), + ); + }, +); + +export default [GetDirectMessages]; diff --git a/client/src/mocks/handlers/index.js b/client/src/mocks/handlers/index.js index 7911dbba..a411c0e4 100644 --- a/client/src/mocks/handlers/index.js +++ b/client/src/mocks/handlers/index.js @@ -1,5 +1,11 @@ import AuthHandlers from './Auth'; +import DMHandlers from './DM'; import FriendHandlers from './Friend'; import UserHandlers from './User'; -export const handlers = [...AuthHandlers, ...FriendHandlers, ...UserHandlers]; +export const handlers = [ + ...AuthHandlers, + ...FriendHandlers, + ...UserHandlers, + ...DMHandlers, +]; From e2da9a763d13f1a63a3d3350ca3ffb2e250fa731 Mon Sep 17 00:00:00 2001 From: leegwae Date: Fri, 25 Nov 2022 17:50:32 +0900 Subject: [PATCH 094/121] =?UTF-8?q?feat:=20DM=20=EB=AA=A9=EB=A1=9D=20?= =?UTF-8?q?=EA=B0=80=EC=A0=B8=EC=98=A4=EA=B8=B0=20API=20=EC=9E=91=EC=84=B1?= =?UTF-8?q?=20#125?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/apis/dm.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 client/src/apis/dm.ts diff --git a/client/src/apis/dm.ts b/client/src/apis/dm.ts new file mode 100644 index 00000000..a241d3c2 --- /dev/null +++ b/client/src/apis/dm.ts @@ -0,0 +1,16 @@ +import type { User } from '@apis/user'; + +import { API_URL } from '@constants/url'; +import axios from 'axios'; + +export interface DirectMessage { + _id: string; + user: User; +} + +export type GetDirectMessagesResult = DirectMessage[]; + +export type GetDirectMessages = () => Promise; + +export const getDirectMessages: GetDirectMessages = () => + axios.get(`${API_URL}/api/user/dms`).then((res) => res.data.result); From 384bd15aa229fa8a4306080d0ee834c81f3abe9a Mon Sep 17 00:00:00 2001 From: leegwae Date: Fri, 25 Nov 2022 17:52:00 +0900 Subject: [PATCH 095/121] =?UTF-8?q?feat:=20`directMessageQueryKey`=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1=20#125?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/queryKeyCreator.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/client/src/queryKeyCreator.ts b/client/src/queryKeyCreator.ts index e4e4c7d4..31e04bce 100644 --- a/client/src/queryKeyCreator.ts +++ b/client/src/queryKeyCreator.ts @@ -1,3 +1,9 @@ +const directMessageQueryKey = { + all: ['directMessages'] as const, + list: () => [...directMessageQueryKey.all] as const, + detail: (id: string) => [...directMessageQueryKey.all, id] as const, +} as const; + const queryKeyCreator = { me: () => ['me'] as const, signUp: () => ['signUp'] as const, @@ -6,6 +12,7 @@ const queryKeyCreator = { followers: (): [string] => ['followers'], reissueToken: () => ['reissueToken'] as const, userSearch: (filter: string) => ['userSearch', { filter }], + directMessage: directMessageQueryKey, } as const; export default queryKeyCreator; From 14bc762a334117c0d52588349e6efae4ef86ea91 Mon Sep 17 00:00:00 2001 From: leegwae Date: Fri, 25 Nov 2022 17:52:55 +0900 Subject: [PATCH 096/121] =?UTF-8?q?feat:=20`useDirectMessagesQuery`=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1=20#125?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/hooks/useDirectMessagesQuery.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 client/src/hooks/useDirectMessagesQuery.ts diff --git a/client/src/hooks/useDirectMessagesQuery.ts b/client/src/hooks/useDirectMessagesQuery.ts new file mode 100644 index 00000000..474f4ac5 --- /dev/null +++ b/client/src/hooks/useDirectMessagesQuery.ts @@ -0,0 +1,18 @@ +import type { GetDirectMessagesResult } from '@apis/dm'; +import type { AxiosError } from 'axios'; + +import { getDirectMessages } from '@apis/dm'; +import { useQuery } from '@tanstack/react-query'; + +import queryKeyCreator from '@/queryKeyCreator'; + +const useDirectMessagesQuery = () => { + const query = useQuery( + queryKeyCreator.directMessage.list(), + getDirectMessages, + ); + + return query; +}; + +export default useDirectMessagesQuery; From 90847262e573967ce354c14ba114e65d24a3c0b6 Mon Sep 17 00:00:00 2001 From: leegwae Date: Fri, 25 Nov 2022 18:03:06 +0900 Subject: [PATCH 097/121] =?UTF-8?q?design:=20`UserItem`=20=EB=86=92?= =?UTF-8?q?=EC=9D=B4=20=EB=B3=80=EA=B2=BD,=20`hover`=20=EB=B6=99=EC=9D=B4?= =?UTF-8?q?=EB=8A=94=20=EA=B3=B3=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit !리팩토링 필요! --- client/src/components/UserItem/index.tsx | 4 ++-- client/src/components/UserProfile/index.tsx | 2 +- client/src/layouts/Followers/index.tsx | 26 ++++++++++----------- client/src/layouts/Followings/index.tsx | 26 ++++++++++----------- client/src/layouts/UserSearch/index.tsx | 22 ++++++++--------- 5 files changed, 40 insertions(+), 40 deletions(-) diff --git a/client/src/components/UserItem/index.tsx b/client/src/components/UserItem/index.tsx index 659f951b..8a9604cb 100644 --- a/client/src/components/UserItem/index.tsx +++ b/client/src/components/UserItem/index.tsx @@ -11,10 +11,10 @@ interface Props extends ComponentPropsWithoutRef<'li'> { const UserItem: React.FC = ({ user, right }) => { return ( -
  • +
    {right} -
  • +
    ); }; diff --git a/client/src/components/UserProfile/index.tsx b/client/src/components/UserProfile/index.tsx index d2ef469b..6c0c1446 100644 --- a/client/src/components/UserProfile/index.tsx +++ b/client/src/components/UserProfile/index.tsx @@ -20,7 +20,7 @@ const UserProfile: React.FC = ({ user: { nickname, profileUrl, status }, }) => { return ( -
    +
    { placeholder="검색하기" />
    -
    - {followersQuery.isLoading ? ( -
    loading...
    - ) : followersQuery.data?.followers.length ? ( - - {followersQuery.data.followers.map((user) => ( - - ))} - - ) : ( - '일치하는 사용자가 없습니다.' - )} -
    + {followersQuery.isLoading ? ( +
    loading...
    + ) : followersQuery.data?.followers.length ? ( + + {followersQuery.data.followers.map((user) => ( +
  • + +
  • + ))} +
    + ) : ( + '일치하는 사용자가 없습니다.' + )}
    ); }; diff --git a/client/src/layouts/Followings/index.tsx b/client/src/layouts/Followings/index.tsx index 7abdf43b..4b5b0418 100644 --- a/client/src/layouts/Followings/index.tsx +++ b/client/src/layouts/Followings/index.tsx @@ -20,19 +20,19 @@ const Followings = () => { placeholder="검색하기" />
    -
    - {followingsQuery.isLoading ? ( -
    loading...
    - ) : followingsQuery.data?.followings.length ? ( - - {followingsQuery.data.followings.map((user) => ( - - ))} - - ) : ( - '일치하는 사용자가 없습니다.' - )} -
    + {followingsQuery.isLoading ? ( +
    loading...
    + ) : followingsQuery.data?.followings.length ? ( + + {followingsQuery.data.followings.map((user) => ( +
  • + +
  • + ))} +
    + ) : ( + '일치하는 사용자가 없습니다.' + )}
    ); }; diff --git a/client/src/layouts/UserSearch/index.tsx b/client/src/layouts/UserSearch/index.tsx index f7184bd1..514df464 100644 --- a/client/src/layouts/UserSearch/index.tsx +++ b/client/src/layouts/UserSearch/index.tsx @@ -39,17 +39,17 @@ const UserSearch = () => {
    -
    - {usersQuery.data?.users.length ? ( - - {usersQuery.data.users.map((user) => ( - - ))} - - ) : ( -
    검색된 사용자가 없습니다
    - )} -
    + {usersQuery.data?.users.length ? ( + + {usersQuery.data.users.map((user) => ( +
  • + +
  • + ))} +
    + ) : ( +
    검색된 사용자가 없습니다
    + )}
    ); }; From 73ce76c6e2bf8f69ec37b64420e6bee2fbc4878a Mon Sep 17 00:00:00 2001 From: leegwae Date: Fri, 25 Nov 2022 18:03:42 +0900 Subject: [PATCH 098/121] =?UTF-8?q?feat:=20DM=20=EB=AA=A9=EB=A1=9D=20?= =?UTF-8?q?=EB=B3=B4=EC=97=AC=EC=A3=BC=EB=8A=94=20`DMNav`=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1=20#125?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/layouts/DmNav/index.tsx | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/client/src/layouts/DmNav/index.tsx b/client/src/layouts/DmNav/index.tsx index 927aae18..1a048bcb 100644 --- a/client/src/layouts/DmNav/index.tsx +++ b/client/src/layouts/DmNav/index.tsx @@ -1,12 +1,35 @@ +import UserProfile from '@components/UserProfile'; +import useDirectMessagesQuery from '@hooks/useDirectMessagesQuery'; import React from 'react'; -import { Link } from 'react-router-dom'; +import { Link, useNavigate } from 'react-router-dom'; const DmNav = () => { + const naviagte = useNavigate(); + const directMessagesQuery = useDirectMessagesQuery(); + return ( ); }; From dbad2bf3bb28da0807154a61680d620df30364d3 Mon Sep 17 00:00:00 2001 From: leegwae Date: Fri, 25 Nov 2022 18:07:37 +0900 Subject: [PATCH 099/121] =?UTF-8?q?feat:=20`development`=EC=9D=B8=20?= =?UTF-8?q?=EA=B2=BD=EC=9A=B0=20`accessToken`=EC=97=90=20=EB=8D=94?= =?UTF-8?q?=EB=AF=B8=20=EB=AC=B8=EC=9E=90=EC=97=B4=20=EB=84=A3=EC=96=B4?= =?UTF-8?q?=EC=A4=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/stores/tokenStore.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/stores/tokenStore.ts b/client/src/stores/tokenStore.ts index b13ad94a..854fdd91 100644 --- a/client/src/stores/tokenStore.ts +++ b/client/src/stores/tokenStore.ts @@ -9,7 +9,7 @@ type TokenStore = { export const tokenStore = createVanillaStore()( devtools((set) => ({ - accessToken: null, + accessToken: process.env.NODE_ENV === 'development' ? 'null' : null, setAccessToken: (newAccessToken) => set(() => ({ accessToken: newAccessToken })), })), From d311a4cdfa09e7c92f428827056d87cd87ba0cfc Mon Sep 17 00:00:00 2001 From: leegwae Date: Fri, 25 Nov 2022 18:09:14 +0900 Subject: [PATCH 100/121] =?UTF-8?q?feat:=20=ED=99=98=EA=B2=BD=EB=B3=80?= =?UTF-8?q?=EC=88=98=20=EC=9E=90=EB=8F=99=EC=99=84=EC=84=B1=20=EC=9C=84?= =?UTF-8?q?=ED=95=B4=20`NodeJS`=20=EB=84=A4=EC=9E=84=EC=8A=A4=ED=94=84?= =?UTF-8?q?=EC=97=90=EC=8B=9C=EC=9D=98=20`ProcessEnv`=20=EC=9D=B8=ED=84=B0?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=8A=A4=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/types/apis/process.d.ts | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 client/src/types/apis/process.d.ts diff --git a/client/src/types/apis/process.d.ts b/client/src/types/apis/process.d.ts new file mode 100644 index 00000000..cac93912 --- /dev/null +++ b/client/src/types/apis/process.d.ts @@ -0,0 +1,6 @@ +declare namespace NodeJS { + interface ProcessEnv { + NODE_ENV?: string; + API_URL?: string; + } +} From 5c9d28b7c24a0b4fe54fbb4eff12d2ea29a8f1fc Mon Sep 17 00:00:00 2001 From: leegwae Date: Fri, 25 Nov 2022 19:00:13 +0900 Subject: [PATCH 101/121] =?UTF-8?q?feat:=20GET=20`/api/users`=20mock=20API?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EB=8C=80=EC=86=8C=EB=AC=B8=EC=9E=90=20?= =?UTF-8?q?=EC=83=81=EA=B4=80=EC=97=86=EC=9D=B4=20=ED=95=84=ED=84=B0?= =?UTF-8?q?=EB=A7=81=ED=95=9C=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EB=B0=98?= =?UTF-8?q?=ED=99=98=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/mocks/handlers/User.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/client/src/mocks/handlers/User.js b/client/src/mocks/handlers/User.js index c15929fc..358eae5e 100644 --- a/client/src/mocks/handlers/User.js +++ b/client/src/mocks/handlers/User.js @@ -4,7 +4,7 @@ import { rest } from 'msw'; import { users } from '../data/users'; const GetFilteredUsers = rest.get(`${API_URL}/api/users`, (req, res, ctx) => { - const search = req.url.searchParams.get('search'); + const search = req.url.searchParams.get('search').toUpperCase(); return res( ctx.delay(), @@ -13,7 +13,9 @@ const GetFilteredUsers = rest.get(`${API_URL}/api/users`, (req, res, ctx) => { statusCode: 200, result: { users: users.filter( - (user) => user.id.includes(search) || user.nickname.includes(search), + (user) => + user.id.toUpperCase().includes(search) || + user.nickname.toUpperCase().includes(search), ), }, }), From 07d9b7260fe1e683ae4c5297f8ab50de60db7b39 Mon Sep 17 00:00:00 2001 From: leegwae Date: Fri, 25 Nov 2022 19:00:58 +0900 Subject: [PATCH 102/121] =?UTF-8?q?refactor:=20=EC=9E=90=EC=8B=9D=20`li`?= =?UTF-8?q?=EC=9D=98=20hover=20css=EB=A5=BC=20=EB=B6=80=EB=AA=A8=20`ul`?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EB=8B=A4=EB=A3=A8=EB=8F=84=EB=A1=9D=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 --- client/src/components/UserList/index.tsx | 6 +++++- client/src/layouts/DmNav/index.tsx | 7 ++----- client/src/layouts/Followers/index.tsx | 4 +--- client/src/layouts/Followings/index.tsx | 4 +--- client/src/layouts/UserSearch/index.tsx | 4 +--- 5 files changed, 10 insertions(+), 15 deletions(-) diff --git a/client/src/components/UserList/index.tsx b/client/src/components/UserList/index.tsx index bb7f2e40..e9fa6eb7 100644 --- a/client/src/components/UserList/index.tsx +++ b/client/src/components/UserList/index.tsx @@ -7,7 +7,11 @@ interface Props extends ComponentPropsWithoutRef<'ul'> { } const UserList = ({ children }: Props) => { - return
      {children}
    ; + return ( +
      + {children} +
    + ); }; export default UserList; diff --git a/client/src/layouts/DmNav/index.tsx b/client/src/layouts/DmNav/index.tsx index 1a048bcb..7d4ba7f0 100644 --- a/client/src/layouts/DmNav/index.tsx +++ b/client/src/layouts/DmNav/index.tsx @@ -16,12 +16,9 @@ const DmNav = () => {
    loading...
    ) : ( directMessagesQuery.data?.length && ( -
      +
        {directMessagesQuery.data.map((directMessage) => ( -
      • +
      • diff --git a/client/src/layouts/Followers/index.tsx b/client/src/layouts/Followers/index.tsx index 0f784ee2..70fa6873 100644 --- a/client/src/layouts/Followers/index.tsx +++ b/client/src/layouts/Followers/index.tsx @@ -25,9 +25,7 @@ const Followers = () => { ) : followersQuery.data?.followers.length ? ( {followersQuery.data.followers.map((user) => ( -
      • - -
      • + ))} ) : ( diff --git a/client/src/layouts/Followings/index.tsx b/client/src/layouts/Followings/index.tsx index 4b5b0418..fe8d0388 100644 --- a/client/src/layouts/Followings/index.tsx +++ b/client/src/layouts/Followings/index.tsx @@ -25,9 +25,7 @@ const Followings = () => { ) : followingsQuery.data?.followings.length ? ( {followingsQuery.data.followings.map((user) => ( -
      • - -
      • + ))}
        ) : ( diff --git a/client/src/layouts/UserSearch/index.tsx b/client/src/layouts/UserSearch/index.tsx index 514df464..062565aa 100644 --- a/client/src/layouts/UserSearch/index.tsx +++ b/client/src/layouts/UserSearch/index.tsx @@ -42,9 +42,7 @@ const UserSearch = () => { {usersQuery.data?.users.length ? ( {usersQuery.data.users.map((user) => ( -
      • - -
      • + ))}
        ) : ( From 278845e65235be6d321538c21448480b0b80b4f6 Mon Sep 17 00:00:00 2001 From: leegwae Date: Fri, 25 Nov 2022 19:01:20 +0900 Subject: [PATCH 103/121] =?UTF-8?q?design:=20`UserItem`=20=ED=8C=A8?= =?UTF-8?q?=EB=94=A9=20top,=20bottom=20=EB=8D=94=20=ED=81=AC=EA=B2=8C=20?= =?UTF-8?q?=EC=A1=B0=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/UserItem/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/components/UserItem/index.tsx b/client/src/components/UserItem/index.tsx index 8a9604cb..ef86011e 100644 --- a/client/src/components/UserItem/index.tsx +++ b/client/src/components/UserItem/index.tsx @@ -11,7 +11,7 @@ interface Props extends ComponentPropsWithoutRef<'li'> { const UserItem: React.FC = ({ user, right }) => { return ( -
        +
        {right}
        From b45164f7d6a3fc886a7b581fe4dc9ac9e72a50d4 Mon Sep 17 00:00:00 2001 From: leegwae Date: Fri, 25 Nov 2022 19:21:32 +0900 Subject: [PATCH 104/121] =?UTF-8?q?fix:=20`UserItem`=EC=9D=84=20`li`?= =?UTF-8?q?=EB=A1=9C=20=EA=B0=90=EC=8B=B8=EC=A7=80=20=EC=95=8A=EA=B2=8C=20?= =?UTF-8?q?=EB=90=98=EC=97=88=EC=9C=BC=EB=AF=80=EB=A1=9C=20`div`=EC=97=90?= =?UTF-8?q?=EC=84=9C=20`li`=EB=A1=9C=20=EB=B3=80=EA=B2=BD=20#125?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/UserItem/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/components/UserItem/index.tsx b/client/src/components/UserItem/index.tsx index ef86011e..6d4d1d78 100644 --- a/client/src/components/UserItem/index.tsx +++ b/client/src/components/UserItem/index.tsx @@ -11,10 +11,10 @@ interface Props extends ComponentPropsWithoutRef<'li'> { const UserItem: React.FC = ({ user, right }) => { return ( -
        +
      • {right} -
      • + ); }; From 6b6bd742d3bd512ac889fd042042a83da37f8032 Mon Sep 17 00:00:00 2001 From: leegwae Date: Fri, 25 Nov 2022 19:42:27 +0900 Subject: [PATCH 105/121] =?UTF-8?q?refactor:=20=EB=9D=BC=EC=9A=B0=ED=8C=85?= =?UTF-8?q?=20=EB=AA=A9=EC=A0=81=EC=9C=BC=EB=A1=9C=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=ED=95=98=EB=8A=94=20`button`=EC=9D=84=20`Link`=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20#125?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/FollowingUserItem/index.tsx | 15 +++++---------- client/src/layouts/DmNav/index.tsx | 7 +++---- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/client/src/components/FollowingUserItem/index.tsx b/client/src/components/FollowingUserItem/index.tsx index b8056baf..37064358 100644 --- a/client/src/components/FollowingUserItem/index.tsx +++ b/client/src/components/FollowingUserItem/index.tsx @@ -6,34 +6,29 @@ import { ChatBubbleLeftIcon, } from '@heroicons/react/20/solid'; import useFollowingMutation from '@hooks/useFollowingMutation'; -import React, { memo } from 'react'; -import { useNavigate } from 'react-router-dom'; +import React from 'react'; +import { Link } from 'react-router-dom'; interface Props { user: User; } const FollowingUserItem: React.FC = ({ user }) => { - const navigate = useNavigate(); const followingMutation = useFollowingMutation(user._id); const { mutate: updateFollowing } = followingMutation; - const handleChatButtonClick = () => { - navigate(`/dms/${user._id}`); - }; - return ( - + + ))}
      From 35c2b96ecab37d67669465cfc46385935807a956 Mon Sep 17 00:00:00 2001 From: Cola Date: Thu, 24 Nov 2022 22:44:26 +0900 Subject: [PATCH 106/121] =?UTF-8?q?fix:=20Button=20outlined=20=EC=95=84?= =?UTF-8?q?=EB=8B=90=20=EB=95=8C=20border=20=EC=8A=A4=ED=83=80=EC=9D=BC=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 --- client/src/components/Button/index.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/src/components/Button/index.tsx b/client/src/components/Button/index.tsx index 115a0a4a..2c00cd1c 100644 --- a/client/src/components/Button/index.tsx +++ b/client/src/components/Button/index.tsx @@ -15,13 +15,13 @@ const buttonRounded = { const buttonBg = (outlined: boolean) => ({ primary: outlined ? 'border-primary hover:border-primary-dark active:border-primary' - : 'bg-primary hover:bg-primary-dark active:bg-primary', + : 'bg-primary hover:bg-primary-dark active:bg-primary border-primary', secondary: outlined ? 'border-secondary hover:border-secondary-dark active:border-secondary' - : 'bg-secondary hover:bg-secondary-dark active:bg-secondary', + : 'bg-secondary hover:bg-secondary-dark active:bg-secondary border-secondary', dark: outlined ? 'border-indigo hover:border-titleActive active:border-indigo' - : 'bg-indigo hover:bg-titleActive active:bg-indigo', + : 'bg-indigo hover:bg-titleActive active:bg-indigo border-indigo', }); const buttonText = (outlined: boolean) => ({ From a6cd60bf731fac82e045fbd8bc10976fbd0981ed Mon Sep 17 00:00:00 2001 From: Cola Date: Fri, 25 Nov 2022 00:19:06 +0900 Subject: [PATCH 107/121] =?UTF-8?q?chore:=20react-modal=20=ED=8C=A8?= =?UTF-8?q?=ED=82=A4=EC=A7=80=20=EC=84=A4=EC=B9=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/client/package.json b/client/package.json index 1594440c..073e0de5 100644 --- a/client/package.json +++ b/client/package.json @@ -18,6 +18,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-hook-form": "^7.39.4", + "react-modal": "^3.16.1", "react-router-dom": "^6.4.3", "react-toastify": "^9.1.1", "shared": "1.0.0", From 7e91573f668ea51389d62d0fba59718f717dd840 Mon Sep 17 00:00:00 2001 From: Cola Date: Fri, 25 Nov 2022 00:55:22 +0900 Subject: [PATCH 108/121] =?UTF-8?q?chore:=20=EB=A6=AC=ED=94=84=EB=A0=88?= =?UTF-8?q?=EC=8B=9C=20=ED=86=A0=ED=81=B0=20=EA=B4=80=EB=A0=A8=20=EC=9E=91?= =?UTF-8?q?=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 로그인 Mock API에서 리프레시 토큰 세팅하도록 변경 --- client/src/mocks/handlers/Auth.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/client/src/mocks/handlers/Auth.js b/client/src/mocks/handlers/Auth.js index 7bd2af94..b004573b 100644 --- a/client/src/mocks/handlers/Auth.js +++ b/client/src/mocks/handlers/Auth.js @@ -4,6 +4,9 @@ import { rest } from 'msw'; import { users } from '../data/users'; const BASE_URL = `${API_URL}/api`; +const devCookies = { + refreshTokenKey: 'dev_refreshToken', +}; // 회원가입 const SignUp = rest.post(`${BASE_URL}/user/auth/signup`, (req, res, ctx) => { @@ -41,6 +44,7 @@ const SignIn = rest.post(`${BASE_URL}/user/auth/signin`, (req, res, ctx) => { const ERROR = false; const successResponse = res( + ctx.cookie(devCookies.refreshTokenKey, '.'), ctx.status(200), ctx.delay(500), ctx.json({ @@ -70,7 +74,8 @@ const ReissueToken = rest.post( `${BASE_URL}/user/auth/refresh`, (req, res, ctx) => { // 응답 메세지 성공-실패를 토글하려면 이 값을 바꿔주세요. - const ERROR = true; + const existsRefreshToken = !!req.cookies[devCookies.refreshTokenKey]; + const ERROR = existsRefreshToken && true; const isUnknownError = true; const successResponse = res( From 46f244bb136615926108e1b8324961d9a921aa97 Mon Sep 17 00:00:00 2001 From: Cola Date: Fri, 25 Nov 2022 03:58:31 +0900 Subject: [PATCH 109/121] =?UTF-8?q?design:=20no-scrollbar=20css=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/index.css | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/client/src/index.css b/client/src/index.css index b39d69f7..5510c518 100644 --- a/client/src/index.css +++ b/client/src/index.css @@ -18,4 +18,13 @@ bottom: 0; left: 0; right: 0; -} \ No newline at end of file +} + +.no-display-scrollbar::-webkit-scrollbar { + display: none; +} + +.no-display-scrollbar { + -ms-overflow-style: none; + scrollbar-width: none; +} From ee0df87399aafae9c817794dcddc63e9cc3fe231 Mon Sep 17 00:00:00 2001 From: Cola Date: Fri, 25 Nov 2022 04:01:16 +0900 Subject: [PATCH 110/121] =?UTF-8?q?feat:=20Avatar=20=EC=97=85=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Props 추가, children props 추가 --- client/src/components/Avatar/index.tsx | 48 ++++++++++++++++++++------ 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/client/src/components/Avatar/index.tsx b/client/src/components/Avatar/index.tsx index ec55eb64..c339739d 100644 --- a/client/src/components/Avatar/index.tsx +++ b/client/src/components/Avatar/index.tsx @@ -1,3 +1,5 @@ +import type { ReactNode } from 'react'; + import React from 'react'; export interface AvatarProps { @@ -5,6 +7,8 @@ export interface AvatarProps { variant: 'circle' | 'rectangle'; name: string; url?: string; + className?: string; + children?: ReactNode; } const ROUNDED = { @@ -17,20 +21,42 @@ const SCALE = { medium: 'w-[65px] h-[65px]', }; -const Avatar: React.FC = ({ name, url, size, variant }) => { +const getFirstLetter = (str: string) => { + const firstLetter = str.at(0); + + if (!firstLetter) { + console.warn( + `getFirstLetter의 인자로는 반드시 길이 1이상의 문자열이 들어와야 합니다.`, + ); + return ''; + } + + return firstLetter; +}; + +const Avatar: React.FC = ({ + name, + url, + size, + variant, + className = '', + children, +}) => { return (
      - {url ? ( - {`${name}의 - ) : ( - name - )} + {children} + {!children && + (url ? ( + {`${name}의 + ) : ( + getFirstLetter(name) + ))}
      ); }; From b22a851163a5ba659fce4640b2184489ac0de3ee Mon Sep 17 00:00:00 2001 From: Cola Date: Fri, 25 Nov 2022 04:01:57 +0900 Subject: [PATCH 111/121] =?UTF-8?q?feat:=20GnbItemContainer=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/GnbItemContainer/index.tsx | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 client/src/components/GnbItemContainer/index.tsx diff --git a/client/src/components/GnbItemContainer/index.tsx b/client/src/components/GnbItemContainer/index.tsx new file mode 100644 index 00000000..2f49c3c0 --- /dev/null +++ b/client/src/components/GnbItemContainer/index.tsx @@ -0,0 +1,49 @@ +import type { ReactNode } from 'react'; + +import cn from 'classnames'; +import React, { useState, memo, useCallback } from 'react'; + +interface Props { + children: ReactNode; + disableLeftFillBar?: boolean; + isActive?: boolean; + tooltip?: string; +} + +// TODO: Tooltip 추가하기 +const GnbItemContainer: React.FC = ({ + children, + disableLeftFillBar = false, + isActive = false, +}) => { + const [isItemHover, setIsItemHover] = useState(false); + const leftFillBarClassnames = disableLeftFillBar + ? '' + : cn({ + 'bg-primary-light': isItemHover, + 'bg-primary-dark': isActive, + }); + + const handleMouseEnterOnItem = useCallback(() => setIsItemHover(true), []); + const handleMouseLeaveFromItem = useCallback(() => setIsItemHover(false), []); + + return ( +
      +
      +
      + {/* Item 영역 */} +
      + {children} +
      +
      +
      + ); +}; + +export default memo(GnbItemContainer); From 6db06855c04e946f8195f0ce2365f1b5a69936e5 Mon Sep 17 00:00:00 2001 From: Cola Date: Fri, 25 Nov 2022 04:02:40 +0900 Subject: [PATCH 112/121] =?UTF-8?q?feat:=20Gnb=20Item=20=EC=97=85=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/layouts/Gnb/index.tsx | 48 ++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/client/src/layouts/Gnb/index.tsx b/client/src/layouts/Gnb/index.tsx index 49f5e6b8..847b8700 100644 --- a/client/src/layouts/Gnb/index.tsx +++ b/client/src/layouts/Gnb/index.tsx @@ -1,9 +1,53 @@ +import Avatar from '@components/Avatar'; +import GnbItemContainer from '@components/GnbItemContainer'; +import { LOGO_IMG_URL } from '@constants/url'; +import { PlusIcon } from '@heroicons/react/24/solid'; import React from 'react'; +import { Link, useLocation } from 'react-router-dom'; const Gnb = () => { + const { pathname } = useLocation(); + return ( -
      - Gnb +
      +
      + + + + + + +
      + +
        + + + + + + + + + + +
      + + +
      ); }; From ded7bf21b4e42a7c11d08dc4d50bbf11f7d18f64 Mon Sep 17 00:00:00 2001 From: Cola Date: Fri, 25 Nov 2022 04:03:08 +0900 Subject: [PATCH 113/121] =?UTF-8?q?feat:=20=EB=A1=9C=EA=B3=A0=20=EC=9D=B4?= =?UTF-8?q?=EB=AF=B8=EC=A7=80=20URL=20=EC=83=81=EC=88=98=EC=97=90=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/constants/url.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/src/constants/url.ts b/client/src/constants/url.ts index dad72071..6d95906b 100644 --- a/client/src/constants/url.ts +++ b/client/src/constants/url.ts @@ -1,3 +1,5 @@ const _API_URL = process.env.API_URL as string; export const API_URL = _API_URL; +export const LOGO_IMG_URL = + 'https://user-images.githubusercontent.com/79135734/203833936-4621bc34-d43d-4fd7-975b-54ae469207b6.png'; From 899953a705e70aa0f984072bc9ad26354d196488 Mon Sep 17 00:00:00 2001 From: Cola Date: Fri, 25 Nov 2022 17:25:38 +0900 Subject: [PATCH 114/121] =?UTF-8?q?chore:=20react-custom-scrollbars-2=20?= =?UTF-8?q?=ED=8C=A8=ED=82=A4=EC=A7=80=20=EC=84=A4=EC=B9=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/package.json | 1 + yarn.lock | 90 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 89 insertions(+), 2 deletions(-) diff --git a/client/package.json b/client/package.json index 073e0de5..9a8a18f1 100644 --- a/client/package.json +++ b/client/package.json @@ -16,6 +16,7 @@ "axios": "^1.1.3", "classnames": "^2.3.2", "react": "^18.2.0", + "react-custom-scrollbars-2": "^4.5.0", "react-dom": "^18.2.0", "react-hook-form": "^7.39.4", "react-modal": "^3.16.1", diff --git a/yarn.lock b/yarn.lock index 3a9ca5ed..187fab05 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3679,6 +3679,11 @@ acorn@^8.0.4, acorn@^8.1.0, acorn@^8.4.1, acorn@^8.5.0, acorn@^8.7.1, acorn@^8.8 resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.1.tgz#0a3f9cbecc4ec3bea6f0a80b66ae8dd2da250b73" integrity sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA== +add-px-to-style@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/add-px-to-style/-/add-px-to-style-1.0.0.tgz#d0c135441fa8014a8137904531096f67f28f263a" + integrity sha512-YMyxSlXpPjD8uWekCQGuN40lV4bnZagUwqa2m/uFv1z/tNImSk9fnXVMUI5qwME/zzI3MMQRvjZ+69zyfSSyew== + agent-base@6: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" @@ -5162,6 +5167,15 @@ dom-converter@^0.2.0: dependencies: utila "~0.4" +dom-css@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/dom-css/-/dom-css-2.1.0.tgz#fdbc2d5a015d0a3e1872e11472bbd0e7b9e6a202" + integrity sha512-w9kU7FAbaSh3QKijL6n59ofAhkkmMJ31GclJIz/vyQdjogfyxcB6Zf8CZyibOERI5o0Hxz30VmJS7+7r5fEj2Q== + dependencies: + add-px-to-style "1.0.0" + prefix-style "2.0.1" + to-camel-case "1.0.0" + dom-serializer@^1.0.1: version "1.4.1" resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.4.1.tgz#de5d41b1aea290215dc45a6dae8adcf1d32e2d30" @@ -5813,6 +5827,11 @@ execa@^5.0.0: signal-exit "^3.0.3" strip-final-newline "^2.0.0" +exenv@^1.2.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d" + integrity sha512-Z+ktTxTwv9ILfgKCk32OX3n/doe+OcLTRtqK9pcL+JsP3J1/VW8Uvl4ZjLlKqeW4rzK4oesDOGMEMRIZqtP4Iw== + exit@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" @@ -8156,7 +8175,7 @@ logform@^2.3.2, logform@^2.4.0: safe-stable-stringify "^2.3.1" triple-beam "^1.3.0" -loose-envify@^1.1.0, loose-envify@^1.4.0: +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -9011,6 +9030,11 @@ pause@0.0.1: resolved "https://registry.yarnpkg.com/pause/-/pause-0.0.1.tgz#1d408b3fdb76923b9543d96fb4c9dfd535d9cb5d" integrity sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg== +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow== + picocolors@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" @@ -9335,6 +9359,11 @@ postcss@^8.4.17, postcss@^8.4.18, postcss@^8.4.19: picocolors "^1.0.0" source-map-js "^1.0.2" +prefix-style@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/prefix-style/-/prefix-style-2.0.1.tgz#66bba9a870cfda308a5dc20e85e9120932c95a06" + integrity sha512-gdr1MBNVT0drzTq95CbSNdsrBDoHGlb2aDJP/FoY+1e+jSDPOb1Cv554gH2MGiSr2WTcXi/zu+NaFzfcHQkfBQ== + prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" @@ -9411,7 +9440,7 @@ prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.5" -prop-types@^15.8.1: +prop-types@^15.5.10, prop-types@^15.7.2, prop-types@^15.8.1: version "15.8.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== @@ -9478,6 +9507,13 @@ quick-lru@^5.1.1: resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== +raf@^3.1.0: + version "3.4.1" + resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39" + integrity sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA== + dependencies: + performance-now "^2.1.0" + randombytes@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" @@ -9500,6 +9536,15 @@ raw-body@2.5.1: iconv-lite "0.4.24" unpipe "1.0.0" +react-custom-scrollbars-2@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/react-custom-scrollbars-2/-/react-custom-scrollbars-2-4.5.0.tgz#cff18e7368bce9d570aea0be780045eda392c745" + integrity sha512-/z0nWAeXfMDr4+OXReTpYd1Atq9kkn4oI3qxq3iMXGQx1EEfwETSqB8HTAvg1X7dEqcCachbny1DRNGlqX5bDQ== + dependencies: + dom-css "^2.0.0" + prop-types "^15.5.10" + raf "^3.1.0" + react-dom@^18.2.0: version "18.2.0" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d" @@ -9528,6 +9573,21 @@ react-is@^18.0.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== +react-lifecycles-compat@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" + integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== + +react-modal@^3.16.1: + version "3.16.1" + resolved "https://registry.yarnpkg.com/react-modal/-/react-modal-3.16.1.tgz#34018528fc206561b1a5467fc3beeaddafb39b2b" + integrity sha512-VStHgI3BVcGo7OXczvnJN7yT2TWHJPDXZWyI/a0ssFNhGZWsPmB8cF0z33ewDXq4VfYMO1vXgiv/g8Nj9NDyWg== + dependencies: + exenv "^1.2.0" + prop-types "^15.7.2" + react-lifecycles-compat "^3.0.0" + warning "^4.0.3" + react-refresh@^0.14.0: version "0.14.0" resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.0.tgz#4e02825378a5f227079554d4284889354e5f553e" @@ -10643,11 +10703,23 @@ tmpl@1.0.5: resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== +to-camel-case@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/to-camel-case/-/to-camel-case-1.0.0.tgz#1a56054b2f9d696298ce66a60897322b6f423e46" + integrity sha512-nD8pQi5H34kyu1QDMFjzEIYqk0xa9Alt6ZfrdEMuHCFOfTLhDG5pgTu/aAM9Wt9lXILwlXmWP43b8sav0GNE8Q== + dependencies: + to-space-case "^1.0.0" + to-fast-properties@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== +to-no-case@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/to-no-case/-/to-no-case-1.0.2.tgz#c722907164ef6b178132c8e69930212d1b4aa16a" + integrity sha512-Z3g735FxuZY8rodxV4gH7LxClE4H0hTIyHNIHdk+vpQxjLm0cwnKXq/OFVZ76SOQmto7txVcwSCwkU5kqp+FKg== + to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" @@ -10655,6 +10727,13 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" +to-space-case@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/to-space-case/-/to-space-case-1.0.0.tgz#b052daafb1b2b29dc770cea0163e5ec0ebc9fc17" + integrity sha512-rLdvwXZ39VOn1IxGL3V6ZstoTbwLRckQmn/U8ZDLuWwIXNpuZDhQ3AiRUlhTbOXFVE9C+dR51wM0CBDhk31VcA== + dependencies: + to-no-case "^1.0.0" + toidentifier@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" @@ -11016,6 +11095,13 @@ walker@^1.0.8: dependencies: makeerror "1.0.12" +warning@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3" + integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w== + dependencies: + loose-envify "^1.0.0" + watchpack@^2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d" From d44bd4a9664e5705efb054a7e8a497701e6bded6 Mon Sep 17 00:00:00 2001 From: Cola Date: Fri, 25 Nov 2022 17:36:55 +0900 Subject: [PATCH 115/121] =?UTF-8?q?feat:=20Following,=20Follower,=20UserSe?= =?UTF-8?q?arch=EC=97=90=20=EC=8A=A4=ED=81=AC=EB=A1=A4=EB=B0=94=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/layouts/Followers/index.tsx | 25 ++++++++++++++----------- client/src/layouts/Followings/index.tsx | 25 ++++++++++++++----------- client/src/layouts/UserSearch/index.tsx | 23 ++++++++++++++--------- 3 files changed, 42 insertions(+), 31 deletions(-) diff --git a/client/src/layouts/Followers/index.tsx b/client/src/layouts/Followers/index.tsx index 70fa6873..d00dd559 100644 --- a/client/src/layouts/Followers/index.tsx +++ b/client/src/layouts/Followers/index.tsx @@ -4,6 +4,7 @@ import UserList from '@components/UserList'; import useDebouncedValue from '@hooks/useDebouncedValue'; import useFollowersQuery from '@hooks/useFollowersQuery'; import React, { useState } from 'react'; +import Scrollbars from 'react-custom-scrollbars-2'; const Followers = () => { const DEBOUNCE_DELAY = 500; @@ -20,17 +21,19 @@ const Followers = () => { placeholder="검색하기" />
      - {followersQuery.isLoading ? ( -
      loading...
      - ) : followersQuery.data?.followers.length ? ( - - {followersQuery.data.followers.map((user) => ( - - ))} - - ) : ( - '일치하는 사용자가 없습니다.' - )} + + {followersQuery.isLoading ? ( +
      로딩중...
      + ) : followersQuery.data?.followers.length ? ( + + {followersQuery.data.followers.map((user) => ( + + ))} + + ) : ( + '일치하는 사용자가 없습니다.' + )} +
    ); }; diff --git a/client/src/layouts/Followings/index.tsx b/client/src/layouts/Followings/index.tsx index fe8d0388..645f0f94 100644 --- a/client/src/layouts/Followings/index.tsx +++ b/client/src/layouts/Followings/index.tsx @@ -4,6 +4,7 @@ import UserList from '@components/UserList'; import useDebouncedValue from '@hooks/useDebouncedValue'; import useFollowingsQuery from '@hooks/useFollowingsQuery'; import React, { useState } from 'react'; +import Scrollbars from 'react-custom-scrollbars-2'; const Followings = () => { const DEBOUNCE_DELAY = 500; @@ -20,17 +21,19 @@ const Followings = () => { placeholder="검색하기" />
    - {followingsQuery.isLoading ? ( -
    loading...
    - ) : followingsQuery.data?.followings.length ? ( - - {followingsQuery.data.followings.map((user) => ( - - ))} - - ) : ( - '일치하는 사용자가 없습니다.' - )} + + {followingsQuery.isLoading ? ( +
    로딩중...
    + ) : followingsQuery.data?.followings.length ? ( + + {followingsQuery.data.followings.map((user) => ( + + ))} + + ) : ( + '일치하는 사용자가 없습니다.' + )} +
    ); }; diff --git a/client/src/layouts/UserSearch/index.tsx b/client/src/layouts/UserSearch/index.tsx index 062565aa..e94d20dc 100644 --- a/client/src/layouts/UserSearch/index.tsx +++ b/client/src/layouts/UserSearch/index.tsx @@ -5,6 +5,7 @@ import SearchInput from '@components/SearchInput'; import UserList from '@components/UserList'; import useUsersQuery from '@hooks/useUsersQuery'; import React, { useState } from 'react'; +import Scrollbars from 'react-custom-scrollbars-2'; import Button from '@/components/Button'; @@ -39,15 +40,19 @@ const UserSearch = () => {
    - {usersQuery.data?.users.length ? ( - - {usersQuery.data.users.map((user) => ( - - ))} - - ) : ( -
    검색된 사용자가 없습니다
    - )} + + {usersQuery.data?.users.length ? ( + + {usersQuery.data.users.map((user) => ( + + ))} + + ) : ( +
    + 검색된 사용자가 없습니다 +
    + )} +
    ); }; From 9da2737dc37dc1fe1a009635314a0c347835e51e Mon Sep 17 00:00:00 2001 From: Cola Date: Fri, 25 Nov 2022 17:38:32 +0900 Subject: [PATCH 116/121] =?UTF-8?q?chore:=20ReissueToken=20Mock=20API=20?= =?UTF-8?q?=ED=95=A8=EC=88=98=20=EC=97=90=EB=9F=AC=20=EB=B0=9C=EC=83=9D=20?= =?UTF-8?q?=EC=A1=B0=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 --- client/src/mocks/handlers/Auth.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/client/src/mocks/handlers/Auth.js b/client/src/mocks/handlers/Auth.js index b004573b..b06b703b 100644 --- a/client/src/mocks/handlers/Auth.js +++ b/client/src/mocks/handlers/Auth.js @@ -75,7 +75,8 @@ const ReissueToken = rest.post( (req, res, ctx) => { // 응답 메세지 성공-실패를 토글하려면 이 값을 바꿔주세요. const existsRefreshToken = !!req.cookies[devCookies.refreshTokenKey]; - const ERROR = existsRefreshToken && true; + + const ERROR = !existsRefreshToken || false; const isUnknownError = true; const successResponse = res( @@ -121,7 +122,7 @@ export const GetMyInfo = rest.get( `${BASE_URL}/user/auth/me`, (req, res, ctx) => { return res( - ctx.delay(), + ctx.delay(300), ctx.status(200), ctx.json({ statusCode: 200, From c76ec0f2db5fc72ffa90014ecce344c362459170 Mon Sep 17 00:00:00 2001 From: Cola Date: Fri, 25 Nov 2022 19:35:17 +0900 Subject: [PATCH 117/121] =?UTF-8?q?chore:=20@types/react-modal=20=ED=8C=A8?= =?UTF-8?q?=ED=82=A4=EC=A7=80=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/package.json | 1 + yarn.lock | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/client/package.json b/client/package.json index 9a8a18f1..b22b0ec2 100644 --- a/client/package.json +++ b/client/package.json @@ -40,6 +40,7 @@ "@types/jest": "^29.2.2", "@types/react": "^18.0.25", "@types/react-dom": "^18.0.8", + "@types/react-modal": "^3.13.1", "@types/webpack-bundle-analyzer": "^4.6.0", "@typescript-eslint/eslint-plugin": "^5.42.1", "@typescript-eslint/parser": "^5.42.1", diff --git a/yarn.lock b/yarn.lock index 187fab05..ad0153df 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3228,6 +3228,13 @@ dependencies: "@types/react" "*" +"@types/react-modal@^3.13.1": + version "3.13.1" + resolved "https://registry.yarnpkg.com/@types/react-modal/-/react-modal-3.13.1.tgz#5b9845c205fccc85d9a77966b6e16dc70a60825a" + integrity sha512-iY/gPvTDIy6Z+37l+ibmrY+GTV4KQTHcCyR5FIytm182RQS69G5ps4PH2FxtC7bAQ2QRHXMevsBgck7IQruHNg== + dependencies: + "@types/react" "*" + "@types/react@*", "@types/react@^18.0.25": version "18.0.25" resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.25.tgz#8b1dcd7e56fe7315535a4af25435e0bb55c8ae44" From 601cef99bb97afaa5307917ab3a220f17aff9893 Mon Sep 17 00:00:00 2001 From: Cola Date: Fri, 25 Nov 2022 19:35:38 +0900 Subject: [PATCH 118/121] =?UTF-8?q?chore:=20no-empty-interface=EB=A3=B0=20?= =?UTF-8?q?off?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/.eslintrc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/.eslintrc b/client/.eslintrc index a4598dee..6048da0b 100644 --- a/client/.eslintrc +++ b/client/.eslintrc @@ -29,6 +29,7 @@ "no-duplicate-imports": "off", "@typescript-eslint/no-empty-function": "off", "@typescript-eslint/consistent-type-imports": "error", - "no-nested-ternary": "off" + "no-nested-ternary": "off", + "@typescript-eslint/no-empty-interface": "off" } } From bfeda326c570b82f2baf9e3adf44010a0e85590f Mon Sep 17 00:00:00 2001 From: Cola Date: Fri, 25 Nov 2022 19:48:24 +0900 Subject: [PATCH 119/121] =?UTF-8?q?feat:=20ModalSlice=20=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/stores/modalSlice.ts | 15 +++++++++++++++ client/src/stores/rootStore.ts | 14 ++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 client/src/stores/modalSlice.ts create mode 100644 client/src/stores/rootStore.ts diff --git a/client/src/stores/modalSlice.ts b/client/src/stores/modalSlice.ts new file mode 100644 index 00000000..4fca1f10 --- /dev/null +++ b/client/src/stores/modalSlice.ts @@ -0,0 +1,15 @@ +import type { StateCreator } from 'zustand'; + +export interface ModalSlice { + createCommunityModal: { + open: boolean; + }; +} + +export const createModalSlice: StateCreator = ( + set, +) => ({ + createCommunityModal: { + open: false, + }, +}); diff --git a/client/src/stores/rootStore.ts b/client/src/stores/rootStore.ts new file mode 100644 index 00000000..f4421b24 --- /dev/null +++ b/client/src/stores/rootStore.ts @@ -0,0 +1,14 @@ +import type { ModalSlice } from '@stores/modalSlice'; + +import store from 'zustand'; +import { devtools } from 'zustand/middleware'; + +import { createModalSlice } from './modalSlice'; + +export type Store = ModalSlice; + +export const useStore = store()( + devtools((...a) => ({ + ...createModalSlice(...a), + })), +); From 8502e4cac87804e13d7788961fedcd106fa565cc Mon Sep 17 00:00:00 2001 From: Cola Date: Fri, 25 Nov 2022 19:48:48 +0900 Subject: [PATCH 120/121] =?UTF-8?q?feat:=20CreateCommunityModal=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 아직 세부적인 구현은 X --- .../components/Modals/CreateCommunityModal/index.tsx | 10 ++++++++++ client/src/pages/Home/index.tsx | 2 ++ 2 files changed, 12 insertions(+) create mode 100644 client/src/components/Modals/CreateCommunityModal/index.tsx diff --git a/client/src/components/Modals/CreateCommunityModal/index.tsx b/client/src/components/Modals/CreateCommunityModal/index.tsx new file mode 100644 index 00000000..75daa3d7 --- /dev/null +++ b/client/src/components/Modals/CreateCommunityModal/index.tsx @@ -0,0 +1,10 @@ +import React from 'react'; +import ReactModal from 'react-modal'; + +interface Props {} + +const CreateCommunityModal: React.FC = () => { + return 커뮤니티 모달; +}; + +export default CreateCommunityModal; diff --git a/client/src/pages/Home/index.tsx b/client/src/pages/Home/index.tsx index 6e7bdc60..aeb911e0 100644 --- a/client/src/pages/Home/index.tsx +++ b/client/src/pages/Home/index.tsx @@ -1,3 +1,4 @@ +import CreateCommunityModal from '@components/Modals/CreateCommunityModal'; import Gnb from '@layouts/Gnb'; import Sidebar from '@layouts/Sidebar'; import React from 'react'; @@ -9,6 +10,7 @@ const Home = () => { + ); }; From 7331618c902275534d465a5f28579390454d7f4d Mon Sep 17 00:00:00 2001 From: Cola Date: Fri, 25 Nov 2022 20:13:18 +0900 Subject: [PATCH 121/121] =?UTF-8?q?fix:=20import=20memo=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/FollowingUserItem/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/components/FollowingUserItem/index.tsx b/client/src/components/FollowingUserItem/index.tsx index 37064358..038f8459 100644 --- a/client/src/components/FollowingUserItem/index.tsx +++ b/client/src/components/FollowingUserItem/index.tsx @@ -6,7 +6,7 @@ import { ChatBubbleLeftIcon, } from '@heroicons/react/20/solid'; import useFollowingMutation from '@hooks/useFollowingMutation'; -import React from 'react'; +import React, { memo } from 'react'; import { Link } from 'react-router-dom'; interface Props {