Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
c85a17b
feat: Tag 삭제하는 로직 만들기
Jun 24, 2023
08112fb
feat: Asset 수정 페이지
Jun 24, 2023
af6f599
feat: 아이콘 추가 및 컴포넌트화
Jun 26, 2023
7d7433e
feat: react-aria 에 필요한 SSR Provider 적용하기
Jun 26, 2023
28aac4a
fix: ImageUploader 트러블 해결
Jun 26, 2023
17f14cc
refactor: Tag, TagContainer 컴포넌트 리팩토링
Jun 26, 2023
4c49109
delete:
Jun 26, 2023
51b326d
feat: Radio 컴포넌트 구현
Jun 26, 2023
3c467e1
feat: TextInput 컴포넌트 counter 기능 구현
Jun 26, 2023
8386d4d
feat: Radio 컴포넌트 및 기능 구현
Jun 26, 2023
3615c0d
feat: 에셋 수정 페이지
Jun 26, 2023
5d7d7e0
refactor: FileUploader 컴포넌트 리팩토링
Jun 26, 2023
3a66f9b
feat: Select 컴포넌트 기능 구현
Jun 26, 2023
a25701e
feat: 라이브러리 설치
Jun 26, 2023
09d3ffc
feat: assetData ,setAssetData 메인 테이블 컴포넌트에 추가
Jun 26, 2023
bfae67b
fix: 에러 주석 처리
Jun 26, 2023
b34b692
Merge branch 'develop' into main
Jun 26, 2023
8344e92
Merge branch 'develop' of https://github.com/3DAsset-eCommerce/3D-Admin
Jun 27, 2023
254f942
config: 라이브러리 설치
Jun 27, 2023
8eab828
refactor: 타입 변경
Jun 27, 2023
3931cd2
refactor: 이벤트핸들러 변경
Jun 27, 2023
db0f349
feat: 안쓰는 기능 disabled 처리
Jun 27, 2023
0f48316
config: 라이브러리 설치
Jul 1, 2023
a19c56e
feat: redux 세팅
Jul 1, 2023
3415b44
feat: axoios 설정 및 api interfaces, 함수 생성
Jul 1, 2023
9d287b4
delete
Jul 1, 2023
7df847b
typo
Jul 1, 2023
6aa364e
Merge branch 'main' of https://github.com/www-r/3D-Admin
Jul 1, 2023
79b7956
feat: Redux Provider 적용
Jul 1, 2023
5e9d3f8
feat: Tags Input 기능 구현
Jul 1, 2023
9890a87
feat: Input 컴포넌트에 tags 관련 기능 추가하기
Jul 1, 2023
cae2886
feat: 선택한 카테고리 실시간으로 보이기
Jul 1, 2023
74abf5e
fix: typescript 타입 관련 에러 해결
Jul 1, 2023
efa305e
feat: debounce 함수 구현
Jul 3, 2023
7bc8379
feat: debounce 함수 구현
Jul 3, 2023
ff7c097
feat: Tag 추가, 삭제 기능 구현, 에러 핸들링 로직 추가
Jul 3, 2023
3b714e7
delete
Jul 3, 2023
c5b9895
feat: asset Slice (redux) 생성
Jul 3, 2023
e6dc7c4
Merge branch 'develop' into main
ronieo Jul 3, 2023
6b6277c
feat: react hook form 설치
Jul 3, 2023
b93390a
feat: 상세 페이지 이미지 필수요건 제외
Jul 3, 2023
fc2962b
feat: 파일 업로드 기능 구현
Jul 3, 2023
94b4140
feat: required props 추가
Jul 4, 2023
0d81544
feat: react hook form 사용
Jul 4, 2023
0d6edee
Merge branch 'develop' of https://github.com/3DAsset-eCommerce/3D-Admin
Jul 4, 2023
6b93846
fix: merge 충돌 해결
Jul 4, 2023
92436c7
chore: :hammer: delete files
Jul 5, 2023
cf48037
refactor: :recycle: sideNav 컴포넌트화
Jul 5, 2023
ea67c37
feat: :sparkles: page 경로 수정
Jul 5, 2023
14a5e5c
refactor: :recycle: table 표 클라이언트 렌더링 하기 위해 페이지에서 분리
Jul 5, 2023
f08c261
style: :lipstick: tailwind CSS로 스타일 추가
Jul 5, 2023
74b44c7
refactor: :recycle: selectContainer 에서 ListBox 만 따로 분리해서 컴포넌트화
Jul 5, 2023
a4facbb
chore: :hammer: chore
Jul 5, 2023
f3a1ce6
feat: :sparkles: radio Select 컴포넌트 생성
Jul 5, 2023
cc948dd
chore: :hammer: 스타일 수정 및 라이브러리 추가\
Jul 5, 2023
f4b2699
feat: :sparkles: date Input 컴포넌트 생성
Jul 5, 2023
0139f7e
feat: :sparkles: cSR 에서 SSG 으로 변경
Jul 5, 2023
200618d
Merge branch 'main' of https://github.com/www-r/3D-Admin
Jul 5, 2023
8939d04
perf: :zap: 에셋조회API 요청 Request Interface
Jul 7, 2023
cd835a1
refactor: :recycle: select 와 Select Container 컴포넌트 더 단순화
Jul 7, 2023
3a7c4cd
style: :lipstick: 코드 정리
Jul 7, 2023
1a3ba7c
refactor: :recycle: 테이블표에서 공통 컴포넌트 만들기
Jul 7, 2023
15e05a2
feat: :sparkles: input File 상황별 조건에 따라 기능 구현
Jul 7, 2023
2eb7e3b
feat: :sparkles: input Text 디바운스 기능 구현 -> 일정한 시간 지나야 상태set 한다
Jul 7, 2023
f6a0d4c
feat: :sparkles: input Image(File) 상황별 조건에 따른 기능 구현
Jul 7, 2023
ff93a55
refactor: :recycle: 컴포넌트 및 기능 리팩토링
Jul 7, 2023
3459e10
feat: :sparkles: 디바운스 함수 구현
Jul 7, 2023
106937f
feat: :sparkles: asset 관련 redux 및 API 기능
Jul 7, 2023
e37ef21
fix: :bug: type error 수정
Jul 7, 2023
f6ef945
fix: :bug: inputRef 타입 에러 수정
Jul 7, 2023
dd5940e
fix: :bug: useEffect missing dependency 에러 fix
Jul 7, 2023
c54d5fd
fix: :bug: 태그 추가할 때 Input 창 초기화
Jul 7, 2023
ac95b7f
fix: :bug: asset 등록 시 초기 상태 변경
Jul 7, 2023
90844c1
feat: :sparkles: 체크박스 삭제 (불필요한 기능)
Jul 7, 2023
6bc26b8
refactor: :recycle: asset 수정 dynamic Route 수정
Jul 7, 2023
2304192
fix: :bug: button type 에 따른 onClick 혼동 해결
Jul 7, 2023
af4877e
feat: File 등록 관련 기능 ( 수정 필요)
Jul 16, 2023
b5cfe44
fix: File 등록 API 에러 해결
Jul 16, 2023
a33f231
refactor: File 등록 API 함수 통합( file, thumbnail, detail)
Jul 16, 2023
c2f558f
Update README.md (!ㅑㅜㅎ)
wwwr-kim0en Jul 22, 2023
4bf6acd
docs: Update README.md
wwwr-kim0en Jul 31, 2023
725646c
Update README.md
wwwr-kim0en Feb 4, 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
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ yarn-error.log*

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

# vercel
.vercel

Expand Down
80 changes: 59 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,34 +1,72 @@
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
# Nation A - 3D Assets 거래 사이트
![](https://bleyetciwkirndgevlln.supabase.co/storage/v1/object/sign/images/3dasset.png?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1cmwiOiJpbWFnZXMvM2Rhc3NldC5wbmciLCJpYXQiOjE3MDcwMjc3MTAsImV4cCI6MTczODU2MzcxMH0.RoEXVhxI8-rdTbitJ14KLMzGMkb0gjE2QtOyPt5WoAs&t=2024-02-04T06%3A21%3A50.403Z)
![](https://bleyetciwkirndgevlln.supabase.co/storage/v1/object/sign/images/3dasset-2.png?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1cmwiOiJpbWFnZXMvM2Rhc3NldC0yLnBuZyIsImlhdCI6MTcwNzAyNzY2MiwiZXhwIjoxNzM4NTYzNjYyfQ.SAqeY1PJuZT1XAF_hBu1Uuq7HokNt3l3HkoMHapuU-A&t=2024-02-04T06%3A21%3A03.129Z)

## Getting Started
## 🏆배포
- 주소: 현재 서버가 닫혀 있음
- Admin 관리자
- ID : quanliza1@nate.com
- PW : qwe123!@#

First, run the development server:
## ✔️ 깃허브

```bash
npm run dev
# or
yarn dev
# or
pnpm dev
```
https://github.com/3DAsset-eCommerce/3D-FE.git

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
https://github.com/3DAsset-eCommerce/3D-Admin

You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
## 📆 기간

This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
2023.06 - 2023.07

## Learn More
## 👭 인원

To learn more about Next.js, take a look at the following resources:
FE 4명, BE 4명, UI/UX 2명, PM 4명

- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
## 🛠️ 기술

You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
TypeScript, Next.js 13, Tailwind-CSS, Redux-Toolkit, React-Query, React-Hook-Form

## Deploy on Vercel
- **Next.js** : 온라인 스토어 특성상 SEO가 중요합니다.

서버사이드렌더링과 다른 렌더링 방식들을 혼합해서 사용해여 성능 개선을 이룰 수 있습니다.

이미지 최적화 , 폴더 기반 라우터, 코드 스플리팅을 지원합니다.

- **Tailwind CSS** : Next.js에서 SSR을 사용할 때 CSS-in-JS는 hydrate이전의 스타일이 적용되지 않습니다.
- **React Query** : 서버 데이터와 상태 동기화, 자동 캐싱, 실시간 업데이트, 간편한 데이터 관리를 위해서 입니다.

The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
## 📃  담당 파트

- 에셋 등록 페이지 (admin)
- 에셋 수정 페이지 (admin)
- 에셋 조회 페이지 (admin)
- 주문내역 조회 페이지 (admin)

## ✍️상세 설명

### 에셋 등록 페이지 , 에셋 수정 페이지

- 페이지에 대부분은 SSR로 하고, 유저와 인터렉션이 필요한 일부 컴포넌트(input, button 등)만 CSR로 했습니다.
- 커스텀 클래스와 스타일을 tailwind.config.js에 정의해서 개발 시간을 절약했습니다.
- 디자인을 충족시키기 위해, 기존의 input 창들을 커스텀해서 사용했습니다.
- 3d 에셋, 이미지 등을 업로드하고 내려받기 위해 formData를 활용했습니다.
- 데이터 변경을 화면에 즉각적으로 적용하기 위해 Redux-Toolkit을 사용해서 에셋의 각 항목별 데이터들을 전역으로 관리했습니다.
- 에셋명 input의 state를 사용자가 입력할 때 마다 set하지 않고, useDebounce 커스텀 훅을 만들어 사용함으로써 EventListener가 비효율적으로 많이 호출되는 점을 개선했습니다.
- 각 항목마다 API가 있는데, 입력될 때 마다 요청을 보내는 것이 아니라, 에셋 등록 버튼을 눌렀을 때 한번에 요청을 보낼 수 있게 함으로써 API요청 횟수를 줄여 성능을 개선했습니다.

![1](https://bleyetciwkirndgevlln.supabase.co/storage/v1/object/sign/images/3dasset1.png?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1cmwiOiJpbWFnZXMvM2Rhc3NldDEucG5nIiwiaWF0IjoxNzA3MDI3NzQ4LCJleHAiOjE3Mzg1NjM3NDh9.w49lqvE5DVdl6MN3Dt_X6XNMTvK5nzwIY7sOk4SErGo&t=2024-02-04T06%3A22%3A28.260Z)

![2](https://bleyetciwkirndgevlln.supabase.co/storage/v1/object/sign/images/3dasset-4%20(1).png?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1cmwiOiJpbWFnZXMvM2Rhc3NldC00ICgxKS5wbmciLCJpYXQiOjE3MDcwMjc4MDksImV4cCI6MTczODU2MzgwOX0.3jqnoBIaKaBOi31CFPlY7j3LrHfQr0n9j6KFe6f13A8&t=2024-02-04T06%3A23%3A29.464Z)

### 에셋 조회 페이지

- React Query의 useInfiniteQuery와 Intersection Observer를 활용해 무한스크롤 기능을 구현했습니다.

![3](https://bleyetciwkirndgevlln.supabase.co/storage/v1/object/sign/images/3dasset-4.png?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1cmwiOiJpbWFnZXMvM2Rhc3NldC00LnBuZyIsImlhdCI6MTcwNzAyNzgzMCwiZXhwIjoxNzM4NTYzODMwfQ.V6gxQ3lPhrt0TPBTPMaUUKQZrl54ynUCL43jnB_9-dA&t=2024-02-04T06%3A23%3A50.811Z)

### 주문 조회 페이지

- 표에 배열 형태의 데이터를 선택한 조건에 따라 정렬하는 기능을 구현했습니다.

![4](https://bleyetciwkirndgevlln.supabase.co/storage/v1/object/sign/images/3dasset-3.png?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1cmwiOiJpbWFnZXMvM2Rhc3NldC0zLnBuZyIsImlhdCI6MTcwNzAyNzg3MywiZXhwIjoxNzM4NTYzODczfQ.Q_6c5FVUKVDBG1ABrPDc81860rUYk_n4Fp98gWQrJkA&t=2024-02-04T06%3A24%3A33.578Z)

Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
6 changes: 5 additions & 1 deletion next.config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
/** @type {import('next').NextConfig} */
const nextConfig = {}
const nextConfig = {
experimental: {
serverActions: true,
},
}

module.exports = nextConfig
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,14 @@
"commit": "git-cz"
},
"dependencies": {
"@react-aria/listbox": "^3.9.1",
"@react-aria/select": "^3.10.1",
"@react-stately/select": "^3.5.1",
"@headlessui/react": "^1.7.15",
"@reduxjs/toolkit": "^1.9.5",
"@tanstack/react-query": "^4.29.19",
"@tanstack/react-query-devtools": "^4.29.19",
"@types/node": "20.2.5",
"@types/react": "18.2.9",
"@types/react-dom": "18.2.4",
"antd": "^5.6.4",
"autoprefixer": "10.4.14",
"axios": "^1.4.0",
"commitizen": "^4.3.0",
Expand All @@ -28,6 +27,7 @@
"next": "13.4.4",
"postcss": "8.4.24",
"react": "18.2.0",
"react-aria": "^3.25.0",
"react-dom": "18.2.0",
"react-hook-form": "^7.45.1",
"react-redux": "^8.1.1",
Expand Down
4 changes: 4 additions & 0 deletions public/icons/Active.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions public/icons/ArrowDropDown.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions public/icons/Inactive.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions public/icons/checkboxEmpty.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 20 additions & 0 deletions public/icons/icons.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import Image from 'next/image'
import Active from './Active.svg'
import Inactive from './Inactive.svg'
import ArrowDropDown from './ArrowDropDown.svg'
import Close from './close.svg'
export const RadioActive = () => {
return <Image src={Active} alt='radio active icon' width={24} height={24}/>
}

export const RadioInactive = () => {
return <Image src={Inactive} alt='radio inactive icon'width={24} height={24}/>
}

export const DropDownIcon = () => {
return <Image src={ArrowDropDown} alt='drop down icon'width={24} height={24}/>
}

export const CloseIcon = () => {
return <Image src={Close} alt='close icon' width={24} height={24}/>
}
73 changes: 73 additions & 0 deletions src/api/interface/asset.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { ApiResponse } from './'

export interface AssetsSearchRequest {
page?: number
size?: number
sort?: 'createdAt' | 'desc'
num?: number
name?: string
category?: string
subcategory?: string
status?: boolean
}

export interface AssetDetail {
assetId: number
assetName: string
price: number
description: string
discount: number
discountPrice: number
extension: string
fileSize: number
fileUrl: string
creator: string
rating: number
reviewCount: number
wishCount: number
visitCount: number
wishlistId: null
previewList: string[]
tagList: string[]
}

export interface AssetUploadRequest {
assetName: string
assetDescription: string
price: number
discount: number
category: string
subCategory: string
addTagList: string[]
fileUrl: string
fileSize: number
extension: string
thumbnailUrl: string
previewUrlList: string[]
}
export interface AssetEditRequest {
assetId: number
assetName?: string
assetContent?: string
price?: number
assetDiscount?: number
category?: string
subCategory?: string
deleteTag: string[] | null
addTag?: string[]
fileUrl?: string
thumbnailUrl?: string
previewUrl?: string[]
}

export interface AssetInactiveRequest {
assets: number[]
}
export interface AssetActiveRequest {
assets: number[]
}



export type AssetDetailResponse = ApiResponse<AssetDetail>

12 changes: 12 additions & 0 deletions src/api/interface/category.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
interface Category {
id: number
categoryName: string
subCategory?: SubCategory[]
}
interface SubCategory {
id: number
subCategoryName: string
}
interface CategoryList {
categoryList: Category[]
}
55 changes: 55 additions & 0 deletions src/api/service/asset.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import axios from 'axios'
import { axiosInstance } from '../axios'
import { AssetDetailResponse, AssetUploadRequest, AssetsSearchRequest } from '../interface/asset'
import { getToken } from '@/utils/token'
//에셋 조회
// export const searchAssets = async ({
// page,
// size,
// sort,
// num,
// name,
// category,
// subcategory,
// status,
// }: AssetsSearchRequest) => {
// const res = await axiosInstance.get(`https://neuroid-asset.shop/s/admin/assets?num=${
// num && num
// }&name=${name && name}&category=${category && category}&subcategory=${subcategory && subcategory}
// &status=${status && status}&page=${page}&size=${size}&sort=${sort}`)
// return res.data
// }
export const getAllAssets = async () => {
const res = await axiosInstance.get(
'/s/admin/assets?num=&name=man&category=&subcategory=&status=true&page=0&size=100&sort=createdAt',
)
return res.data
}

//에셋 상세보기
export const getAssetDetail = async <T = AssetDetailResponse>(id: number): Promise<T> => {
const res = await axiosInstance.get<T>(`/assets/${id}/details`)
return res.data
}
export const uploadAsset = async (asset: FormData) => {
const res = await axiosInstance.post('/s/admin/asset', asset)
return res.data
}
export const uploadFileAsset = async (file: FormData, type: 'fbx' | 'thumbnail' | 'detail') => {
const token = getToken()
const res = await axios.post(`/s/admin/file/${type}`, file, {
baseURL: process.env.NEXT_PUBLIC_BASE_URL,
headers: {
'Content-Type': 'multipart/form-data',
Authorization: `Bearer ${token}`,
},
withCredentials: true,
})
return res
}

// export const editAsset = async (asset): Promise<T> => {
// const res = await axiosInstance.post('/s/admin/asset/update', asset)
// }
// export const inactivateAsset = async (): Promise<T> => {}
// export const activateAsset = async (): Promise<T> => {}
13 changes: 13 additions & 0 deletions src/api/service/category.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { axiosInstance } from '../axios'

//카테고리 리스트 조회
export const getFullCategoryList = async () => {
const res = await axiosInstance.get('s/admin/category')
return res.data
}

//서브 카테고리 리스트 조회
export const getSubCategoryList = async (categoryName: string) => {
const res = await axiosInstance.get(`s/admin/${categoryName}/subcategory`)
return res.data
}
Loading