Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feat] 마이페이지 - 기본 페이지 구현 #81

Merged
merged 34 commits into from
Jun 17, 2024
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
438e27f
Feat: page 레이아웃 구성
bokeeeey Jun 12, 2024
2117d0f
Feat: userProfile 컴포넌트 추가
bokeeeey Jun 12, 2024
c693aca
Feat: my-info page => barrel import export 적용
bokeeeey Jun 13, 2024
7fd54e6
Feat: EdiProfile Modal => Form 기본 틀 작성
bokeeeey Jun 13, 2024
26d6123
Feat: nickname 중복확인 구현
bokeeeey Jun 13, 2024
4346f66
Feat: phone value값 편집
bokeeeey Jun 13, 2024
8d418aa
Feat: PutEditProfile mutate 구현
bokeeeey Jun 13, 2024
3f6e6cc
Merge: develop pull & merge
bokeeeey Jun 13, 2024
814c729
Fix: env 파일 삭제
bokeeeey Jun 14, 2024
f409b57
Fix: env 파일 삭제
bokeeeey Jun 14, 2024
279523b
Fix: 필요없는 주석 제거
bokeeeey Jun 14, 2024
dc4effa
Fix: RecentProduct text => children으로 수정
bokeeeey Jun 14, 2024
1ad7aae
Fix: fontSize Mixin 수정
bokeeeey Jun 14, 2024
500e2e7
Fix: radio 관련 버그 발견 => 잠시 주석처리
bokeeeey Jun 14, 2024
0c304dd
Fix: API호출 console 제거
bokeeeey Jun 14, 2024
9548fe8
Refactor: Dropdown => hover borderRadius수정
bokeeeey Jun 14, 2024
f0c96f1
Fix: Dropdown 컴포넌트 디버깅중
bokeeeey Jun 14, 2024
d57eb8d
Fix: Dropdown 컴포넌트 디버깅중
bokeeeey Jun 14, 2024
42b0986
Fix: dropdown에서 onChange 사용 추가
bokeeeey Jun 14, 2024
5c23f2f
Fix: Dropdown useEffect 제거
bokeeeey Jun 14, 2024
1e87fbd
Fix: radioField 수정: onChange => onClick
bokeeeey Jun 14, 2024
dfa233d
Fix: console.log 주석처리
bokeeeey Jun 14, 2024
da3697b
Fix: Input컴포넌트 props 수정
bokeeeey Jun 14, 2024
be867c1
Merge: devalop pull & merge
bokeeeey Jun 15, 2024
3e8dfba
Fix: API env 수정 및 api base_url 수정
bokeeeey Jun 17, 2024
620b8cf
Feat: token값의 변경이 있을때마다 쿼리 갱신 설정
bokeeeey Jun 17, 2024
472c13c
Fix: phone number fommetter 수정
bokeeeey Jun 17, 2024
d512fb9
Feat: refreshToken api함수 추가
bokeeeey Jun 17, 2024
76ea46a
Feat: toasity 설치
bokeeeey Jun 17, 2024
7e2a7f8
Fix: header css수정중
bokeeeey Jun 17, 2024
282550b
Merge: develop pull & merge
bokeeeey Jun 17, 2024
de44d2e
Fix: header css 수정
bokeeeey Jun 17, 2024
cb15f77
Feat: Add my-page redirecting
bokeeeey Jun 17, 2024
90b8798
Style: header border botton 추가
bokeeeey Jun 17, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ yarn-error.log*

# local env files
.env*.local
.env*

# vercel
.vercel
Expand Down
4 changes: 4 additions & 0 deletions next.config.mjs
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

환경 변수 config에 등록 안해도 되지 않나요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저도 안올라갈줄 알았는데 이전 커밋 확인해보시면 올라가더라구요
.local붙혀서 수정하긴 했는데 보험차원에서 작성했읍니다

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

env에 이름을 NEXT_PUBLIC_KEYDEUK_API_BASE_URL라고 등록하면 여기엔 안써도 되는 것 같습니다??

Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
const nextConfig = {
reactStrictMode: true,

env: {
NEXT_PUBLIC_KEYDEUK_API_BASE_URL: process.env.NEXT_PUBLIC_KEYDEUK_API_BASE_URL,
},

images: {
remotePatterns: [
{
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions public/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { default as AlertIcon } from './svgs/alertIcon.svg';
export { default as ChevronIcon } from './svgs/chevron.svg';
export { default as EyeOffIcon } from './svgs/eyeOff.svg';
export { default as EyeOnIcon } from './svgs/eyeOn.svg';
Expand Down
3 changes: 3 additions & 0 deletions public/svgs/alertIcon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
84 changes: 84 additions & 0 deletions src/api/profileAPI.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { FieldValues } from 'react-hook-form';

const BASE_URL = process.env.NEXT_PUBLIC_KEYDEUK_API_BASE_URL;

interface PutEditProfileProps {
payload: FieldValues;
token: string | null;
}

/**
* 주어진 토큰을 사용하여 사용자 데이터를 호출
*
* @param {string} token - 인증 토큰입니다.
* @returns {Promise<Object>} - 사용자 데이터를 반환합니다.
* @throws {Error} - 요청이 실패한 경우 에러를 던집니다.
*/
export async function getUserData(token: string | null) {
if (!token) {
return null;
}

try {
const res = await fetch(`${BASE_URL}/api/v1/users/me`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`,
},
});

const data = await res.json();
return data;
} catch (error) {
throw error;
}
}

/**
* 주어진 payload로 사용자 프로필을 업데이트
*
* @param {FieldValues} payload - 사용자 프로필을 업데이트할 데이터입니다.
* @returns {Promise<Object>} - 응답 데이터를 반환합니다.
* @throws {Error} - 요청이 실패한 경우 에러를 던집니다.
*/
export async function putEditProfile({ payload, token }: PutEditProfileProps) {
try {
const res = await fetch(`${BASE_URL}/api/v1/users/me`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`,
},
body: JSON.stringify(payload),
});

const result = await res.json();
return result;
} catch (error) {
throw error;
}
}

/**
* 주어진 닉네임이 사용 가능한지 확인
*
* @param {string} nickname - 확인할 닉네임입니다.
* @returns {Promise<Object>} - 닉네임이 사용 가능한지 여부를 나타내는 응답 데이터를 반환합니다.
* @throws {Error} - 요청이 실패한 경우 에러를 던집니다.
*/
export async function checkNickname(nickname: string) {
try {
const res = await fetch(`${BASE_URL}/api/v1/users/check/nickname?nickname=${nickname}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
});

const result = await res.json();
return result;
} catch (error) {
throw error;
}
}
80 changes: 2 additions & 78 deletions src/app/(test)/bk/page.tsx
Original file line number Diff line number Diff line change
@@ -1,83 +1,7 @@
'use client';

import { InputField } from '@/components';
import Dropdown from '@/components/Dropdown/Dropdown';
import classNames from 'classnames/bind';
import { FormEvent } from 'react';

import Breadcrumb from '@/components/Breadcrumb/Breadcrumb';
import styles from './page.module.scss';

const cn = classNames.bind(styles);

const OPTIONS = ['인기순', '조회순', '최신순', '가격 낮은순', '가격 높은순', '직접 입력'];
import EditProfileModal from '@/app/my-info/_components/UserProfile/EditProfileModal/EditProfileModal';

export default function Page() {
const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();

// const formData = new FormData(e.currentTarget);
// const payload = Object.fromEntries(formData.entries());
// console.log(payload);
};

// const handleClick = (e: MouseEvent<HTMLInputElement>) => {
// console.log('onClick', true, e.currentTarget.value);
// };
const handleClick = () => {};

return (
<form onSubmit={handleSubmit}>
<InputField
label='비밀번호'
id='이메일'
name='인풋'
type='password'
placeholder='이메일을 입력해 주세요'
suffixIcon='eye'
sizeVariant='md'
/>
<br />
<br />
<br />
<br />
<br />
<br />
<div style={{ width: '600px' }}>
<Dropdown
options={OPTIONS}
name='드롭다운'
sizeVariant='md'
placeholder='fdsa'
onClick={handleClick}
className={cn('dropdown')}
/>
</div>
<br />
<br />
<br />
<br />
<br />
<br />
{/* <TextField label='텍스트필드' id='텍스트' name='텍스트' placeholder='최소 20자 이상 입력해 주세요' /> */}
<br />
<br />
<br />
<br />
<br />
<br />
{/* <RadioField options={OPTIONS} label='숫자' value='6' /> */}
{/* <ItemOverview /> */}
<Breadcrumb />
<br />
<br />
<br />
<br />
<br />
<br />
<button style={{ border: '1px solid', width: '100%', height: '10vh', textAlign: 'center' }} type='submit'>
테스트
</button>
</form>
);
return <EditProfileModal />;
}
13 changes: 9 additions & 4 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { Header } from '@/components';
import { HydrationBoundary, QueryClient, dehydrate } from '@tanstack/react-query';
import type { Metadata } from 'next';
import { cookies } from 'next/headers';
import { ReactNode } from 'react';

import { getUserData } from '@/api/profileAPI';
import { Header } from '@/components';
import { Providers } from './providers';

import '@/styles/reset.css';
Expand All @@ -18,9 +21,11 @@ export default async function RootLayout({
}>) {
const queryClient = new QueryClient();

// 유저 data api 호출
// const Token = cookies().get('accessToken')?.value ?? null;
// await queryClient.prefetchQuery({ queryKey: ['userData'], queryFn: () => getUserData(Token), });
const token = cookies().get('accessToken')?.value || null;

if (token) {
await queryClient.prefetchQuery({ queryKey: ['userData'], queryFn: () => getUserData(token) });
}

return (
<html lang='ko'>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// init
26 changes: 26 additions & 0 deletions src/app/my-info/_components/DeliveryStatus/DeliveryStatus.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import classNames from 'classnames/bind';
import styles from './DeliveryStatus.module.scss';

const cn = classNames.bind(styles);

const DELIVERY_STATUS_LIST = [
{ label: '주문접수', count: 1 },
{ label: '결제완료', count: 0 },
{ label: '배송준비중', count: 0 },
{ label: '배송중', count: 0 },
{ label: '배송완료', count: 0 },
];

export default function DeliveryStatus() {
return (
<ul className={cn('status-list')}>
{DELIVERY_STATUS_LIST.map((status, i) => (
<li key={status.label} className={cn('status-item')}>
<span className={cn('status-count', { active: status.count > 0 })}>{status.count}</span>
<span className={cn('status-label', { active: status.count > 0 })}>{status.label}</span>
{i < DELIVERY_STATUS_LIST.length - 1 && <span className={cn('separator')}>&gt;</span>}
</li>
))}
</ul>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
.empty-case {
flex-direction: column;
width: 100%;
gap: 2.4rem;
padding: 8rem 3.2rem;
border-radius: 0.8rem;
@include flex-center;

.empty-case-text {
color: $gray-40;
@include pretendard-20-600;
}

.empty-case-button {
width: 12.8rem;
height: 4rem;
@include pretendard-16-500;
}
}

.background-color {
background-color: $gray-10;
}
32 changes: 32 additions & 0 deletions src/app/my-info/_components/MyInfoEmptyCase/MyInfoEmptyCase.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Button } from '@/components';
import { ROUTER } from '@/constants/route';
import { AlertIcon } from '@/public/index';
import classNames from 'classnames/bind';
import Link from 'next/link';
import styles from './MyInfoEmptyCase.module.scss';

const cn = classNames.bind(styles);

interface MyInfoEmptyCaseProps {
children: string;
isBackgroundColor?: boolean;
}

export default function MyInfoEmptyCase({ children, isBackgroundColor }: MyInfoEmptyCaseProps) {
return (
<div className={cn('empty-case', { 'background-color': isBackgroundColor })}>
<AlertIcon />
<p className={cn('empty-case-text')}>{children}</p>
<Button
as={Link}
href={ROUTER.SHOP.ALL}
backgroundColor='background-gray-40'
className={cn('empty-case-button')}
paddingVertical={8}
radius={4}
>
키득 둘러보기
</Button>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.recent {
@include flex-column(4rem);

.recent-title {
color: $black;
@include pretendard-20-600;
}
}
14 changes: 14 additions & 0 deletions src/app/my-info/_components/RecentProducts/RecentProducts.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import classNames from 'classnames/bind';
import MyInfoEmptyCase from '../MyInfoEmptyCase/MyInfoEmptyCase';
import styles from './RecentProducts.module.scss';

const cn = classNames.bind(styles);

export default function RecentProducts() {
return (
<article className={cn('recent')}>
<h1 className={cn('recent-title')}>최근 본 상품</h1>
<MyInfoEmptyCase isBackgroundColor>최근 본 상품이 없습니다</MyInfoEmptyCase>
</article>
);
}
29 changes: 23 additions & 6 deletions src/app/my-info/_components/SNB/SNB.module.scss
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
.snb {
@include flex-column(4rem);

position: absolute;
top: 18.6rem;
left: 12rem;
width: 20rem;

.snb-main {
@include pretendard-30-700;

margin-bottom: 2rem;
}

.snb-sections {
@include flex-column(1.6rem);

color: $black;

&.snb-section-1 {
@include pretendard-30-700;

margin-bottom: 0.4rem;
}

.snb-category {
@include pretendard-20-700;
}
Expand All @@ -23,6 +28,18 @@
@include pretendard-18-400;

color: $gray-50;

/* stylelint-disable-next-line max-nesting-depth */
&:focus {
@include pretendard-18-700;

color: $primary;
}

/* stylelint-disable-next-line max-nesting-depth */
&:hover {
color: $primary-60;
}
}
}
}
Expand Down
Loading