Skip to content

Commit d2d7cef

Browse files
authored
Merge pull request #266 from asksa1256/refactor/keyboards-etc
Refactor: 마이프로필 페이지
2 parents 3c5d2c3 + ffa8a75 commit d2d7cef

File tree

7 files changed

+90
-99
lines changed

7 files changed

+90
-99
lines changed

src/app/(global)/myprofile/page.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
1-
import Myprofile from '@/components/feature/myProfile/Myprofile';
1+
import MyprofileMain from '@/components/feature/myProfile/MyprofileMain';
2+
import MyprofileSidebar from '@/components/feature/myProfile/MyprofileSidebar';
23

34
const Page = () => {
4-
return <Myprofile />;
5+
return (
6+
<div className='flex flex-col gap-[30px] px-4 py-5 m-auto max-w-[1140px] md:gap-10 md:px-5 md:pt-4 md:pb-5 lg:flex-row lg:gap-15 lg:px-0 lg:py-[37px] lg:items-start'>
7+
<MyprofileSidebar />
8+
<MyprofileMain />
9+
</div>
10+
);
511
};
612

713
export default Page;

src/components/feature/Keyboards/KeyboardsList.tsx

Lines changed: 0 additions & 12 deletions
This file was deleted.

src/components/feature/myProfile/MyKeyboardArea.tsx

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use client';
22

33
import { AxiosError } from 'axios';
4-
import { useEffect, useState } from 'react';
4+
import { useEffect, useRef, useState } from 'react';
55

66
import KeyboardForm, { KeyboardFormValues } from '@/components/feature/Form/KeyboardForm';
77
import Modal from '@/components/feature/Modal';
@@ -31,20 +31,30 @@ const MyKeyboardArea = () => {
3131
const [keyboardList, setKeyboardList] = useState<MyKeyboardItemType[] | null>(null);
3232
const [totalCount, setTotalCount] = useState<number>(0);
3333
const [cursor, setCursor] = useState<number | null>(0);
34+
const [isLoading, setIsLoading] = useState(false);
35+
36+
const groupRef = useRef<number>(0);
37+
3438
const isListEmpty = keyboardList?.length === 0;
3539

3640
const getKeyboardList = async () => {
3741
if (cursor === null) return;
42+
if (isLoading) return;
3843

44+
console.log('loading');
3945
try {
46+
setIsLoading(true);
4047
const data = await fetchKeyboardList(cursor);
4148
const { list, nextCursor, totalCount } = data;
4249

4350
setKeyboardList((prev) => (prev === null ? list : [...prev, ...list]));
4451
setTotalCount(totalCount);
4552
setCursor(nextCursor);
53+
groupRef.current++;
4654
} catch (error) {
4755
console.error(error);
56+
} finally {
57+
setIsLoading(false);
4858
}
4959
};
5060

@@ -128,12 +138,18 @@ const MyKeyboardArea = () => {
128138
price: +formData.price,
129139
type: formData.type ?? KEYBOARD_TYPES_MAP[0].type,
130140
};
141+
131142
// 키보드 등록 api
132143
try {
133144
const res = await apiClient.post(`/${TEAM}/wines`, payload);
134145
const data = res?.data;
135146

136-
setKeyboardList((prev) => (prev === null ? [data] : [...prev, data]));
147+
setKeyboardList((prev) => {
148+
if (prev === null) return [data];
149+
if (prev.length >= DEFAULT_LIMIT * groupRef.current) return prev;
150+
// 현재 렌더링 된 키보드리스트 개수가 LIMIT * 무한스크롤API요청횟수(LIMIT 10 * CURRENT 1) 초과시 키보드리스트에 추가하지 않음. -> 무한 스크롤을 완료하면 가장 마지막에 나오므로
151+
return [...prev, data];
152+
});
137153
setTotalCount((totalCount) => totalCount + 1);
138154
handleKeyboardModalClose();
139155
addToast({ message: '키보드 등록 성공', type: 'success', duration: 2000 });
@@ -149,6 +165,8 @@ const MyKeyboardArea = () => {
149165
// 데이터 로딩시
150166
if (keyboardList === null) return <MyListLoading />;
151167

168+
console.log(groupRef.current);
169+
152170
return (
153171
<>
154172
<span className='absolute bottom-[calc(100%+16px)] right-0 text-xs text-primary leading-[26px] md:text-md md:leading-[32px] md:bottom-[calc(100%+22px)]'>

src/components/feature/myProfile/MyProfileContents.tsx

Lines changed: 0 additions & 13 deletions
This file was deleted.

src/components/feature/myProfile/MyReviewArea.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,16 @@ const MyReviewArea = () => {
2828
const [reviewList, setReviewList] = useState<MyReviewItemType[] | null>(null);
2929
const [cursor, setCursor] = useState<number | null>(0);
3030
const [totalCount, setTotalCount] = useState<number>(0);
31+
const [isLoading, setIsLoading] = useState(false);
3132
const isListEmpty = reviewList?.length === 0;
3233

3334
const getReviewList = async () => {
3435
if (cursor === null) return;
36+
if (isLoading) return;
3537

3638
try {
39+
setIsLoading(true);
40+
3741
const data = await fetchReviewList(cursor);
3842
const { list, nextCursor, totalCount } = data;
3943

@@ -42,6 +46,8 @@ const MyReviewArea = () => {
4246
setCursor(nextCursor);
4347
} catch (error) {
4448
console.error(error);
49+
} finally {
50+
setIsLoading(false);
4551
}
4652
};
4753

src/components/feature/myProfile/Myprofile.tsx

Lines changed: 0 additions & 19 deletions
This file was deleted.

src/components/feature/myProfile/MyprofileSidebar.tsx

Lines changed: 56 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { ChangeEvent, FocusEvent, useRef, useState } from 'react';
66
import { useShallow } from 'zustand/shallow';
77

88
import CameraIcon from '@/assets/icons/CameraIcon.svg';
9+
import MyListLoading from '@/components/feature/myProfile/MyListLoading';
910
import ButtonDefault from '@/components/ui/ButtonDefault';
1011
import UserThumbnail from '@/components/ui/UserThumbnail';
1112
import { DEFAULT_PROFILE_IMG_URL } from '@/constants';
@@ -104,60 +105,64 @@ const MyprofileSidebar = () => {
104105
setIsSameNickname(isSame);
105106
};
106107

107-
if (!user) return null;
108-
109108
return (
110109
<article className='p-5 border border-gray-300 bg-white rounded-2xl shadow-[0_2px_20px_rgba(0,0,0,0.04)] md:px-10 md:pt-[23px] md:pb-[30px] lg:w-[280px] lg:shrink-0 lg:px-5 lg:py-[39px]'>
111-
<div className='flex items-center gap-4 md:items-start md:gap-8 lg:flex-col lg:items-center'>
112-
<div className='relative'>
113-
<UserThumbnail
114-
imgSrc={user.image}
115-
userName={user.nickname}
116-
className='md:w-20 lg:w-[164px]'
117-
/>
118-
<input
119-
type='file'
120-
name='imgFileUpload'
121-
id='imgFileUpload'
122-
accept='image/*'
123-
className='hidden'
124-
onChange={handleUploadImage}
125-
ref={fileRef}
126-
/>
127-
<label
128-
htmlFor='imgFileUpload'
129-
className='absolute top-[65%] left-[65%] w-[40%] p-1 flex items-center justify-center bg-primary rounded-full cursor-pointer lg:top-0 lg:left-0 lg:w-full lg:h-full lg:bg-primary/30 lg:opacity-0 lg:hover:opacity-100 lg:transition-opacity'
130-
>
131-
<CameraIcon className='text-white w-[100%] h-[100%] lg:w-10 lg:h-10' />
132-
</label>
133-
{isUploading && (
134-
<div className='absolute top-0 left-0 w-full h-full flex items-center justify-center'>
135-
<div className=' w-8 h-8 border-4 mb-4 border-gray-300 border-t-primary rounded-full animate-spin' />
110+
{!user ? (
111+
<MyListLoading />
112+
) : (
113+
<>
114+
<div className='flex items-center gap-4 md:items-start md:gap-8 lg:flex-col lg:items-center'>
115+
<div className='relative'>
116+
<UserThumbnail
117+
imgSrc={user.image}
118+
userName={user.nickname}
119+
className='md:w-20 lg:w-[164px]'
120+
/>
121+
<input
122+
type='file'
123+
name='imgFileUpload'
124+
id='imgFileUpload'
125+
accept='image/*'
126+
className='hidden'
127+
onChange={handleUploadImage}
128+
ref={fileRef}
129+
/>
130+
<label
131+
htmlFor='imgFileUpload'
132+
className='absolute top-[65%] left-[65%] w-[40%] p-1 flex items-center justify-center bg-primary rounded-full cursor-pointer lg:top-0 lg:left-0 lg:w-full lg:h-full lg:bg-primary/30 lg:opacity-0 lg:hover:opacity-100 lg:transition-opacity'
133+
>
134+
<CameraIcon className='text-white w-[100%] h-[100%] lg:w-10 lg:h-10' />
135+
</label>
136+
{isUploading && (
137+
<div className='absolute top-0 left-0 w-full h-full flex items-center justify-center'>
138+
<div className=' w-8 h-8 border-4 mb-4 border-gray-300 border-t-primary rounded-full animate-spin' />
139+
</div>
140+
)}
136141
</div>
137-
)}
138-
</div>
139-
<span className='grow text-xl font-bold md:pt-[7px] md:text-2xl lg:pt-0 lg:min-h-[74px] lg:text-center'>
140-
{user.nickname}
141-
</span>
142-
</div>
143-
<div className='mt-5 md:flex md:flex-wrap md:mt-[30px] lg:mt-[48px]'>
144-
<span className='block mb-2 text-md font-medium md:w-full md:mb-[10px] md:shrink md:text-base'>
145-
닉네임
146-
</span>
147-
<Input
148-
placeholder={user.nickname}
149-
className='input h-[42px] py-[9px] mb-1.5 border-gray-300 shadow-none md:grow md:shrink md:basis-0 md:h-[48px] md:py-[11px] md:mb-0 md:mr-6 lg:grow-0 lg:shrink-0 lg:basis-full lg:mr-0 lg:mb-2'
150-
ref={nicknameRef}
151-
onBlur={checkSameNickname}
152-
/>
153-
<ButtonDefault
154-
onClick={handleUpdateNickname}
155-
disabled={isSameNickname}
156-
className='w-[89px] h-[42px] py-0 px-0 ml-auto text-md font-bold rounded-xl md:w-[116px] md:h-[48px] md:text-base lg:w-[96px] lg:h-[42px]'
157-
>
158-
변경하기
159-
</ButtonDefault>
160-
</div>
142+
<span className='grow text-xl font-bold md:pt-[7px] md:text-2xl lg:pt-0 lg:min-h-[74px] lg:text-center'>
143+
{user.nickname}
144+
</span>
145+
</div>
146+
<div className='mt-5 md:flex md:flex-wrap md:mt-[30px] lg:mt-[48px]'>
147+
<span className='block mb-2 text-md font-medium md:w-full md:mb-[10px] md:shrink md:text-base'>
148+
닉네임
149+
</span>
150+
<Input
151+
placeholder={user.nickname}
152+
className='input h-[42px] py-[9px] mb-1.5 border-gray-300 shadow-none md:grow md:shrink md:basis-0 md:h-[48px] md:py-[11px] md:mb-0 md:mr-6 lg:grow-0 lg:shrink-0 lg:basis-full lg:mr-0 lg:mb-2'
153+
ref={nicknameRef}
154+
onBlur={checkSameNickname}
155+
/>
156+
<ButtonDefault
157+
onClick={handleUpdateNickname}
158+
disabled={isSameNickname}
159+
className='w-[89px] h-[42px] py-0 px-0 ml-auto text-md font-bold rounded-xl md:w-[116px] md:h-[48px] md:text-base lg:w-[96px] lg:h-[42px]'
160+
>
161+
변경하기
162+
</ButtonDefault>
163+
</div>
164+
</>
165+
)}
161166
</article>
162167
);
163168
};

0 commit comments

Comments
 (0)