diff --git a/.eslintrc.cjs b/.eslintrc.cjs
new file mode 100644
index 00000000..20df948c
--- /dev/null
+++ b/.eslintrc.cjs
@@ -0,0 +1,15 @@
+module.exports = {
+ env: { browser: true, es2020: true, node: true },
+ extends: [
+ 'eslint:recommended',
+ 'plugin:@typescript-eslint/recommended',
+ 'plugin:react-hooks/recommended',
+ ],
+ parser: '@typescript-eslint/parser',
+ parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
+ plugins: ['react-refresh'],
+ rules: {
+ 'react-refresh/only-export-components': 'warn',
+ 'no-console': ['warn'],
+ },
+};
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..a547bf36
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,24 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 00000000..198338e7
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,9 @@
+{
+ "printWidth": 80,
+ "semi": true,
+ "singleQuote": true,
+ "trailingComma": "es5",
+ "bracketSpacing": true,
+ "endOfLine": "auto",
+ "tabWidth": 2
+}
diff --git a/README.md b/README.md
index c81804bf..6a4d8726 100644
--- a/README.md
+++ b/README.md
@@ -1,1319 +1,392 @@
-# ๐ค ๊ฑฐ๋ API ํ์ฉ, ํ ํ๋ก์ ํธ
+# ๐ค ํจ์คํธ์บ ํผ์ค FE5 ์ผํ๋ชฐ ํํ๋ก์ ํธ
-์ฃผ์ด์ง API๋ฅผ ๋ถ์ํด ์ด๋ค ํ๋ก์ ํธ๋ฅผ ์งํ/์์ฑํ ๊ฒ์ธ์ง ํ ๋จ์๋ก ์์ ๋กญ๊ฒ ๊ฒฐ์ ํ๊ณ ๋ง๋ค์ด๋ณด์ธ์.
-TypeScript๋ฅผ ํ์๋ก ์ฌ์ฉํด์ผ ํฉ๋๋ค.
-๊ณผ์ ์ํ ๋ฐ ๋ฆฌ๋ทฐ ๊ธฐ๊ฐ์ ๋ณ๋ ๊ณต์ง๋ฅผ ์ฐธ๊ณ ํ์ธ์!
+
+
+
+
+
+
-## ๊ณผ์ ์ํ ๋ฐ ์ ์ถ ๋ฐฉ๋ฒ
+> ๋ณธ ํ๋ก์ ํธ๋ ํจ์คํธ์บ ํผ์ค ๋ถํธ์บ ํ ํ๋ก ํธ์ค๋ 5๊ธฐ, 5์ฐจ ๊ณผ์ ์
๋๋ค.
+> ์ ํฌ 1์กฐ๋ ์ฃผ์ด์ง API๋ฅผ ํ์ฉํ์ฌ ์ถ๊ตฌํ ์จ๋ผ์ธ ์ผํ๋ชฐ์ ์ ์ํ์์ต๋๋ค.
+> ์ฐธ๊ณ ํ ์ฌ์ดํธ: [ํฌ๋ ์ด์ง11](https://crazy11.co.kr/)
+> ๊ฐ๋ฐ ๊ธฐ๊ฐ : 2023. 5. 31 ~ 2023. 6. 21
-```
-KDT๊ธฐ์๋ฒํธ_์ด๋ฆ
-
-E.g, KDT0_ParkYoungWoong
-```
-
-1. ํ์ฌ ์ ์ฅ์๋ฅผ ๋ก์ปฌ์ ํด๋ก (Clone)ํฉ๋๋ค.
-1. ์์ ์ ๋ณธ๋ช
์ผ๋ก ๋ธ๋์น๋ฅผ ์์ฑํฉ๋๋ค.(๊ตฌ๋ถ ๊ฐ๋ฅํ๋๋ก ๋ณธ๋ช
์ ๊ผญ ํ์ค์นผ์ผ์ด์ค๋ก ํ์ํ์ธ์, `git branch KDTX_ParkYoungWoong`)
-1. ์์ ์ ๋ณธ๋ช
๋ธ๋์น์์ ๊ณผ์ ๋ฅผ ์ํํฉ๋๋ค.
-1. ๊ณผ์ ์ํ์ด ์๋ฃ๋๋ฉด, ์์ ์ ๋ณธ๋ช
๋ธ๋์น๋ฅผ ์๊ฒฉ ์ ์ฅ์์ ํธ์(Push)ํฉ๋๋ค.(`main` ๋ธ๋์น์ ํธ์ํ์ง ์๋๋ก ๊ผญ ์ฃผ์ํ์ธ์, `git push origin KDTX_ParkYoungWoong`)
-1. ์ ์ฅ์์์ `main` ๋ธ๋์น๋ฅผ ๋์์ผ๋ก Pull Request ์์ฑํ๋ฉด, ๊ณผ์ ์ ์ถ์ด ์๋ฃ๋ฉ๋๋ค!(E.g, `main` <== `KDTX_ParkYoungWoong`)
-
-- `main` ํน์ ๋ค๋ฅธ ์ฌ๋์ ๋ธ๋์น๋ก ์ ๋ ๋ณํฉํ์ง ์๋๋ก ์ฃผ์ํ์ธ์!
-- Pull Request์์ ๋ณด์ด๋ ์ค๋ช
์ ๋ค๋ฅธ ์ฌ๋๋ค์ด ์ดํดํ๊ธฐ ์ฝ๋๋ก ๊ผผ๊ผผํ๊ฒ ์์ฑํ์ธ์!
-- Pull Request์์ ๊ณผ์ ์ ์ถ ํ ์ ๋ ๋ณํฉ(Merge)ํ์ง ์๋๋ก ์ฃผ์ํ์ธ์!
-- ๊ณผ์ ์ํ ๋ฐ ์ ์ถ ๊ณผ์ ์์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ๊ฒฝ์ฐ, ๋ฐ๋ก ๋ด๋น ๋ฉํ ๋ ๊ฐ์ฌ์์ ์๊ธฐํ์ธ์!
-
-## API ์ฌ์ฉ๋ฒ
-
-๋ชจ๋ API ์์ฒญ(Request) `headers`์ ์๋ ์ ๋ณด๊ฐ ๊ผญ ํฌํจ๋ผ์ผ ํฉ๋๋ค!
-`username`์ `KDT5_TeamX`์ ๊ฐ์ด ๋ณธ๋ช
ํน์ ํ ์ด๋ฆ์ ํฌํจํด์ผ ํฉ๋๋ค!
-ํ์ธํ ์ ์๋ ์ฌ์ฉ์๋ ํ์ DB ์ ๋ณด๋ ์์๋ก ์ญ์ ๋ ์ ์์ต๋๋ค!
-
-```json
-{
- "content-type": "application/json",
- "apikey": "KDT5_nREmPe9B",
- "username": "KDT5_TeamX"
-}
-```
-
-
-
-## ์ธ์ฆ
-
-'์ธ์ฆ' ๊ด๋ จ API๋ ๋ชจ๋ ์ผ๋ฐ ์ฌ์ฉ์ ์ ์ฉ์
๋๋ค.
-
-### ํ์๊ฐ์
-
-์ฌ์ฉ์๊ฐ `username`์ ์ข
์๋์ด ํ์๊ฐ์
ํฉ๋๋ค.
-
-- ์ฌ์ฉ์ ๋น๋ฐ๋ฒํธ๋ ์ํธํํด ์ ์ฅํฉ๋๋ค.(๊ด๋ฆฌ์๋ ํ์ธํ ์ ์์ต๋๋ค!)
-- ํ๋กํ ์ด๋ฏธ์ง๋ 1MB ์ดํ์ฌ์ผ ํฉ๋๋ค.
-
-```curl
-curl https://asia-northeast3-heropy-api.cloudfunctions.net/api/auth/signup
- \ -X 'POST'
-```
-
-์์ฒญ ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
-
-```ts
-interface RequestBody {
- email: string // ์ฌ์ฉ์ ์์ด๋ (ํ์!)
- password: string // ์ฌ์ฉ์ ๋น๋ฐ๋ฒํธ, 8์ ์ด์ (ํ์!)
- displayName: string // ์ฌ์ฉ์ ์ด๋ฆ, 20์ ์ดํ (ํ์!)
- profileImgBase64?: string // ์ฌ์ฉ์ ํ๋กํ ์ด๋ฏธ์ง(base64) - jpg, jpeg, webp, png, gif, svg
-}
-```
-
-```json
-{
- "email": "thesecon@gmail.com",
- "password": "********",
- "displayName": "ParkYoungWoong",
- "profileImgBase64": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAf...(์๋ต)"
-}
-```
-
-์๋ต ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
-
-```ts
-interface ResponseValue {
- user: { // ํ์๊ฐ์
ํ ์ฌ์ฉ์ ์ ๋ณด
- email: string // ์ฌ์ฉ์ ์์ด๋
- displayName: string // ์ฌ์ฉ์ ํ์ ์ด๋ฆ
- profileImg: string | null // ์ฌ์ฉ์ ํ๋กํ ์ด๋ฏธ์ง(URL)
- }
- accessToken: string // ์ฌ์ฉ์ ์ ๊ทผ ํ ํฐ
-}
-```
-
-```json
-{
- "user": {
- "email": "thesecon@gmail.com",
- "displayName": "ParkYoungWoong",
- "profileImg": "https://storage.googleapis.com/heropy-api/vjbtIrh5dGv163442.png"
- },
- "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IlM3WDhpQ...(์๋ต)"
-}
-```
-
-### ๋ก๊ทธ์ธ
-
-- ๋ฐ๊ธ๋ `accessToken`์ 24์๊ฐ ํ ๋ง๋ฃ๋ฉ๋๋ค.(๋ง๋ฃ ํ ๋ค์ ๋ก๊ทธ์ธ ํ์)
-
-```curl
-curl https://asia-northeast3-heropy-api.cloudfunctions.net/api/auth/login
- \ -X 'POST'
-```
-
-์์ฒญ ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
-
-```ts
-interface RequestBody {
- email: string // ์ฌ์ฉ์ ์์ด๋ (ํ์!)
- password: string // ์ฌ์ฉ์ ๋น๋ฐ๋ฒํธ (ํ์!)
-}
-```
-
-```json
-{
- "email": "thesecon@gmail.com",
- "password": "********"
-}
-```
-
-์๋ต ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
-
-```ts
-interface ResponseValue {
- user: { // ํ์๊ฐ์
ํ ์ฌ์ฉ์ ์ ๋ณด
- email: string // ์ฌ์ฉ์ ์์ด๋
- displayName: string // ์ฌ์ฉ์ ํ์ ์ด๋ฆ
- profileImg: string | null // ์ฌ์ฉ์ ํ๋กํ ์ด๋ฏธ์ง(URL)
- }
- accessToken: string // ์ฌ์ฉ์ ์ ๊ทผ ํ ํฐ
-}
-```
-
-```json
-{
- "user": {
- "email": "thesecon@gmail.com",
- "displayName": "ParkYoungWoong",
- "profileImg": "https://storage.googleapis.com/heropy-api/vAKjlJ-Gx5v163442.png"
- },
- "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjlQS3I...(์๋ต)"
-}
-```
-
-### ์ธ์ฆ ํ์ธ
-
-```curl
-curl https://asia-northeast3-heropy-api.cloudfunctions.net/api/auth/me
- \ -X 'POST'
- \ -H 'Authorization: Bearer '
-```
-
-์์ฒญ ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
-
-- ์์
-
-์๋ต ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
-
-```ts
-interface ResponseValue {
- email: string // ์ฌ์ฉ์ ์์ด๋
- displayName: string // ์ฌ์ฉ์ ํ์ ์ด๋ฆ
- profileImg: string | null // ์ฌ์ฉ์ ํ๋กํ ์ด๋ฏธ์ง(URL)
-}
-```
-
-```json
-{
- "email": "thesecon@gmail.com",
- "displayName": "ParkYoungWoong",
- "profileImg": "https://storage.googleapis.com/heropy-api/vAKjlJ-Gx5v163442.png"
-}
-```
-
-### ๋ก๊ทธ์์
-
-```curl
-curl https://asia-northeast3-heropy-api.cloudfunctions.net/api/auth/logout
- \ -X 'POST'
- \ -H 'Authorization: Bearer '
-```
-
-์์ฒญ ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
-
-- ์์
-
-์๋ต ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
-
-```ts
-type ResponseValue = true // ๋ก๊ทธ์์ ์ฒ๋ฆฌ ์ํ
-```
-
-### ์ฌ์ฉ์ ์ ๋ณด ์์
-
-```curl
-curl https://asia-northeast3-heropy-api.cloudfunctions.net/api/auth/user
- \ -X 'PUT'
- \ -H 'Authorization: Bearer '
-```
-
-์์ฒญ ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
-
-```ts
-interface RequestBody {
- displayName?: string // ์๋ก์ด ํ์ ์ด๋ฆ
- profileImgBase64?: string // ์ฌ์ฉ์ ํ๋กํ ์ด๋ฏธ์ง(base64) - jpg, jpeg, webp, png, gif, svg
- oldPassword?: string // ๊ธฐ์กด ๋น๋ฐ๋ฒํธ
- newPassword?: string // ์๋ก์ด ๋น๋ฐ๋ฒํธ
-}
-```
-
-```json
-{
- "oldPassword": "********",
- "newPassword": "**********"
-}
-```
-
-์๋ต ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
-
-```ts
-interface ResponseValue {
- email: string // ์ฌ์ฉ์ ์์ด๋
- displayName: string // ์ฌ์ฉ์ ํ์ ์ด๋ฆ
- profileImg: string | null // ์ฌ์ฉ์ ํ๋กํ ์ด๋ฏธ์ง(URL)
-}
-```
-
-```json
-{
- "email": "thesecon@gmail.com",
- "displayName": "ParkYoungWoong",
- "profileImg": "https://storage.googleapis.com/heropy-api/vAKjlJ-Gx5v163442.png"
-}
-```
+
-### ์ฌ์ฉ์ ๋ชฉ๋ก ์กฐํ
+# ๋ฐฐํฌ์ฃผ์
-- ๊ด๋ฆฌ์ ์ ์ฉ API์
๋๋ค.
+https://kdt-5-m5-crazy11.vercel.app
+
-```curl
-curl https://asia-northeast3-heropy-api.cloudfunctions.net/api/auth/users
- \ -X 'GET'
- \ -H 'masterKey: true'
-```
-
-์์ฒญ ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
+# ๊ฐ๋ฐํ ์๊ฐ
-- ์์
+| ํ์ | ์ ์น์ | ๋ฐํ์ค | ์ต์ฉ์ค | ํฉ์ธ์น | ์ด์ ์ฐ |
+| :----: | :-------------------------------------: | :----------------------------------------------: | :------------------------------------------: | :----------------------------------------------: | :----------------------------------------: |
+| ๊นํ๋ธ | [@Tteum00](https://github.com/Tteum00) | [@HyunJunPark0](https://github.com/HyunJunPark0) | [@PelicanStd](https://github.com/PelicanStd) | [@hwanginseung](https://github.com/hwanginseung) | [@howooking](https://github.com/howooking) |
+| ๋ด๋น | ํ์์ ๋ณด
์ํ ์์ธํ์ด์ง
๊ตฌ๋งคํ์ | ๊ฐ์ธ์ ๋ณด ์์
๊ตฌ๋งค๋ด์ญ
๊ตฌ๋งค์ทจ์ | ์ํ ๊ด๋ฆฌ
์ํ ์ถ๊ฐ
์ํ ์์ | ๊ณ์ข
๊ฑฐ๋๋ด์ญ
์ํ ๊ฒ์ | ์ธ์ฆ / ์ธ๊ฐ
์ํ ๋ฐฐ์น
์คํ์ผ๋ง |
-์๋ต ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
+
-```ts
-type ResponseValue = User[]
+# ์์ ๊ฐ์ด๋
-interface User {
- email: string // ์ฌ์ฉ์ ์์ด๋
- displayName: string // ์ฌ์ฉ์ ํ์ ์ด๋ฆ
- profileImg: string // ์ฌ์ฉ์ ํ๋กํ ์ด๋ฏธ์ง URL
-}
-```
+## Installation
-```json
-[
- {
- "email": "thesecon@gmail.com",
- "displayName": "HEROPY",
- "profileImg": null
- },
- {
- "email": "neo@zillinks.com",
- "displayName": "๋ฐ์์
",
- "profileImg": "https://storage.googleapis.com/heropy-api/Z_una7lyijv074804.png"
- },
- {
- "email": "test@test.com",
- "displayName": "๊ด๋ฆฌ์",
- "profileImg": "https://storage.googleapis.com/heropy-api/ZXcXjwsB7nv121507.png"
- }
-]
+```cli
+$ git clone https://github.com/howooking/KDT5-M5
+$ cd KDT5-M5
+$ npm install
+$ npm run dev
```
-
-
-## ๊ณ์ข
-
-'๊ณ์ข' ๊ด๋ จ API๋ ๋ชจ๋ ์ผ๋ฐ ์ฌ์ฉ์ ์ ์ฉ์
๋๋ค.
-
-### ์ ํ ๊ฐ๋ฅํ ์ํ ๋ชฉ๋ก ์กฐํ
-
-- ์ํ ๋น ํ๋์ ๊ณ์ข๋ง ํ์ฉ๋ฉ๋๋ค.
-- ์ฌ์ฉ์๊ฐ ๊ณ์ข๋ฅผ ์ถ๊ฐํ๋ฉด, ํด๋น ์ํ ์ ๋ณด `disabled` ์์ฑ์ด `true`๋ก ๋ณ๊ฒฝ๋ฉ๋๋ค.
-- ์ํ ์ ๋ณด `digits` ์์ฑ์ ์ซ์๋ฅผ ๋ชจ๋ ๋ํ๋ฉด ๊ฐ ์ํ์ ์ ํจํ ๊ณ์ข๋ฒํธ ๊ธธ์ด๊ฐ ๋ฉ๋๋ค.
-- `[3, 2, 4, 3]` => 123-12-1234-123
-
-```curl
-curl https://asia-northeast3-heropy-api.cloudfunctions.net/api/account/banks
- \ -X 'GET'
- \ -H 'Authorization: Bearer '
-```
+> ๋ฐฑ์ค๋ ์๋ฒ ์คํ์ ๋ถํ์ํฉ๋๋ค.
-์์ฒญ ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
+
-- ์์
+# ์ฌ์ฉํ ๊ธฐ์ , ๋ผ์ด๋ธ๋ฌ๋ฆฌ
-์๋ต ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
+## Environment
-```ts
-type ResponseValue = Bank[] // ์ ํ ๊ฐ๋ฅํ ์ํ ์ ๋ณด ๋ชฉ๋ก
+
+
+
-interface Bank { // ์ ํ ๊ฐ๋ฅํ ์ํ ์ ๋ณด
- name: string // ์ํ ์ด๋ฆ
- code: string // ์ํ ์ฝ๋
- digits: number[] // ์ํ ๊ณ์ข ์๋ฆฟ์
- disabled: boolean // ์ฌ์ฉ์๊ฐ ์ถ๊ฐํ ๊ณ์ข ์ฌ๋ถ
-}
-```
+## Config
-```json
-[
- {
- "name": "KB๊ตญ๋ฏผ์ํ",
- "code": "004",
- "digits": [3, 2, 4, 3],
- "disabled": false
- },
- {
- "name": "์ ํ์ํ",
- "code": "088",
- "digits": [3, 3, 6],
- "disabled": true
- },
- {
- "name": "์ฐ๋ฆฌ์ํ",
- "code": "020",
- "digits": [4, 3, 6],
- "disabled": true
- },
- {
- "name": "ํ๋์ํ",
- "code": "081",
- "digits": [3, 6, 5],
- "disabled": false
- },
- {
- "name": "์ผ์ด๋ฑ
ํฌ",
- "code": "089",
- "digits": [3, 3, 6],
- "disabled": false
- },
- {
- "name": "์นด์นด์ค๋ฑ
ํฌ",
- "code": "090",
- "digits": [4, 2, 7],
- "disabled": false
- },
- {
- "name": "NH๋ํ์ํ",
- "code": "011",
- "digits": [3, 4, 4, 2],
- "disabled": false
- }
-]
-```
+
+
-### ๊ณ์ข ๋ชฉ๋ก ๋ฐ ์์ก ์กฐํ
+## Development
-- ๊ณ์ข๋ฒํธ๋ ์ผ๋ถ๋ง ๋
ธ์ถ๋ฉ๋๋ค. E.g. `"123-XXXX-XXXX-XX"`
-- ์์ก์ ๋จ์๋ '์ํ(๏ฟฆ)'์
๋๋ค.
+
+
+
+
+ : ์ ์ญ ์ํ๊ด๋ฆฌ
+ : ํ์
์๋ด ๋ฉ์์ง
+ : ์ด๋ฏธ์ง ์ฌ๋ผ์ด๋
-```curl
-curl https://asia-northeast3-heropy-api.cloudfunctions.net/api/account
- \ -X 'GET'
- \ -H 'Authorization: Bearer '
-```
+# ํ๋ฉด ๊ตฌ์ฑ
-์์ฒญ ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
+| ๋ฉ์ธํ์ด์ง | ๋ชจ๋ ์ ํ |
+| :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
+| | |
+| ์นดํ
๊ณ ๋ฆฌ๋ณ ์ํ | ์ํ ๊ฒ์ |
+| | |
+| ์ฐ๊ด ์ํ ์ถ์ฒ | ์ํ ์์ธ ํ์ด์ง |
+| | |
+| ํ์ ์ ๋ณด | ์ํ ๊ด๋ฆฌ |
+| | |
+| ์ํ ์ถ๊ฐ | ์ํ ์์ |
+| | |
+| ๊ฑฐ๋ ๋ด์ญ | ๋ด ์ ๋ณด |
+| | |
+| ๊ณ์ข ์กฐํ / ํด์ง | ๊ณ์ข ์ฐ๊ฒฐ |
+| | |
+| ๊ตฌ๋งค ๋ด์ญ | ๋ก๋ฉํ๋ฉด |
+| | |
+| ๋ก๊ทธ์ธ | ํ์๊ฐ์
|
+| | |
-- ์์
+# ๊ณ ์ฐฐ, ๋๋์
-์๋ต ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
+- ์ํ๊ด๋ฆฌ ํด
-```ts
-interface ResponseValue {
- totalBalance: number // ์ฌ์ฉ์ ๊ณ์ข ์์ก ์ดํฉ
- accounts: Bank[] // ์ฌ์ฉ์ ๊ณ์ข ์ ๋ณด ๋ชฉ๋ก
-}
+ - ํ์ ๋ด ์
๋ฌธ์๋ฅผ ๋ฐฐ๋ คํ์ฌ ์๋์ ์ผ๋ก ์ฌ์ฉ์ด ์ฌ์ด [ZUSTAND](https://zustand-demo.pmnd.rs/)๋ฅผ ์ฌ์ฉ
+ - context wrappingํ๋ ๊ณผ์ ์ด ํ์ํ์ง ์์
+ - [src/store.ts](https://github.com/howooking/KDT5-M5/blob/00c7b69fb881e9e7c8cf781f5b96cfd1c15e7b6b/src/store.ts#L1C1-L69)
-interface Bank { // ์ฌ์ฉ์ ๊ณ์ข ์ ๋ณด
- id: string // ๊ณ์ข ID
- bankName: string // ์ํ ์ด๋ฆ
- bankCode: string // ์ํ ์ฝ๋
- accountNumber: string // ๊ณ์ข ๋ฒํธ
- balance: number // ๊ณ์ข ์์ก
-}
-```
+ ```js
+ import { create } from 'zustand';
+ import { authenticate } from '@/api/authApi';
+ import { ADMINS } from '@/constants/constants';
-```json
-{
- "totalBalance": 5999900,
- "accounts": [
- {
- "id": "jQMfKla8vOIFELA3mAXv",
- "bankName": "NH๋ํ์ํ",
- "bankCode": "011",
- "accountNumber": "356-XXXX-XXXX-XX",
- "balance": 2999900
- },
- {
- "id": "wiPgsXvMAmcLw8AuRHIi",
- "bankName": "KB๊ตญ๋ฏผ์ํ",
- "bankCode": "004",
- "accountNumber": "123-XX-XXXX-XXX",
- "balance": 3000000
+ interface UserState {
+ userInfo: LocalUser | null;
+ setUser: (user: LocalUser | null) => void;
+ authMe: () => Promise;
}
- ]
-}
-```
-
-### ๊ณ์ข ์ฐ๊ฒฐ
-
-- ์ฐ๊ฒฐ๋ ๊ณ์ข ์์ก์๋ ์๋์ผ๋ก ๊ธฐ๋ณธ '3๋ฐฑ๋ง์'์ด ์ถ๊ฐ๋ฉ๋๋ค.
-- ์์ฒญํ๋ ๊ณ์ข๋ฒํธ์ ์ ํ๋ฒํธ์๋ `-` ๊ตฌ๋ถ์ด ์์ด์ผ ํฉ๋๋ค.
-
-```curl
-curl https://asia-northeast3-heropy-api.cloudfunctions.net/api/account
- \ -X 'POST'
- \ -H 'Authorization: Bearer '
-```
-
-์์ฒญ ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
-
-```ts
-interface RequestBody {
- bankCode: string // ์ฐ๊ฒฐํ ์ํ ์ฝ๋ (ํ์!)
- accountNumber: string // ์ฐ๊ฒฐํ ๊ณ์ข๋ฒํธ (ํ์!)
- phoneNumber: string // ์ฌ์ฉ์ ์ ํ๋ฒํธ (ํ์!)
- signature: boolean // ์ฌ์ฉ์ ์๋ช
(ํ์!)
-}
-```
-
-```json
-{
- "bankCode": "088",
- "accountNumber": "123456789012",
- "phoneNumber": "01012345678",
- "signature": true
-}
-```
-
-์๋ต ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
-
-```ts
-interface ResponseValue { // ์ฐ๊ฒฐ๋ ๊ณ์ข ์ ๋ณด
- id: string // ๊ณ์ข ID
- bankName: string // ์ํ ์ด๋ฆ
- bankCode: string // ์ํ ์ฝ๋
- accountNumber: string // ๊ณ์ข ๋ฒํธ
- balance: number // ๊ณ์ข ์์ก
-}
-```
-
-```json
-{
- "id": "1qRFC6Ey5VkSu6nyj5Ba",
- "bankName": "์ ํ์ํ",
- "bankCode": "088",
- "accountNumber": "123-XXX-XXXXXX",
- "balance": 3000000
-}
-```
-
-### ๊ณ์ข ํด์ง
-
-- ํด์งํ ๊ณ์ข๋ ๋ค์ ์ฐ๊ฒฐํด๋ ์์ก์ด ๋ฐ์๋์ง ์์ต๋๋ค.(๊ธฐ๋ณธ ๊ธ์ก์ผ๋ก ์ถ๊ฐ๋ฉ๋๋ค)
-
-```curl
-curl https://asia-northeast3-heropy-api.cloudfunctions.net/api/account
- \ -X 'DELETE'
- \ -H 'Authorization: Bearer '
-```
-
-์์ฒญ ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
-
-```ts
-interface RequestBody {
- accountId: string // ๊ณ์ข ID (ํ์!)
- signature: boolean // ์ฌ์ฉ์ ์๋ช
(ํ์!)
-}
-```
-
-```json
-{
- "accountId": "jQMfKla8vOIFELA3mAXv",
- "signature": true
-}
-```
-
-์๋ต ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
-
-```ts
-type ResponseValue = true // ๊ณ์ข ํด์ง ์ฒ๋ฆฌ ์ํ
-```
-
-
-
-## ์ ํ
-
-'์ ํ' ๊ด๋ จ API๋ ๊ด๋ฆฌ์ ์ ์ฉ๊ณผ ์ผ๋ฐ ์ฌ์ฉ์ ์ ์ฉ์ผ๋ก ๊ตฌ๋ถ๋ฉ๋๋ค.
-๊ณต์ฉ API๋ ์์ผ๋ ์ฃผ์ํ์ธ์!
-
-### ๋ชจ๋ ์ ํ ์กฐํ
-
-- ๊ด๋ฆฌ์ ์ ์ฉ API์
๋๋ค.
-- ์์ธ ์ ๋ณด๊ฐ ์๋ ๊ธฐ๋ณธ ์ ๋ณด์ ์ ํ ์ค๋ช
์ 100์๊น์ง๋ง ํฌํจ๋ฉ๋๋ค.
-- ์์ธ ์ ๋ณด๊ฐ ์๋ ๊ธฐ๋ณธ ์ ๋ณด์ ์ ํ ์์ธ ์ฌ์ง์ ํฌํจ๋์ง ์์ต๋๋ค.
-- ์ ํ ํ ์ธ์จ(`discountRate`)์ ์ ํ ๊ฐ๊ฒฉ๊ณผ ์ง์ ๊ด๊ณ๊ฐ ์๋ ๋จ์ ๋ฉ๋ชจ ์์ฑ์
๋๋ค.
-- ์ ํ ํ ์ธ์จ์ด ์๋ ๊ฒฝ์ฐ, `0`์ผ๋ก ํ์๋ฉ๋๋ค.
-
-```curl
-curl https://asia-northeast3-heropy-api.cloudfunctions.net/api/products
- \ -X 'GET'
- \ -H 'masterKey: true'
-```
-
-์์ฒญ ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
-
-- ์์
-
-์๋ต ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
-
-```ts
-type ResponseValue = Product[] // ๊ด๋ฆฌํ๋ ๋ชจ๋ ์ ํ์ ๋ชฉ๋ก
-
-interface Product { // ์ ํ ์ ๋ณด
- id: string // ์ ํ ID
- title: string // ์ ํ ์ด๋ฆ
- price: number // ์ ํ ๊ฐ๊ฒฉ
- description: string // ์ ํ ์ค๋ช
(์ต๋ 100์)
- tags: string[] // ์ ํ ํ๊ทธ
- thumbnail: string | null // ์ ํ ์ธ๋ค์ผ ์ด๋ฏธ์ง(URL)
- isSoldOut: boolean // ์ ํ ๋งค์ง ์ฌ๋ถ
- discountRate: number // ์ ํ ํ ์ธ์จ
-}
-```
-
-```json
-[
- {
- "id": "cFmeC7aY5KjZbBAdJE9y",
- "title": "์ผ์ฑ์ ์ ์ค๋งํธ๋ชจ๋ํฐ M7 S43AM700",
- "price": 639000,
- "description": "107.9cm(43์ธ์น) / ์์ด๋(16:9) / ํ๋ฉด / VA / 3840 x 2160(4K UHD) / ํฝ์
ํผ์น: 0.2451mm / 8ms(GTG) / 300cd / 5,00",
- "tags": [
- "๊ฐ์ ",
- "๋ชจ๋ํฐ",
- "์ปดํจํฐ"
- ],
- "thumbnail": "https://storage.googleapis.com/heropy-api/vBAK4MQdH5v195712.png",
- "isSoldOut": false,
- "discountRate": 20
- },
- {
- "id": "nbqtQvEivYwEXTDet7YM",
- "title": "MacBook Pro 16",
- "price": 3360000,
- "description": "์ญ๋ ๊ฐ์ฅ ๊ฐ๋ ฅํ MacBook Pro๊ฐ ๋ฑ์ฅํ์ต๋๋ค. ์ต์ด์ ํ๋ก์ฉ Apple Silicon์ธ M1 Pro ๋๋ M1 Max ์นฉ์ ํ์ฌํด ์์ด๊ฐ์ด ๋น ๋ฅธ ์๋๋ ๋ฌผ๋ก , ํ๊ธฐ์ ์ธ ์ฑ",
- "tags": [
- "๊ฐ์ ",
- "๋
ธํธ๋ถ",
- "์ปดํจํฐ"
- ],
- "thumbnail": "https://storage.googleapis.com/heropy-api/vIKMk_jy4Yv195256.png",
- "isSoldOut": false,
- "discountRate": 0
- }
-]
-```
-
-### ์ ์ฒด ๊ฑฐ๋(ํ๋งค) ๋ด์ญ
-
-- ๊ด๋ฆฌ์ ์ ์ฉ API์
๋๋ค.
-
-```curl
-curl https://asia-northeast3-heropy-api.cloudfunctions.net/api/products/transactions/all
- \ -X 'GET'
- \ -H 'masterKey: true'
-```
-
-์์ฒญ ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
-
-- ์์
-
-์๋ต ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
-
-```ts
-type RequestValue = TransactionDetail[] // ๋ชจ๋ ๊ฑฐ๋ ๋ด์ญ์ ๋ชฉ๋ก
-interface TransactionDetail { // ๊ฑฐ๋ ๋ด์ญ ์ ๋ณด
- detailId: string // ๊ฑฐ๋ ๋ด์ญ ID
- user: { // ๊ฑฐ๋ํ ์ฌ์ฉ์ ์ ๋ณด
- email: string
- displayName: string
- profileImg: string | null
- }
- account: { // ๊ฑฐ๋ํ ์ฌ์ฉ์์ ๊ณ์ข ์ ๋ณด
- bankName: string
- bankCode: string
- accountNumber: string
- }
- product: { // ๊ฑฐ๋ํ ์ ํ ์ ๋ณด
- productId: string
- title: string
- price: number
- description: string
- tags: string[]
- thumbnail: string | null
- discountRate: number
- }
- reservation: Reservation | null // ๊ฑฐ๋ํ ์ ํ์ ์์ฝ ์ ๋ณด
- timePaid: string // ์ ํ์ ๊ฑฐ๋ํ ์๊ฐ
- isCanceled: boolean // ๊ฑฐ๋ ์ทจ์ ์ฌ๋ถ
- done: boolean // ๊ฑฐ๋ ์๋ฃ ์ฌ๋ถ
-}
-
-interface Reservation {
- start: string // ์์ฝ ์์ ์๊ฐ
- end: string // ์์ฝ ์ข
๋ฃ ์๊ฐ
- isCanceled: boolean // ์์ฝ ์ทจ์ ์ฌ๋ถ
- isExpired: boolean // ์์ฝ ๋ง๋ฃ ์ฌ๋ถ
-}
-```
-
-```json
-[
- {
- "detailId": "dMhfxyrAupQP18OYmywy",
- "user": {
- "email": "thesecon@gmail.com",
- "displayName": "ParkYoungWoong",
- "profileImg": "https://storage.googleapis.com/heropy-api/vsLRqTlPO5v200111.png"
- },
- "account": {
- "bankName": "KB๊ตญ๋ฏผ์ํ",
- "bankCode": "004",
- "accountNumber": "123-XX-XXXX-XXX"
- },
- "product": {
- "productId": "cFmeC7aY5KjZbBAdJE9y",
- "title": "์ผ์ฑ์ ์ ์ค๋งํธ๋ชจ๋ํฐ M7 S43AM700",
- "price": 639000,
- "description": "107.9cm(43์ธ์น) / ์์ด๋(16:9) / ํ๋ฉด / VA / 3840 x 2160(4K UHD) / ํฝ์
ํผ์น: 0.2451mm / 8ms(GTG) / 300cd / 5,00",
- "tags": [
- "๊ฐ์ ",
- "๋ชจ๋ํฐ",
- "์ปดํจํฐ"
- ],
- "thumbnail": "https://storage.googleapis.com/heropy-api/vBAK4MQdH5v195712.png",
- "discountRate": 0
- },
- "reservation": null,
- "timePaid": "2021-11-07T20:01:49.100Z",
- "isCanceled": false,
- "done": false
- }
-]
-```
-
-์์ฝ ์ ๋ณด(`reservation`)๊ฐ ์๋ ๊ฒฝ์ฐ:
-
-```json
-[
- {
- "reservation": {
- "start": "2021-11-12T06:00:00.000Z",
- "end": "2021-11-12T07:00:00.000Z",
- "isCanceled": false,
- "isExpired": true
+ export const userStore = create((set) => ({
+ userInfo: localStorage.getItem('user')
+ ? JSON.parse(localStorage.getItem('user') as string)
+ : null,
+
+ setUser: (user: LocalUser | null) =>
+ set({
+ userInfo: user,
+ }),
+
+ authMe: async () => {
+ const userInfo: LocalUser | null = localStorage.getItem('user')
+ ? JSON.parse(localStorage.getItem('user') as string)
+ : null;
+ if (!userInfo) {
+ set({
+ userInfo: null,
+ });
+ return '๋ก๊ทธ์ธ์ ํด์ฃผ์ธ์.';
+ }
+ const res = await authenticate(userInfo.accessToken);
+ if (res.statusCode === 200) {
+ const user = res.data as AuthenticateResponseValue;
+ const isAdmin = ADMINS.includes(user.email);
+ set({
+ userInfo: {
+ user: user,
+ accessToken: userInfo.accessToken,
+ isAdmin,
+ },
+ });
+ localStorage.setItem(
+ 'user',
+ JSON.stringify({ user, accessToken: userInfo.accessToken, isAdmin })
+ );
+ return;
+ }
+ set({
+ userInfo: null,
+ });
+ localStorage.removeItem('user');
+ return '๋ก๊ทธ์ธ ํ์ ์ง 24์๊ฐ์ด ์ง๋์
จ์ด์! ๋ค์ ๋ก๊ทธ์ธํด์ฃผ์ธ์.';
+ },
+ }));
+
+
+ (ํ์ํ ๊ณณ์์ ์ฌ์ฉ)
+ import { userStore } from '@/store';
+ const { userInfo, setUser, authMe } = userStore();
+ ```
+
+- ๊ด๋ฆฌ์ ํ์ธ
+
+ - ๋ก๊ทธ์ธ ์ ์๋ฒ๋ก ๋ถํฐ ๋ฐ๋ ๋ฐ์ดํฐ๋ ์๋์ ๊ฐ์ผ๋ฉฐ ํด๋น ์ ๋ณด๋ก๋ ๊ด๋ฆฌ์ ์ฌ๋ถ๋ฅผ ์ ์ ์๋ค.
+
+ ```ts
+ interface ResponseValue {
+ user: {
+ email: string;
+ displayName: string;
+ profileImg: string | null;
+ };
+ accessToken: string;
}
- }
-]
-```
-
-### ๊ฑฐ๋(ํ๋งค) ๋ด์ญ ์๋ฃ/์ทจ์ ๋ฐ ํด์
-
-- ๊ด๋ฆฌ์ ์ ์ฉ API์
๋๋ค.
-- ๊ฑฐ๋ ๋ด์ญ์ ์ทจ์ํ๋ฉด, ์์ฝ๋ ๊ฐ์ด ์ทจ์๋ฉ๋๋ค.
-- ๊ฑฐ๋ ๋ด์ญ์ ์ทจ์ ํด์ ํ๋ฉด, ์์ฝ๋ ๊ฐ์ด ์ทจ์๊ฐ ํด์ ๋ฉ๋๋ค.
-
-```curl
-curl https://asia-northeast3-heropy-api.cloudfunctions.net/api/products/transactions/:detailId
- \ -X 'PUT'
- \ -H 'masterKey: true'
-```
-
-์์ฒญ ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
-
-```ts
-interface RequestBody {
- isCanceled?: boolean // ๊ฑฐ๋ ์ทจ์ ์ฌ๋ถ (์ฌ์ฉ์์ '์ ํ ๊ฑฐ๋(๊ตฌ๋งค) ์ทจ์' ์ํ์ ๊ฐ์ต๋๋ค)
- done?: boolean // ๊ฑฐ๋ ์๋ฃ ์ฌ๋ถ (์ฌ์ฉ์์ '์ ํ ๊ฑฐ๋(๊ตฌ๋งค) ํ์ ' ์ํ์ ๊ฐ์ต๋๋ค)
-}
-```
-
-```json
-{
- "isCanceled": true
-}
-```
-
-์๋ต ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
-
-
-```ts
-type ResponseValue = true // ๊ฑฐ๋ ๋ด์ญ ์๋ฃ/์ทจ์ ๋ฐ ํด์ ์ฒ๋ฆฌ ์ํ
-```
-
-### ์ ํ ์ถ๊ฐ
-
-- ๊ด๋ฆฌ์ ์ ์ฉ API์
๋๋ค.
-- ํ์ผ(์ฌ์ง)์ Base64๋ก ์์ฒญํด์ผ ํฉ๋๋ค.
-- ์ ํ ์ธ๋ค์ผ ์ฌ์ง์ 1MB ์ดํ์ฌ์ผ ํฉ๋๋ค.
-- ์ ํ ์์ธ ์ฌ์ง์ 4MB ์ดํ์ฌ์ผ ํฉ๋๋ค.
-- ์ ํ ํ ์ธ์จ(`discountRate`)์ ์ ํ ๊ฐ๊ฒฉ๊ณผ ์ง์ ๊ด๊ณ๊ฐ ์๋ ๋จ์ ๋ฉ๋ชจ ์์ฑ์
๋๋ค.
-- ์ ํ ํ ์ธ์จ์ `0`~`99` ์ฌ์ด ์ซ์๋ฅผ ์
๋ ฅํ์ธ์. ๋ง์ฝ ํ ์ธ์จ์ด '20%'์ธ ๊ฒฝ์ฐ, `20`์ผ๋ก ์
๋ ฅํด์ผ ํฉ๋๋ค.
-- ์ ํ ํ ์ธ์จ์ ์
๋ ฅํ์ง ์์ผ๋ฉด, `0`์ผ๋ก ์ ์ฉ๋ฉ๋๋ค.
-
-```js
-// ํ ์ธ ์ ๊ฐ๊ฒฉ์ ๊ณ์ฐ!
-const priceBeforeDiscount = price * 100 / (100 - discountRate)
-```
-
-```curl
-curl https://asia-northeast3-heropy-api.cloudfunctions.net/api/products
- \ -X 'POST'
- \ -H 'masterKey: true'
-```
-
-์์ฒญ ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
-
-```ts
-interface RequestBody {
- title: string // ์ ํ ์ด๋ฆ (ํ์!)
- price: number // ์ ํ ๊ฐ๊ฒฉ (ํ์!)
- description: string // ์ ํ ์์ธ ์ค๋ช
(ํ์!)
- tags?: string[] // ์ ํ ํ๊ทธ
- thumbnailBase64?: string // ์ ํ ์ธ๋ค์ผ(๋ํ) ์ฌ์ง(base64) - jpg, jpeg, webp, png, gif, svg
- photoBase64?: string // ์ ํ ์์ธ ์ฌ์ง(base64) - jpg, jpeg, webp, png, gif, svg
- discountRate?: number // ์ ํ ํ ์ธ์จ
-}
-```
-
-```json
-{
- "title": "MacBook Pro 16",
- "price": 3360000,
- "description": "์ญ๋ ๊ฐ์ฅ ๊ฐ๋ ฅํ MacBook Pro๊ฐ ๋ฑ์ฅํ์ต๋๋ค. ์ต์ด์ ํ๋ก์ฉ Apple Silicon์ธ M1 Pro ๋๋ M1 Max ์นฉ์ ํ์ฌํด ์์ด๊ฐ์ด ๋น ๋ฅธ ์๋๋ ๋ฌผ๋ก , ํ๊ธฐ์ ์ธ ์ฑ๋ฅ๊ณผ ๋๋ผ์ด ๋ฐฐํฐ๋ฆฌ ์ฌ์ฉ ์๊ฐ์ ์๋ํ์ฃ . ์ฌ๊ธฐ์ ์์ ์ ์ฌ๋ก์ก๋ Liquid Retina XDR ๋์คํ๋ ์ด, Mac ๋
ธํธ๋ถ ์ฌ์ ์ต๊ณ ์ ์นด๋ฉ๋ผ ๋ฐ ์ค๋์ค ๊ทธ๋ฆฌ๊ณ ๋ํ ๋์ ์์ด ๋ค์ํ ํฌํธ๊น์ง. ๊ธฐ์กด ๊ทธ ์ด๋ค ์นดํ
๊ณ ๋ฆฌ์๋ ์ํ์ง ์๋ ๋
ธํธ๋ถ. ์๋ก์ด MacBook Pro๋ ๊ทธ์ผ๋ง๋ก ์ผ์์
๋๋ค.",
- "tags": [
- "๊ฐ์ ",
- "๋
ธํธ๋ถ",
- "์ปดํจํฐ"
- ],
- "thumbnailBase64": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...(์๋ต)"
-}
-```
-
-์๋ต ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
-
-```ts
-interface ResponseValue { // ์ถ๊ฐํ ์ ํ์ ์์ธ ๋ด์ฉ
- id: string // ์ ํ ID
- title: string // ์ ํ ์ด๋ฆ
- price: number // ์ ํ ๊ฐ๊ฒฉ
- description: string // ์ ํ ์์ธ ์ค๋ช
- tags: string[] // ์ ํ ํ๊ทธ
- thumbnail: string | null // ์ ํ ์ธ๋ค์ผ ์ด๋ฏธ์ง(URL)
- photo: string | null // ์ ํ ์์ธ ์ด๋ฏธ์ง(URL)
- isSoldOut: boolean // ์ ํ ๋งค์ง ์ฌ๋ถ
- discountRate: number // ์ ํ ํ ์ธ์จ
-}
-```
-
-```json
-{
- "id": "nbqtQvEivYwEXTDet7YM",
- "title": "MacBook Pro 16",
- "price": 3360000,
- "description": "์ญ๋ ๊ฐ์ฅ ๊ฐ๋ ฅํ MacBook Pro๊ฐ ๋ฑ์ฅํ์ต๋๋ค. ์ต์ด์ ํ๋ก์ฉ Apple Silicon์ธ M1 Pro ๋๋ M1 Max ์นฉ์ ํ์ฌํด ์์ด๊ฐ์ด ๋น ๋ฅธ ์๋๋ ๋ฌผ๋ก , ํ๊ธฐ์ ์ธ ์ฑ๋ฅ๊ณผ ๋๋ผ์ด ๋ฐฐํฐ๋ฆฌ ์ฌ์ฉ ์๊ฐ์ ์๋ํ์ฃ . ์ฌ๊ธฐ์ ์์ ์ ์ฌ๋ก์ก๋ Liquid Retina XDR ๋์คํ๋ ์ด, Mac ๋
ธํธ๋ถ ์ฌ์ ์ต๊ณ ์ ์นด๋ฉ๋ผ ๋ฐ ์ค๋์ค ๊ทธ๋ฆฌ๊ณ ๋ํ ๋์ ์์ด ๋ค์ํ ํฌํธ๊น์ง. ๊ธฐ์กด ๊ทธ ์ด๋ค ์นดํ
๊ณ ๋ฆฌ์๋ ์ํ์ง ์๋ ๋
ธํธ๋ถ. ์๋ก์ด MacBook Pro๋ ๊ทธ์ผ๋ง๋ก ์ผ์์
๋๋ค.",
- "tags": [
- "๊ฐ์ ",
- "๋
ธํธ๋ถ",
- "์ปดํจํฐ"
- ],
- "thumbnail": "https://storage.googleapis.com/heropy-api/vIKMk_jy4Yv195256.png",
- "photo": "https://storage.googleapis.com/heropy-api/voihKb3NLGcv195257.png",
- "isSoldOut": false,
- "discountRate": 0
-}
-```
-
-### ์ ํ ์์
-
-- ๊ด๋ฆฌ์ ์ ์ฉ API์
๋๋ค.
-- ์ฌ์ฉ์์ ๊ตฌ๋งค ๋ด์ญ ํ์ธ์ ์ํด, ์ ํ์ ์ค์ ๋ก๋ ์ญ์ ํ์ง ์๊ณ ๋งค์ง(Sold Out) ์ฒ๋ฆฌํด์ผ ํฉ๋๋ค.
-- ๋งค์ง์ ๋ค์ ํด์ ํ ์ ์์ต๋๋ค.
-
-```curl
-curl https://asia-northeast3-heropy-api.cloudfunctions.net/api/products/:productId
- \ -X 'PUT'
- \ -H 'masterKey: true'
-```
-
-์์ฒญ ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
-
-```ts
-interface RequestBody {
- title?: string // ์ ํ ์ด๋ฆ
- price?: number // ์ ํ ๊ฐ๊ฒฉ
- description?: string // ์ ํ ์์ธ ์ค๋ช
- tags?: string[] // ์ ํ ํ๊ทธ
- thumbnailBase64?: string // ์ ํ ์ธ๋ค์ผ(๋ํ) ์ฌ์ง(base64) - jpg, jpeg, webp, png, gif, svg
- photoBase64?: string // ์ ํ ์์ธ ์ฌ์ง(base64) - jpg, jpeg, webp, png, gif, svg
- isSoldOut?: boolean // ์ ํ ๋งค์ง ์ฌ๋ถ
- discountRate?: number // ์ ํ ํ ์ธ์จ
-}
-```
-
-```json
-{
- "price": 1500
-}
-```
-
-์๋ต ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
-
-```ts
-interface ResponseValue { // ์์ ํ ์ ํ์ ์์ธ ๋ด์ฉ
- id: string // ์ ํ ID
- title: string // ์ ํ ์ด๋ฆ
- price: number // ์ ํ ๊ฐ๊ฒฉ
- description: string // ์ ํ ์์ธ ์ค๋ช
- tags: string[] // ์ ํ ํ๊ทธ
- thumbnail: string | null // ์ ํ ์ธ๋ค์ผ ์ด๋ฏธ์ง(URL)
- photo: string | null // ์ ํ ์์ธ ์ด๋ฏธ์ง(URL)
- isSoldOut: boolean // ์ ํ ๋งค์ง ์ฌ๋ถ
- discountRate: number // ์ ํ ํ ์ธ์จ
-}
-```
-
-```json
-{
- "id": "nbqtQvEivYwEXTDet7YM",
- "title": "MacBook Pro 16",
- "price": 1500,
- "description": "์ญ๋ ๊ฐ์ฅ ๊ฐ๋ ฅํ MacBook Pro๊ฐ ๋ฑ์ฅํ์ต๋๋ค. ์ต์ด์ ํ๋ก์ฉ Apple Silicon์ธ M1 Pro ๋๋ M1 Max ์นฉ์ ํ์ฌํด ์์ด๊ฐ์ด ๋น ๋ฅธ ์๋๋ ๋ฌผ๋ก , ํ๊ธฐ์ ์ธ ์ฑ๋ฅ๊ณผ ๋๋ผ์ด ๋ฐฐํฐ๋ฆฌ ์ฌ์ฉ ์๊ฐ์ ์๋ํ์ฃ . ์ฌ๊ธฐ์ ์์ ์ ์ฌ๋ก์ก๋ Liquid Retina XDR ๋์คํ๋ ์ด, Mac ๋
ธํธ๋ถ ์ฌ์ ์ต๊ณ ์ ์นด๋ฉ๋ผ ๋ฐ ์ค๋์ค ๊ทธ๋ฆฌ๊ณ ๋ํ ๋์ ์์ด ๋ค์ํ ํฌํธ๊น์ง. ๊ธฐ์กด ๊ทธ ์ด๋ค ์นดํ
๊ณ ๋ฆฌ์๋ ์ํ์ง ์๋ ๋
ธํธ๋ถ. ์๋ก์ด MacBook Pro๋ ๊ทธ์ผ๋ง๋ก ์ผ์์
๋๋ค.",
- "tags": [
- "๊ฐ์ ",
- "๋
ธํธ๋ถ",
- "์ปดํจํฐ"
- ],
- "thumbnail": "https://storage.googleapis.com/heropy-api/vIKMk_jy4Yv195256.png",
- "photo": "https://storage.googleapis.com/heropy-api/voihKb3NLGcv195257.png",
- "isSoldOut": false,
- "discountRate": 0
-}
-```
-
-### ์ ํ ์ญ์
-
-- ๊ด๋ฆฌ์ ์ ์ฉ API์
๋๋ค.
-
-```curl
-curl https://asia-northeast3-heropy-api.cloudfunctions.net/api/products/:productId
- \ -X 'DELETE'
- \ -H 'masterKey: true'
-```
-
-์์ฒญ ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
-
-- ์์
-
-์๋ต ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
-
-```ts
-type ResponseValue = true // ์ ํ ์ญ์ ์ฒ๋ฆฌ ์ํ
-```
-
-### ๋จ์ผ ์ ํ ์์ธ ์กฐํ
-
-- ๊ณต์ฉ API์
๋๋ค.
-
-```curl
-curl https://asia-northeast3-heropy-api.cloudfunctions.net/api/products/:productId
- \ -X 'GET'
-```
-
-์์ฒญ ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
-
-- ์์
-
-์๋ต ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
-
-```ts
-interface ResponseValue { // ์ ํ์ ์์ธ ๋ด์ฉ
- id: string // ์ ํ ID
- title: string // ์ ํ ์ด๋ฆ
- price: number // ์ ํ ๊ฐ๊ฒฉ
- description: string // ์ ํ ์์ธ ์ค๋ช
- tags: string[] // ์ ํ ํ๊ทธ
- thumbnail: string | null // ์ ํ ์ธ๋ค์ผ ์ด๋ฏธ์ง(URL)
- photo: string | null // ์ ํ ์์ธ ์ด๋ฏธ์ง(URL)
- isSoldOut: boolean // ์ ํ ๋งค์ง ์ฌ๋ถ
- reservations: Reservation[] // ์ ํ์ ๋ชจ๋ ์์ฝ ์ ๋ณด ๋ชฉ๋ก
- discountRate: number // ์ ํ ํ ์ธ์จ
-}
-
-interface Reservation {
- start: string // ์์ฝ ์์ ์๊ฐ
- end: string // ์์ฝ ์ข
๋ฃ ์๊ฐ
- isCanceled: boolean // ์์ฝ ์ทจ์ ์ฌ๋ถ
- isExpired: boolean // ์์ฝ ๋ง๋ฃ ์ฌ๋ถ
-}
-```
-
-```json
-{
- "id": "nbqtQvEivYwEXTDet7YM",
- "title": "MacBook Pro 16",
- "price": 3360000,
- "description": "์ญ๋ ๊ฐ์ฅ ๊ฐ๋ ฅํ MacBook Pro๊ฐ ๋ฑ์ฅํ์ต๋๋ค. ์ต์ด์ ํ๋ก์ฉ Apple Silicon์ธ M1 Pro ๋๋ M1 Max ์นฉ์ ํ์ฌํด ์์ด๊ฐ์ด ๋น ๋ฅธ ์๋๋ ๋ฌผ๋ก , ํ๊ธฐ์ ์ธ ์ฑ๋ฅ๊ณผ ๋๋ผ์ด ๋ฐฐํฐ๋ฆฌ ์ฌ์ฉ ์๊ฐ์ ์๋ํ์ฃ . ์ฌ๊ธฐ์ ์์ ์ ์ฌ๋ก์ก๋ Liquid Retina XDR ๋์คํ๋ ์ด, Mac ๋
ธํธ๋ถ ์ฌ์ ์ต๊ณ ์ ์นด๋ฉ๋ผ ๋ฐ ์ค๋์ค ๊ทธ๋ฆฌ๊ณ ๋ํ ๋์ ์์ด ๋ค์ํ ํฌํธ๊น์ง. ๊ธฐ์กด ๊ทธ ์ด๋ค ์นดํ
๊ณ ๋ฆฌ์๋ ์ํ์ง ์๋ ๋
ธํธ๋ถ. ์๋ก์ด MacBook Pro๋ ๊ทธ์ผ๋ง๋ก ์ผ์์
๋๋ค.",
- "tags": [
- "๊ฐ์ ",
- "๋
ธํธ๋ถ",
- "์ปดํจํฐ"
- ],
- "thumbnail": "https://storage.googleapis.com/heropy-api/vIKMk_jy4Yv195256.png",
- "photo": "https://storage.googleapis.com/heropy-api/voihKb3NLGcv195257.png",
- "isSoldOut": false,
- "reservations": [],
- "discountRate": 0
-}
-```
-
-์์ฝ ์ ๋ณด(`reservation`)๊ฐ ์๋ ๊ฒฝ์ฐ:
-
-```json
-{
- "reservations": [
- {
- "reservation": {
- "start": "2021-11-12T06:00:00.000Z",
- "end": "2021-11-12T07:00:00.000Z",
- "isCanceled": false,
- "isExpired": true
+ ```
+
+ - ๋ฐ๋ผ์ ํด๋ผ์ด์ธํธ ๋จ์์ ๊ด๋ฆฌ์ ์ฌ๋ถ๋ฅผ ํ์ธํ๊ณ isAdmin property๋ฅผ ์ถ๊ฐํ์ฌ ์ ์ญ์ํ์ ๋ก์ปฌ์ ์ฅ์์ ์ ์ฅํ๋ค.
+
+ ```ts
+ interface LocalUser {
+ user: {
+ email: string;
+ displayName: string;
+ profileImg: string | null;
+ };
+ accessToken: string;
+ isAdmin: boolean;
+ }
+ ```
+
+ - ์ด ๋ฐฉ๋ฒ์ ๋ณด์์ ์ํํ์ง๋ง ๋ค์๊ณผ ๊ฐ์ ๋์ ์ ๋ต์ ์ทจํ ์ ์๋ค.
+
+ - ๋น๊ฑด์ ํ ์ฌ์ฉ์๊ฐ local storage์ ์ ๊ทผํ์ฌ isAdmin์ true๋ก ๋ฐ๊ฟ ๊ฒฝ์ฐ
๐ ๊ด๋ฆฌ์๋ง ์ ๊ทผ ํ ์ ์๋ route ๋ถ๊ธฐ์ ์ ์ธ์ฆ api๋ฅผ ์ฌ์ฉํ์ฌ ์ฌ์ฉ์์ ์ ์์ ํ์ธํ๋ค.
+ - [src/routes/admin/Admin.tsx](https://github.com/howooking/KDT5-M5/blob/0172a31077634c42139005c52c4e62156e3ab2ba/src/routes/admin/Admin.tsx#L1C1-L26)
+
+ ```js
+ export default function Admin() {
+ const { authMe } = userStore();
+ useEffect(() => {
+ async function auth() {
+ const errorMessage = await authMe();
+ if (errorMessage) {
+ toast.error(errorMessage, { id: 'authMe' });
+ }
+ }
+ auth();
+ }, []);
+ return (
+ <>
+
+
+ >
+ );
}
+ ```
+
+ - ๋น๊ฑด์ ํ ์ฌ์ฉ์๊ฐ ํ์ผ์ ์ ์ฅ๋ ๊ด๋ฆฌ์ ์ด๋ฉ์ผ ์ฃผ์๋ฅผ ๋ณด๋ ๊ฒฝ์ฐ
๐ ๊ด๋ฆฌ์์ ๋ฉ์ผ ์ฃผ์๋ฅผ ์๋๋ผ๋ ๋น๋ฐ๋ฒํธ๋ ๋ชจ๋ฅด๊ธฐ ๋๋ฌธ์ ๊ด์ฐฎ๋ค. ๊ด๋ฆฌ์ ๋ฉ์ผ ์ฃผ์๋ฅผ ํ๊ฒฝ๋ณ์์ ์ ์ฅํ๋ ๋ฐฉ๋ฒ๋ ์๋ค.
+
+- ๋ถ์กฑํ ์ํ ์ ๋ณด
+
+ - ์ํ์ ์คํค๋ง๋ ์๋์ ๊ฐ์ผ๋ฉฐ ๋ณธ ํ๋ก์ ํธ์์ ํ์ํ 'category'์ 'brand' ํญ๋ชฉ์ด ์๋ค.
+ ```ts
+ interface Product {
+ id: string;
+ title: string;
+ price: number;
+ description: string;
+ tags: string[];
+ thumbnail: string | null;
+ photo: string | null;
+ isSoldOut: boolean;
+ discountRate: number;
}
- ]
-}
-```
+ ```
+ - tags ํญ๋ชฉ์์ ๋ฐฐ์ด์ ์ฒซ๋ฒ์งธ ์์๋ฅผ category, ๋๋ฒ์งธ ์์๋ฅผ brand๋ก ์ง์ ํ์๋ค.
-### ์ ํ ๊ฒ์
+ ```js
+ tags: ['soccer', 'nike'],
+ ```
-- ์ฌ์ฉ์ ์ ์ฉ API์
๋๋ค.
-- ์ ํ ์ด๋ฆ๊ณผ ํ๊ทธ๋ฅผ ๋์์ ๊ฒ์ํ ์ ์๊ณ , 'And'(๊ฒ์ํ ์ด๋ฆ๊ณผ ํ๊ทธ ๋ชจ๋ ํฌํจ๋ ์ ํ) ์กฐ๊ฑด์ผ๋ก ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํฉ๋๋ค.
-- ์ ํ ์ด๋ฆ๊ณผ ํ๊ทธ ๋ชจ๋ ํฌํจํ์ง ์์ผ๋ฉด, ๋ชจ๋ ์ ํ์ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํฉ๋๋ค.
-- ์ ํ์ ๊ธฐ๋ณธ ์ ๋ณด๋ง ๋ฐํํฉ๋๋ค.
-- ๋งค์ง๋ ์ ํ์ ๊ฒ์๋์ง ์์ต๋๋ค.
+- ๋ผ์ฐํธ ๋ณดํธ
-```curl
-curl https://asia-northeast3-heropy-api.cloudfunctions.net/api/products/search
- \ -X 'POST'
-```
+ - ๋ก๊ทธ์ธ ์ํ, ๊ด๋ฆฌ์ ์ฌ๋ถ์ ๋ฐ๋ผ์ ์ ๊ทผํ ์ ์๋ ํ์ด์ง๋ฅผ ์ ํํด์ผ ํ๋ค.
+ - ProdtectedRoute์์ ์ ์ญ User ์ํ์ adminRequired props ์์ฑ์ ๋ฐ๋ผ์ ์ ๊ทผ์ ์ ํํ๊ฒ ํ์๋ค.
+ - [src/routes/ProtectedRoute.tsx](https://github.com/howooking/KDT5-M5/blob/0172a31077634c42139005c52c4e62156e3ab2ba/src/routes/ProtectedRoute.tsx#L1-L22)
-์์ฒญ ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
+ ```js
+ import { Navigate } from 'react-router-dom';
+ import { userStore } from '@/store';
-```ts
-interface RequestBody {
- searchText?: string // ๊ฒ์ํ ์ ํ ์ด๋ฆ
- searchTags?: string[] // ๊ฒ์ํ ์ ํ ํ๊ทธ
-}
-```
+ type ProtectedRouteProps = {
+ element: React.ReactNode,
+ adminRequired?: boolean,
+ };
-```json
-{
- "searchText": "์ผ์ฑ์ ์",
- "searchTags": ["๊ฐ์ "]
-}
-```
-
-์๋ต ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
+ export default function ProtectedRoute({
+ element,
+ adminRequired,
+ }: ProtectedRouteProps) {
+ const { userInfo } = userStore();
-```ts
-type ResponseValue = Product[] // ๊ด๋ฆฌํ๋ ๋ชจ๋ ์ ํ์ ๋ชฉ๋ก
-
-interface Product { // ์ ํ ์ ๋ณด
- id: string // ์ ํ ID
- title: string // ์ ํ ์ด๋ฆ
- price: number // ์ ํ ๊ฐ๊ฒฉ
- description: string // ์ ํ ์ค๋ช
(์ต๋ 100์)
- tags: string[] // ์ ํ ํ๊ทธ
- thumbnail: string | null // ์ ํ ์ธ๋ค์ผ ์ด๋ฏธ์ง(URL)
- discountRate: number // ์ ํ ํ ์ธ์จ
-}
-```
-
-```json
-[
- {
- "id": "cFmeC7aY5KjZbBAdJE9y",
- "title": "์ผ์ฑ์ ์ ์ค๋งํธ๋ชจ๋ํฐ M7 S43AM700",
- "price": 639000,
- "description": "107.9cm(43์ธ์น) / ์์ด๋(16:9) / ํ๋ฉด / VA / 3840 x 2160(4K UHD) / ํฝ์
ํผ์น: 0.2451mm / 8ms(GTG) / 300cd / 5,00",
- "tags": [
- "๊ฐ์ ",
- "๋ชจ๋ํฐ",
- "์ปดํจํฐ"
- ],
- "thumbnail": "https://storage.googleapis.com/heropy-api/vBAK4MQdH5v195712.png",
- "discountRate": 0
- }
-]
-```
-
-### ์ ํ ๊ฑฐ๋(๊ตฌ๋งค) ์ ์ฒญ
-
-- ์ฌ์ฉ์ ์ ์ฉ API์
๋๋ค.
-- ๊ฑฐ๋(๊ตฌ๋งค) ์ ์ฒญ์ ์ฐ๊ฒฐ๋ ๊ณ์ข์์ ๊ฒฐ์ ๋ฉ๋๋ค.
-- ๊ฒฐ์ ํ ๊ณ์ข(ID)๋ฅผ ๊ผญ ์ ํํด์ผ ํฉ๋๋ค.(`๊ณ์ข ๋ชฉ๋ก ๋ฐ ์์ก ์กฐํ` API๋ฅผ ์ฌ์ฉํ์ธ์)
-- ์ ํํ ๊ณ์ข์ ์์ก๋ณด๋ค ๊ฒฐ์ ๊ธ์ก์ด ํฌ๋ฉด ๊ฒฐ์ ๊ฐ ์ฒ๋ฆฌ๋์ง ์์ต๋๋ค.(์๋ฌ ๋ฐํ)
-
-```curl
-curl https://asia-northeast3-heropy-api.cloudfunctions.net/api/products/buy
- \ -X 'POST'
- \ -H 'Authorization: Bearer '
-```
-
-์์ฒญ ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
-
-```ts
-interface RequestBody {
- productId: string // ๊ฑฐ๋ํ ์ ํ ID (ํ์!)
- accountId: string // ๊ฒฐ์ ํ ์ฌ์ฉ์ ๊ณ์ข ID (ํ์!)
- reservation?: { // ์์ฝ ์ ๋ณด(์์ฝ ์์คํ
์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ๋ง ํ์)
- start: string // ์์ฝ ์์ ์๊ฐ(ISO)
- end: string // ์์ฝ ์ข
๋ฃ ์๊ฐ(ISO)
- }
-}
-```
-
-```js
-const isoString = new Date().toISOString()
-```
-
-```json
-{
- "productId": "nbqtQvEivYwEXTDet7YM",
- "accountId": "Mq2KKHk8vlmr6Xkg58Fa",
- "reservation": {
- "start": "2021-11-12T06:00:00.000Z",
- "end": "2021-11-12T07:00:00.000Z"
- }
-}
-```
-
-์๋ต ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
-
-```ts
-type ResponseValue = true // ๊ฑฐ๋ ์ ์ฒญ ์ฒ๋ฆฌ ์ฌ๋ถ
-```
-
-### ์ ํ ๊ฑฐ๋(๊ตฌ๋งค) ์ทจ์
-
-- ์ฌ์ฉ์ ์ ์ฉ API์
๋๋ค.
-- '๊ฑฐ๋ ์ทจ์'์ ๊ฒฐ์ ํ ์ฌ์ฉ์ ๊ณ์ข๋ก ๊ธ์ก์ด ํ๋ถ๋ฉ๋๋ค.
-
-```curl
-curl https://asia-northeast3-heropy-api.cloudfunctions.net/api/products/cancel
- \ -X 'POST'
- \ -H 'Authorization: Bearer '
-```
-
-์์ฒญ ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
-
-```ts
-interface RequestBody {
- detailId: string // ์ทจ์ํ ์ ํ์ ๊ฑฐ๋ ๋ด์ญ ID
-}
-```
-
-```json
-{
- "detailId": "dMhfxyrAupQP18OYmywy"
-}
-```
-
-์๋ต ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
-
-```ts
-type ResponseValue = true // ๊ฑฐ๋ ์ทจ์ ์ฒ๋ฆฌ ์ฌ๋ถ
-```
-
-### ์ ํ ๊ฑฐ๋(๊ตฌ๋งค) ํ์
-
-- ์ฌ์ฉ์ ์ ์ฉ API์
๋๋ค.
-- '๊ฑฐ๋(๊ตฌ๋งค) ํ์ ' ํ์๋ '๊ฑฐ๋ ์ทจ์'๋ฅผ ํ ์ ์์ต๋๋ค.
-
-```curl
-curl https://asia-northeast3-heropy-api.cloudfunctions.net/api/products/ok
- \ -X 'POST'
- \ -H 'Authorization: Bearer '
-```
-
-์์ฒญ ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
-
-```ts
-interface RequestBody {
- detailId: string // ๊ฑฐ๋(๊ตฌ๋งค) ํ์ ํ ์ ํ์ ๊ฑฐ๋ ๋ด์ญ ID
-}
-```
-
-```json
-{
- "detailId": "dMhfxyrAupQP18OYmywy"
-}
-```
-
-์๋ต ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
-
-```ts
-type ResponseValue = true // ๊ฑฐ๋(๊ตฌ๋งค) ํ์ ์ฒ๋ฆฌ ์ฌ๋ถ
-```
-
-### ์ ํ ์ ์ฒด ๊ฑฐ๋(๊ตฌ๋งค) ๋ด์ญ
-
-- ์ฌ์ฉ์ ์ ์ฉ API์
๋๋ค.
-- ๊ฑฐ๋ ๋ด์ญ์ ๊ธฐ๋ณธ ์ ๋ณด๋ง ํฌํจ๋ฉ๋๋ค.
-
-```curl
-curl https://asia-northeast3-heropy-api.cloudfunctions.net/api/products/transactions/details
- \ -X 'GET'
- \ -H 'Authorization: Bearer '
-```
-
-์์ฒญ ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
-
-- ์์
-
-์๋ต ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
-
-```ts
-type RequestValue = TransactionDetail[] // ๋ชจ๋ ๊ฑฐ๋ ๋ด์ญ์ ๋ชฉ๋ก
-
-interface TransactionDetail { // ๊ฑฐ๋ ๋ด์ญ ์ ๋ณด
- detailId: string // ๊ฑฐ๋ ๋ด์ญ ID
- product: { // ๊ฑฐ๋ํ ์ ํ ์ ๋ณด
- productId: string
- title: string
- price: number
- description: string
- tags: string[]
- thumbnail: string | null
- discountRate: number // ์ ํ ํ ์ธ์จ
- }
- reservation: Reservation | null // ๊ฑฐ๋ํ ์ ํ์ ์์ฝ ์ ๋ณด
- timePaid: string // ์ ํ์ ๊ฑฐ๋ํ ์๊ฐ
- isCanceled: boolean // ๊ฑฐ๋ ์ทจ์ ์ฌ๋ถ
- done: boolean // ๊ฑฐ๋ ์๋ฃ ์ฌ๋ถ
-}
-
-interface Reservation {
- start: string // ์์ฝ ์์ ์๊ฐ
- end: string // ์์ฝ ์ข
๋ฃ ์๊ฐ
- isCanceled: boolean // ์์ฝ ์ทจ์ ์ฌ๋ถ
- isExpired: boolean // ์์ฝ ๋ง๋ฃ ์ฌ๋ถ
-}
-```
-
-```json
-[
- {
- "detailId": "9jAoagzrZBkSWI5NctEB",
- "product": {
- "productId": "nbqtQvEivYwEXTDet7YM",
- "title": "MacBook Pro 16",
- "price": 3360000,
- "description": "์ญ๋ ๊ฐ์ฅ ๊ฐ๋ ฅํ MacBook Pro๊ฐ ๋ฑ์ฅํ์ต๋๋ค. ์ต์ด์ ํ๋ก์ฉ Apple Silicon์ธ M1 Pro ๋๋ M1 Max ์นฉ์ ํ์ฌํด ์์ด๊ฐ์ด ๋น ๋ฅธ ์๋๋ ๋ฌผ๋ก , ํ๊ธฐ์ ์ธ ์ฑ",
- "tags": [
- "๊ฐ์ ",
- "๋
ธํธ๋ถ",
- "์ปดํจํฐ"
- ],
- "thumbnail": "https://storage.googleapis.com/heropy-api/vIKMk_jy4Yv195256.png",
- "discountRate": 0
- },
- "reservation": null,
- "timePaid": "2021-11-07T20:17:32.112Z",
- "isCanceled": true,
- "done": false
- },
- {
- "detailId": "dMhfxyrAupQP18OYmywy",
- "product": {
- "productId": "cFmeC7aY5KjZbBAdJE9y",
- "title": "์ผ์ฑ์ ์ ์ค๋งํธ๋ชจ๋ํฐ M7 S43AM700",
- "price": 639000,
- "description": "107.9cm(43์ธ์น) / ์์ด๋(16:9) / ํ๋ฉด / VA / 3840 x 2160(4K UHD) / ํฝ์
ํผ์น: 0.2451mm / 8ms(GTG) / 300cd / 5,00",
- "tags": [
- "๊ฐ์ ",
- "๋ชจ๋ํฐ",
- "์ปดํจํฐ"
- ],
- "thumbnail": "https://storage.googleapis.com/heropy-api/vBAK4MQdH5v195712.png",
- "discountRate": 0
- },
- "reservation": {
- "start": "2021-11-12T06:00:00.000Z",
- "end": "2021-11-12T07:00:00.000Z",
- "isCanceled": false,
- "isExpired": true
- },
- "timePaid": "2021-11-07T20:01:49.100Z",
- "isCanceled": false,
- "done": true
- }
-]
-```
-
-### ๋จ์ผ ์ ํ ์์ธ ๊ฑฐ๋(๊ตฌ๋งค) ๋ด์ญ
-
-- ์ฌ์ฉ์ ์ ์ฉ API์
๋๋ค.
-
-```curl
-curl https://asia-northeast3-heropy-api.cloudfunctions.net/api/products/transactions/detail
- \ -X 'POST'
- \ -H 'Authorization: Bearer '
-```
-
-์์ฒญ ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
-
-```ts
-interface RequestBody {
- detailId: string // ์์ธ ๋ด์ฉ์ ํ์ธํ ๊ฑฐ๋(๊ตฌ๋งค) ๋ด์ญ ID
-}
-```
-
-```json
-{
- "detailId": "dMhfxyrAupQP18OYmywy"
-}
-```
-
-์๋ต ๋ฐ์ดํฐ ํ์
๋ฐ ์์:
-
-```ts
-interface TransactionDetail { // ์์ธ ๊ฑฐ๋ ์ ๋ณด
- detailId: string // ๊ฑฐ๋ ๋ด์ญ ID
- account: { // ๊ฑฐ๋ํ ์ฌ์ฉ์์ ๊ณ์ข ์ ๋ณด
- bankName: string
- bankCode: string
- accountNumber: string
- }
- product: { // ๊ฑฐ๋ํ ์ ํ ์ ๋ณด
- productId: string
- title: string
- price: number
- description: string
- tags: string[]
- thumbnail: string | null
- photo: string | null
- discountRate: number // ์ ํ ํ ์ธ์จ
- }
- reservation: Reservation | null // ๊ฑฐ๋ํ ์ ํ์ ์์ฝ ์ ๋ณด
- timePaid: string // ์ ํ์ ๊ฑฐ๋ํ ์๊ฐ
- isCanceled: boolean // ๊ฑฐ๋ ์ทจ์ ์ฌ๋ถ
- done: boolean // ๊ฑฐ๋ ์๋ฃ ์ฌ๋ถ
-}
-
-interface Reservation {
- start: string // ์์ฝ ์์ ์๊ฐ
- end: string // ์์ฝ ์ข
๋ฃ ์๊ฐ
- isCanceled: boolean // ์์ฝ ์ทจ์ ์ฌ๋ถ
- isExpired: boolean // ์์ฝ ๋ง๋ฃ ์ฌ๋ถ
-}
-```
-
-```json
-{
- "detailId": "dMhfxyrAupQP18OYmywy",
- "account": {
- "bankName": "KB๊ตญ๋ฏผ์ํ",
- "bankCode": "004",
- "accountNumber": "123-XX-XXXX-XXX"
- },
- "product": {
- "productId": "cFmeC7aY5KjZbBAdJE9y",
- "title": "์ผ์ฑ์ ์ ์ค๋งํธ๋ชจ๋ํฐ M7 S43AM700",
- "price": 639000,
- "description": "107.9cm(43์ธ์น) / ์์ด๋(16:9) / ํ๋ฉด / VA / 3840 x 2160(4K UHD) / ํฝ์
ํผ์น: 0.2451mm / 8ms(GTG) / 300cd / 5,000:1 / ์ต๋ ์ฃผ์ฌ์จ: 60Hz / HDMI 2.0 / USB Type-C / ํ๋ฆฌ์ปค ํ๋ฆฌ / ๋ธ๋ฃจ๋ผ์ดํธ ์ฐจ๋จ / ๊ฒ์๋ชจ๋ ์ง์ / ์คํผ์ปค / ๋ฆฌ๋ชจ์ปจ / USBํ๋ธ / Wi-Fi(๋ฌด์ ) / ์ค๋งํธTV / ๋ธ๋ฃจํฌ์ค / ํธํธ(์ํ) / 200 x 200mm / HDR / HDR10 / 10.6kg ๊ธฐํ์ ์ฐจ์ธ๋ ๊ฒ์ ๋ผ์ดํ PS5 ๋งค๋ ฅ๋ถ์ ๊ด๋ จ๊ธฐ์ฌ ํ์๋, 43์ธ์น 4K UHD ์ค๋งํธ ๋ชจ๋ํฐ โ์ผ์ฑ์ ์ M7 S43AM700โ ์ถ์ ๋ฐ ํ ์ธ ํ์ฌ ์ฌ์ฉ๊ธฐ ์ผ์ฑ ์ค๋งํธ๋ชจ๋ํฐ m7 s43am700",
- "tags": [
- "๊ฐ์ ",
- "๋ชจ๋ํฐ",
- "์ปดํจํฐ"
- ],
- "thumbnail": "https://storage.googleapis.com/heropy-api/vBAK4MQdH5v195712.png",
- "photo": "https://storage.googleapis.com/heropy-api/vVLP-ox_zSDv195712.jpg",
- "discountRate": 0
- },
- "reservation": null,
- "timePaid": "2021-11-07T20:01:49.100Z",
- "isCanceled": false,
- "done": true
-}
-```
+ if (!userInfo) {
+ return ;
+ }
+ if (adminRequired && !userInfo.isAdmin) {
+ return ;
+ }
+ return <>{element}>;
+ }
+ ```
+
+- ์ํ์ ๋ฐ๋ฅธ UI์ ๋์ ๋ณํ
+ - ๊ด๋ฆฌ์
+ - ๊ด๋ฆฌ์์ ๊ฒฝ์ฐ Navbar์ "๊ด๋ฆฌ์" ๋ฒํผ์ด ๋ณด์ธ๋ค.
+ - ๊ด๋ฆฌ์์ ๊ฒฝ์ฐ ๊ด๋ฆฌ์ ํ์ด์ง์ ์ ๊ทผ ํ ์ ์๋ค.
+ - ๊ด๋ฆฌ์์ ๊ฒฝ์ฐ ๋ก๊ทธ์ธ์ "์ฃผ์ธ๋ ์ค์
จ์ต๋๋ค" ์๋ฆผ ๋ฉ์ธ์ง๊ฐ ์ถ๋ ฅ๋๋ค.
+ - ๊ด๋ฆฌ์์ ๊ฒฝ์ฐ ์ํ ์์ธ ํ์ด์ง์์ ์ํ ์์ ์์ด์ฝ์ด ๋ณด์ธ๋ค.
+ - ๋ก๊ทธ์ธ
+ - ๋ก๊ทธ์ธํ์ง ์์ ๊ฒฝ์ฐ ๊ฐ์ธ์ ๋ณด ํ์ด์ง์ ์ ๊ทผํ ์ ์๋ค.
+ - ๋ก๊ทธ์ธํ์ง ์์ ๊ฒฝ์ฐ ์ํ ์์ธ ํ์ด์ง์์ ๊ฒฐ์ ๋ฒํผ ๋์ "๋ก๊ทธ์ธ ํ๋ฌ๊ฐ๊ธฐ" ๋ฒํผ์ด ๋ณด์ธ๋ค.
+ - ๋ก๊ทธ์ธ์ ํ ๊ฒฝ์ฐ login ํ์ด์ง์ signup ํ์ด์ง์ ์ ๊ทผํ ์ ์๋ค.
+ - ๊ณ์ข
+ - ๊ณ์ข๋ฅผ ํ๋๋ ๋ฑ๋กํ์ง ์์ ๊ฒฝ์ฐ ์ํ ์์ธ ํ์ด์ง์์ "์ํด๋ฆฐ ๊ฐํธ ๊ฒฐ์ " ๋ฒํผ ๋์ "๊ณ์ข ๋ฑ๋กํ๋ฌ ๊ฐ๊ธฐ" ๋ฒํผ์ด ๋ณด์ธ๋ค.
+ - ๊ณ์ข ์ฐ๊ฒฐ ํ์ด์ง์์ ์ํ ์ ํ์ ์
๋ ฅ์ฐฝ์ ํด๋น ์ํ์ ๊ณ์ข๋ฒํธ์๋ฅผ ์๋ ค์ฃผ๋ฉฐ ๊ทธ ์๋ฅผ input ์์์ maxLength๋ก ์ง์ ํ๋ค.
+ - ์ํ
+ - ์ํ ์์ธ ํ์ด์ง ํ๋จ์ ํด๋น ์ํ๊ณผ ๊ฐ์ ์นดํ
๊ณ ๋ฆฌ์ ์๋ ์ ํ 10๊ฐ๋ฅผ ๋๋ค์ผ๋ก ์ถ์ฒํ๋ค.
+ - ์ํ์ด ๋งค์ง์ธ ๊ฒฝ์ฐ "SOLD OUT" ์ด๋ฏธ์ง๋ฅผ ์ํ ์ด๋ฏธ์ง ์์ ํ์ํ๋ค.
+ - ์ํ์ด ๋งค์ง์ธ ๊ฒฝ์ฐ "์
๊ณ ์๋ฆผ" ๋ฒํผ์ด ๋ณด์ธ๋ค.
+
+- ์ฒซ ํ์
ํ๋ก์ ํธ
+ - ์ฒซ ํํ๋ก์ ํธ๋ค ๋ณด๋ ์งํ๊ณผ์ ์์ ์์ฌ์ ๋ ๋ถ๋ถ์ด ๋ง์์
+ - ๋ธ๋์น ์ ๋ต
+ - 5๋ช
์ด ๊ฐ์ ๋งก์ ๊ธฐ๋ฅ์ branch๋ฅผ ์์ฑํ์ฌ develope ๋ธ๋์น์ mergeํ๊ณ ์ต์ข
์ ์ผ๋ก main ๋ธ๋์น์ mergeํ๋ ๋ฐฉ์์ผ๋ก ์งํ
+ - ์ด ๋ณด๋ค๋ git hub์์ pull request๋ฅผ ํ๊ณ ๋ค๊ฐ์ด ๋ฆฌ๋ทฐ๋ฅผ ํ ํ mergeํ๋ ๋ฐฉ์์ด ๋ฐ๋์งํ๋ค.
+ - ์ ๊ธฐ์ ์ผ๋ก develope ๋ธ๋ ์น๋ฅผ pullํด์ผ ํ๊บผ๋ฒ์ ๋ง์ ์์ conflict๊ฐ ๋ฐ์ํ๋ ๊ฒ์ ๋ฐฉ์งํ ์ ์๋ค.
+ - commit ๋จ์ & commit message
+ - commit์ ๋จ์๋ ๊ธฐ๋ฅ ๋จ์์ฌ์ผ ํ๋ค.
+ - commit message๋ฅผ ์ ๊ธฐ ํ๋ค๋ค๋ฉด ํด๋น commit์ ๋๋ฌด ๋ง์ ๊ธฐ๋ฅ์ ๋ด๊ณ ์์ ๊ฐ๋ฅ์ฑ์ด ๋๋ค.
+ - commit ๋จ์๋ ํ์ผ ๋จ์๊ฐ ์๋์ฌ๋ ๋๋ค. ์ค ๋จ์๋ก commit์ด ๊ฐ๋ฅํ๋ค.
+ - 5๋ช
์ commit message๊ฐ ์ ๊ฐ๊ฐ์ด๋ผ ๋ค๋ฅธ ์ฌ๋์ commit์ ํ๋ฒ์ ์ดํดํ๊ธฐ ์ด๋ ค์ ๋ค.
+ - ํ์
์ ์งํํ๊ธฐ ์ commit ๊ท์น์ ๋ฐ๋์ ์ธ์ฐ๊ณ ์์ํด์ผ ํจ
+
+
+# ๋๋ ํ ๋ฆฌ ๊ตฌ์กฐ
+
+```
+KDT5-M5
+โฃ public
+โฃ src
+โ โฃ api
+โ โ โฃ adminApi.ts
+โ โ โฃ authApi.ts
+โ โ โฃ bankApi.ts
+โ โ โ transactionApi.ts
+โ โฃ components
+โ โ โฃ product
+โ โ โ โฃ ProductBar.tsx
+โ โ โ โฃ ProductCard.tsx
+โ โ โ โฃ ProductSection.tsx
+โ โ โ โ ProductSortOptions.tsx
+โ โ โฃ ui
+โ โ โ โฃ Breadcrumbs.tsx
+โ โ โ โฃ Button.tsx
+โ โ โ โฃ CrazyLoading.tsx
+โ โ โ โฃ ImageUpload.tsx
+โ โ โ โฃ Input.tsx
+โ โ โ โฃ LoadingSpinner.tsx
+โ โ โ โฃ ProfileImage.tsx
+โ โ โ โฃ SectionTitle.tsx
+โ โ โ โฃ Select.tsx
+โ โ โ โ Skeleton.tsx
+โ โ โฃ Footer.tsx
+โ โ โฃ ImageSlider.tsx
+โ โ โฃ Layout.tsx
+โ โ โฃ Navbar.tsx
+โ โ โฃ Search.tsx
+โ โ โฃ SingleUser.tsx
+โ โ โ SubNavbar.tsx
+โ โฃ constants
+โ โ โฃ constants.ts
+โ โ โ library.ts
+โ โฃ lib
+โ โ โฃ ceilPrice.ts
+โ โ โ time.ts
+โ โฃ routes
+โ โ โฃ admin
+โ โ โ โฃ AddProduct.tsx
+โ โ โ โฃ Admin.tsx
+โ โ โ โฃ AdminClients.tsx
+โ โ โ โฃ AdminProducts.tsx
+โ โ โ โฃ AllTransactions.tsx
+โ โ โ โ EditProduct.tsx
+โ โ โฃ myAccount
+โ โ โ โฃ bank
+โ โ โ โ โฃ BankAccounts.tsx
+โ โ โ โ โ ConnectBankAccount.tsx
+โ โ โ โฃ ChangeName.tsx
+โ โ โ โฃ ChangePassword.tsx
+โ โ โ โฃ Info.tsx
+โ โ โ โฃ Login.tsx
+โ โ โ โฃ LogoutNeededRoute.tsx
+โ โ โ โฃ MyAccount.tsx
+โ โ โ โฃ OrderDetail.tsx
+โ โ โ โฃ OrderList.tsx
+โ โ โ โ SignUp.tsx
+โ โ โฃ Home.tsx
+โ โ โฃ Login.tsx
+โ โ โฃ LogoutNeededRoute.tsx
+โ โ โฃ NotFound.tsx
+โ โ โฃ ProductDetail.tsx
+โ โ โฃ Products.tsx
+โ โ โฃ ProtectedRoute.tsx
+โ โ โฃ SearchProducts.tsx
+โ โ โ SignUp.tsx
+โ โฃ App.tsx
+โ โฃ index.css
+โ โฃ main.tsx
+โ โฃ store.ts
+โ โ vite-env.d.ts
+โฃ .eslintrc.cjs
+โฃ .gitignore
+โฃ .prettierrc
+โฃ custom.d.ts
+โฃ index.html
+โฃ package-lock.json
+โฃ package.json
+โฃ postcss.config.js
+โฃ README.md
+โฃ tailwind.config.js
+โฃ tsconfig.json
+โฃ tsconfig.node.json
+โ vite.config.ts
+ ```
\ No newline at end of file
diff --git a/custom.d.ts b/custom.d.ts
new file mode 100644
index 00000000..160c2e89
--- /dev/null
+++ b/custom.d.ts
@@ -0,0 +1,228 @@
+// !!Auth๊ด๋ จ ํ์
๋ค
+
+// ๋ก๊ทธ์ธ ์์ฒญ์ or ํ์๊ฐ์
์์ฒญ์ ์ฑ๊ณตํ๋ฉด ์๋ฒ์์ ์ค๋ ์ ์ ธ ๋ฐ์ดํฐ
+interface UserResponseValue {
+ user: {
+ email: string;
+ displayName: string;
+ profileImg: string | null;
+ };
+ accessToken: string;
+}
+
+// ์์ ์ ์ฑ๊ณตํ๋ฉด ์๋ฒ์์ ๋ณด๋ด์ฃผ๋ ์ ์ ธ๊ฐ
+interface UpdatedUserResponseValue {
+ email: string;
+ displayName: string;
+ profileImg: string | null;
+}
+
+interface LocalUser {
+ user: {
+ email: string;
+ displayName: string;
+ profileImg: string | null;
+ };
+ accessToken: string | null;
+ isAdmin: boolean;
+}
+
+// !! ์ด๋๋ฏผ ๊ด๋ฆฌ ๊ด๋ จ api
+
+// ์ด๋๋ฏผ์์ ์ฌ์ฉ์๋ค ์ ๋ณด๋ฅผ ์กฐํํ ๋ ์ค๋ ์ฌ์ฉ์ ์ ๋ณด ํ์
+interface Client {
+ email: string; // ์ฌ์ฉ์ ์์ด๋
+ displayName: string; // ์ฌ์ฉ์ ํ์ ์ด๋ฆ
+ profileImg: string; // ์ฌ์ฉ์ ํ๋กํ ์ด๋ฏธ์ง URL
+}
+interface SpentMoneyIncludedClient extends Client {
+ spentMoney: number;
+}
+
+// ์ํ ์ถ๊ฐ์ ์๋ฒ๋ก ๋ถํฐ ๋ฐ๋ ์๋ต
+interface AddProductResponseValue {
+ id: string;
+ title: string;
+ price: number;
+ description: string;
+ tags: string[];
+ thumbnail: string | null;
+ photo: string | null;
+ isSoldOut: boolean;
+ discountRate: number;
+}
+
+//์ ํ ์ถ๊ฐ์ ์ฌ์ฉ์๊ฐ ์
๋ ฅํ๋ ๊ฐ
+interface ProductInputData {
+ title: string;
+ price: string;
+ description: string;
+ tags: string[];
+ thumbnailBase64?: string;
+ photoBase64?: string;
+ discountRate?: string;
+ isSoldOut: boolean;
+}
+
+// ์ค์ ์ ํ ์ถ๊ฐ์ ์๊ตฌ๋๋ ๊ฐ
+interface AddProductData {
+ title: string;
+ price: number;
+ description: string;
+ tags?: string[];
+ thumbnailBase64?: string;
+ photoBase64?: string;
+ discountRate?: number;
+}
+
+//์ ํ ์์ ์ ์ฌ์ฉ์๊ฐ ์
๋ ฅํ๋ ๊ฐ
+interface EditProductInputData {
+ title: string;
+ price: string;
+ description: string;
+ tags: string[];
+ isSoldOut: string;
+ thumbnailBase64?: string | null;
+ photoBase64?: string | null;
+ discountRate?: string;
+}
+
+// ์ค์ ์์ ์ ์๊ตฌ๋๋ ๊ฐ
+interface UpdateProductBodyData {
+ title?: string;
+ price?: number;
+ description?: string;
+ tags?: string[];
+ thumbnailBase64?: string | null;
+ photoBase64?: string | null;
+ isSoldOut?: boolean;
+ discountRate?: number;
+}
+
+// ์์ ์ ์๋ฒ๋ก ๋ถํฐ ๋ฐ๋ ์์ ๋ ์ํ ๊ฐ
+interface UpdatedProduct {
+ id: string; // ์ ํ ID
+ title: string; // ์ ํ ์ด๋ฆ
+ price: number; // ์ ํ ๊ฐ๊ฒฉ
+ description: string; // ์ ํ ์์ธ ์ค๋ช
+ tags: string[]; // ์ ํ ํ๊ทธ
+ thumbnail: string | null; // ์ ํ ์ธ๋ค์ผ ์ด๋ฏธ์ง(URL)
+ photo: string | null; // ์ ํ ์์ธ ์ด๋ฏธ์ง(URL)
+ isSoldOut: boolean; // ์ ํ ๋งค์ง ์ฌ๋ถ
+ discountRate: number; // ์ ํ ํ ์ธ์จ
+}
+
+// ๊ฑฐ๋ ์ธ๋ถ ๋ด์ญ
+interface TransactionDetail {
+ detailId: string;
+ user: {
+ email: string;
+ displayName: string;
+ profileImg: string | null;
+ };
+ account: {
+ bankName: string;
+ bankCode: string;
+ accountNumber: string;
+ };
+ product: {
+ productId: string;
+ title: string;
+ price: number;
+ description: string;
+ tags: string[];
+ thumbnail: string | null;
+ discountRate: number;
+ };
+ timePaid: string;
+ isCanceled: boolean;
+ done: boolean;
+}
+
+interface Bank {
+ name: string;
+ code: string;
+ digits: number[];
+ disabled: boolean;
+}
+
+interface AccountsAndBalance {
+ totalBalance: number;
+ accounts: UserAccount[];
+}
+interface UserAccount {
+ id: string;
+ bankName: string;
+ bankCode: string;
+ accountNumber: string;
+ balance: number;
+ delete?: boolean;
+}
+
+interface ConnectAccount {
+ bankCode: string; // ์ฐ๊ฒฐํ ์ํ ์ฝ๋ (ํ์!)
+ accountNumber: string; // ์ฐ๊ฒฐํ ๊ณ์ข๋ฒํธ (ํ์!)
+ phoneNumber: string; // ์ฌ์ฉ์ ์ ํ๋ฒํธ (ํ์!)
+ signature: boolean; // ์ฌ์ฉ์ ์๋ช
(ํ์!)
+}
+
+interface ProductDetail {
+ id: string;
+ title: string;
+ price: number;
+ description: string;
+ tags: string[]; // ์ ํ ํ๊ทธ
+ thumbnail?: string; // ์ ํ ์ธ๋ค์ผ
+ photo?: string; //์์ธ์ด๋ฏธ์ง URL
+ isSoldOut: boolean; // ์ ํ ๋งค์ง์ฌ๋ถ
+ discountRate: number;
+}
+
+// ๊ด๋ฆฌ์ํจ๋์์ ์ํ ๋ชฉ๋ก ์กฐํ์ ๊ฐ๋ณ ์ํ
+interface Product {
+ id: string; // ์ ํ ID
+ title: string; // ์ ํ ์ด๋ฆ
+ price: number; // ์ ํ ๊ฐ๊ฒฉ
+ description: string; // ์ ํ ์ค๋ช
(์ต๋ 100์)
+ tags: string[]; // ์ ํ ํ๊ทธ
+ thumbnail: string | null; // ์ ํ ์ธ๋ค์ผ ์ด๋ฏธ์ง(URL)
+ isSoldOut: boolean; // ์ ํ ๋งค์ง ์ฌ๋ถ
+ discountRate: number; // ์ ํ ํ ์ธ์จ
+}
+
+interface Window {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ my_modal_2: any;
+}
+
+interface ConnectAccountBody {
+ bankCode: string;
+ accountNumber: string;
+ phoneNumber: string;
+ signature: boolean;
+}
+
+// ์ธ์ฆํ์ธ ์ฑ๊ณต์ ์๋ต๊ฐ์ ํ์
+interface AuthenticateResponseValue {
+ email: string;
+ displayName: string;
+ profileImg: string | null;
+}
+
+// ์ฌ์ฉ์๊ฐ ์์ ์ ์ฃผ๋ฌธ๋ชฉ๋ก์ ์์ฒญํ๋ฉด ๋ฐ๋ ๊ฐ๋ณ ์ฃผ๋ฌธ์ ๋ณด
+interface TransactionDetail {
+ detailId: string;
+ product: {
+ productId: string;
+ title: string;
+ price: number;
+ description: string;
+ tags: string[];
+ thumbnail: string | null;
+ discountRate: number;
+ };
+ reservation: Reservation | null;
+ timePaid: string;
+ isCanceled: boolean;
+ done: boolean;
+}
diff --git a/index.html b/index.html
new file mode 100644
index 00000000..bc08b7c8
--- /dev/null
+++ b/index.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+ ์ถ๊ตฌํ๋ ์ญ์ CRAZY11
+
+
+
+
+
+
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 00000000..ae98a76c
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,6091 @@
+{
+ "name": "kdt5-m5",
+ "version": "0.0.0",
+ "lockfileVersion": 2,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "kdt5-m5",
+ "version": "0.0.0",
+ "dependencies": {
+ "axios": "^1.4.0",
+ "nuka-carousel": "^6.0.3",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0",
+ "react-hot-toast": "^2.4.1",
+ "react-icons": "^4.9.0",
+ "react-router-dom": "^6.11.2",
+ "zustand": "^4.3.8"
+ },
+ "devDependencies": {
+ "@types/node": "^20.2.5",
+ "@types/react": "^18.0.37",
+ "@types/react-dom": "^18.0.11",
+ "@typescript-eslint/eslint-plugin": "^5.59.0",
+ "@typescript-eslint/parser": "^5.59.0",
+ "@vitejs/plugin-react-swc": "^3.0.0",
+ "autoprefixer": "^10.4.14",
+ "daisyui": "^3.0.20",
+ "eslint": "^8.41.0",
+ "eslint-config-prettier": "^8.8.0",
+ "eslint-plugin-prettier": "^4.2.1",
+ "eslint-plugin-react-hooks": "^4.6.0",
+ "eslint-plugin-react-refresh": "^0.3.4",
+ "postcss": "^8.4.24",
+ "prettier": "^2.8.8",
+ "prettier-plugin-tailwindcss": "^0.3.0",
+ "tailwindcss": "^3.3.2",
+ "ts-node": "^10.9.1",
+ "typescript": "^5.0.2",
+ "vite": "^4.3.9"
+ }
+ },
+ "node_modules/@alloc/quick-lru": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
+ "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@cspotcode/source-map-support": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
+ "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/trace-mapping": "0.3.9"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.9",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
+ "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.0.3",
+ "@jridgewell/sourcemap-codec": "^1.4.10"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz",
+ "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz",
+ "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz",
+ "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz",
+ "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz",
+ "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz",
+ "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz",
+ "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz",
+ "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz",
+ "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz",
+ "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz",
+ "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz",
+ "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz",
+ "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz",
+ "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz",
+ "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz",
+ "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz",
+ "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz",
+ "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz",
+ "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz",
+ "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz",
+ "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz",
+ "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@eslint-community/eslint-utils": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
+ "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==",
+ "dev": true,
+ "dependencies": {
+ "eslint-visitor-keys": "^3.3.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "peerDependencies": {
+ "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
+ }
+ },
+ "node_modules/@eslint-community/regexpp": {
+ "version": "4.5.1",
+ "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz",
+ "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==",
+ "dev": true,
+ "engines": {
+ "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
+ }
+ },
+ "node_modules/@eslint/eslintrc": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz",
+ "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==",
+ "dev": true,
+ "dependencies": {
+ "ajv": "^6.12.4",
+ "debug": "^4.3.2",
+ "espree": "^9.5.2",
+ "globals": "^13.19.0",
+ "ignore": "^5.2.0",
+ "import-fresh": "^3.2.1",
+ "js-yaml": "^4.1.0",
+ "minimatch": "^3.1.2",
+ "strip-json-comments": "^3.1.1"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@eslint/js": {
+ "version": "8.41.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.41.0.tgz",
+ "integrity": "sha512-LxcyMGxwmTh2lY9FwHPGWOHmYFCZvbrFCBZL4FzSSsxsRPuhrYUg/49/0KDfW8tnIEaEHtfmn6+NPN+1DqaNmA==",
+ "dev": true,
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ }
+ },
+ "node_modules/@humanwhocodes/config-array": {
+ "version": "0.11.8",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz",
+ "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==",
+ "dev": true,
+ "dependencies": {
+ "@humanwhocodes/object-schema": "^1.2.1",
+ "debug": "^4.1.1",
+ "minimatch": "^3.0.5"
+ },
+ "engines": {
+ "node": ">=10.10.0"
+ }
+ },
+ "node_modules/@humanwhocodes/module-importer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
+ "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
+ "dev": true,
+ "engines": {
+ "node": ">=12.22"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/nzakas"
+ }
+ },
+ "node_modules/@humanwhocodes/object-schema": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
+ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
+ "dev": true
+ },
+ "node_modules/@jridgewell/gen-mapping": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
+ "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/set-array": "^1.0.1",
+ "@jridgewell/sourcemap-codec": "^1.4.10",
+ "@jridgewell/trace-mapping": "^0.3.9"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/resolve-uri": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
+ "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/set-array": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
+ "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.4.15",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
+ "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
+ "dev": true
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.18",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz",
+ "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/resolve-uri": "3.1.0",
+ "@jridgewell/sourcemap-codec": "1.4.14"
+ }
+ },
+ "node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.4.14",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
+ "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
+ "dev": true
+ },
+ "node_modules/@nodelib/fs.scandir": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+ "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+ "dev": true,
+ "dependencies": {
+ "@nodelib/fs.stat": "2.0.5",
+ "run-parallel": "^1.1.9"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.stat": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+ "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+ "dev": true,
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.walk": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+ "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+ "dev": true,
+ "dependencies": {
+ "@nodelib/fs.scandir": "2.1.5",
+ "fastq": "^1.6.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@remix-run/router": {
+ "version": "1.6.2",
+ "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.6.2.tgz",
+ "integrity": "sha512-LzqpSrMK/3JBAVBI9u3NWtOhWNw5AMQfrUFYB0+bDHTSw17z++WJLsPsxAuK+oSddsxk4d7F/JcdDPM1M5YAhA==",
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/@swc/core": {
+ "version": "1.3.61",
+ "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.61.tgz",
+ "integrity": "sha512-p58Ltdjo7Yy8CU3zK0cp4/eAgy5qkHs35znGedqVGPiA67cuYZM63DuTfmyrOntMRwQnaFkMLklDAPCizDdDng==",
+ "dev": true,
+ "hasInstallScript": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/swc"
+ },
+ "optionalDependencies": {
+ "@swc/core-darwin-arm64": "1.3.61",
+ "@swc/core-darwin-x64": "1.3.61",
+ "@swc/core-linux-arm-gnueabihf": "1.3.61",
+ "@swc/core-linux-arm64-gnu": "1.3.61",
+ "@swc/core-linux-arm64-musl": "1.3.61",
+ "@swc/core-linux-x64-gnu": "1.3.61",
+ "@swc/core-linux-x64-musl": "1.3.61",
+ "@swc/core-win32-arm64-msvc": "1.3.61",
+ "@swc/core-win32-ia32-msvc": "1.3.61",
+ "@swc/core-win32-x64-msvc": "1.3.61"
+ },
+ "peerDependencies": {
+ "@swc/helpers": "^0.5.0"
+ },
+ "peerDependenciesMeta": {
+ "@swc/helpers": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@swc/core-darwin-arm64": {
+ "version": "1.3.61",
+ "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.61.tgz",
+ "integrity": "sha512-Ra1CZIYYyIp/Y64VcKyaLjIPUwT83JmGduvHu8vhUZOvWV4dWL4s5DrcxQVaQJjjb7Z2N/IUYYS55US1TGnxZw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-darwin-x64": {
+ "version": "1.3.61",
+ "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.61.tgz",
+ "integrity": "sha512-LUia75UByUFkYH1Ddw7IE0X9usNVGJ7aL6+cgOTju7P0dsU0f8h/OGc/GDfp1E4qnKxDCJE+GwDRLoi4SjIxpg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-linux-arm-gnueabihf": {
+ "version": "1.3.61",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.61.tgz",
+ "integrity": "sha512-aalPlicYxHAn2PxNlo3JFEZkMXzCtUwjP27AgMqnfV4cSz7Omo56OtC+413e/kGyCH86Er9gJRQQsxNKP8Qbsg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-linux-arm64-gnu": {
+ "version": "1.3.61",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.61.tgz",
+ "integrity": "sha512-9hGdsbQrYNPo1c7YzWF57yl17bsIuuEQi3I1fOFSv3puL3l5M/C/oCD0Bz6IdKh6mEDC5UNJE4LWtV1gFA995A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-linux-arm64-musl": {
+ "version": "1.3.61",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.61.tgz",
+ "integrity": "sha512-mVmcNfFQRP4SYbGC08IPB3B9Xox+VpGIQqA3Qg7LMCcejLAQLi4Lfe8CDvvBPlQzXHso0Cv+BicJnQVKs8JLOA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-linux-x64-gnu": {
+ "version": "1.3.61",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.61.tgz",
+ "integrity": "sha512-ZkRHs7GEikN6JiVL1/stvq9BVHKrSKoRn9ulVK2hMr+mAGNOKm3Y06NSzOO+BWwMaFOgnO2dWlszCUICsQ0kpg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-linux-x64-musl": {
+ "version": "1.3.61",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.61.tgz",
+ "integrity": "sha512-zK7VqQ5JlK20+7fxI4AgvIUckeZyX0XIbliGXNMR3i+39SJq1vs9scYEmq8VnAfvNdMU5BG+DewbFJlMfCtkxQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-win32-arm64-msvc": {
+ "version": "1.3.61",
+ "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.61.tgz",
+ "integrity": "sha512-e9kVVPk5iVNhO41TvLvcExDHn5iATQ5/M4U7/CdcC7s0fK19TKSEUqkdoTLIJvHBFhgR7w3JJSErfnauO0xXoA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-win32-ia32-msvc": {
+ "version": "1.3.61",
+ "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.61.tgz",
+ "integrity": "sha512-7cJULfa6HvKqvFh6M/f7mKiNRhE2AjgFUCZfdOuy5r8vbtpk+qBK94TXwaDjJYDUGKzDVZw/tJ1eN4Y9n9Ls/Q==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-win32-x64-msvc": {
+ "version": "1.3.61",
+ "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.61.tgz",
+ "integrity": "sha512-Jx8S+21WcKF/wlhW+sYpystWUyymDTEsbBpOgBRpXZelakVcNBCIIYSZOKW/A9PwWTpu6S8yvbs9nUOzKiVPqA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@tsconfig/node10": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz",
+ "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==",
+ "dev": true
+ },
+ "node_modules/@tsconfig/node12": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
+ "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
+ "dev": true
+ },
+ "node_modules/@tsconfig/node14": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
+ "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
+ "dev": true
+ },
+ "node_modules/@tsconfig/node16": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
+ "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
+ "dev": true
+ },
+ "node_modules/@types/json-schema": {
+ "version": "7.0.12",
+ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz",
+ "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==",
+ "dev": true
+ },
+ "node_modules/@types/node": {
+ "version": "20.2.5",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.2.5.tgz",
+ "integrity": "sha512-JJulVEQXmiY9Px5axXHeYGLSjhkZEnD+MDPDGbCbIAbMslkKwmygtZFy1X6s/075Yo94sf8GuSlFfPzysQrWZQ==",
+ "dev": true
+ },
+ "node_modules/@types/prop-types": {
+ "version": "15.7.5",
+ "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
+ "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==",
+ "dev": true
+ },
+ "node_modules/@types/react": {
+ "version": "18.2.7",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.7.tgz",
+ "integrity": "sha512-ojrXpSH2XFCmHm7Jy3q44nXDyN54+EYKP2lBhJ2bqfyPj6cIUW/FZW/Csdia34NQgq7KYcAlHi5184m4X88+yw==",
+ "dev": true,
+ "dependencies": {
+ "@types/prop-types": "*",
+ "@types/scheduler": "*",
+ "csstype": "^3.0.2"
+ }
+ },
+ "node_modules/@types/react-dom": {
+ "version": "18.2.4",
+ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.4.tgz",
+ "integrity": "sha512-G2mHoTMTL4yoydITgOGwWdWMVd8sNgyEP85xVmMKAPUBwQWm9wBPQUmvbeF4V3WBY1P7mmL4BkjQ0SqUpf1snw==",
+ "dev": true,
+ "dependencies": {
+ "@types/react": "*"
+ }
+ },
+ "node_modules/@types/scheduler": {
+ "version": "0.16.3",
+ "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz",
+ "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==",
+ "dev": true
+ },
+ "node_modules/@types/semver": {
+ "version": "7.5.0",
+ "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz",
+ "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==",
+ "dev": true
+ },
+ "node_modules/@typescript-eslint/eslint-plugin": {
+ "version": "5.59.8",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.8.tgz",
+ "integrity": "sha512-JDMOmhXteJ4WVKOiHXGCoB96ADWg9q7efPWHRViT/f09bA8XOMLAVHHju3l0MkZnG1izaWXYmgvQcUjTRcpShQ==",
+ "dev": true,
+ "dependencies": {
+ "@eslint-community/regexpp": "^4.4.0",
+ "@typescript-eslint/scope-manager": "5.59.8",
+ "@typescript-eslint/type-utils": "5.59.8",
+ "@typescript-eslint/utils": "5.59.8",
+ "debug": "^4.3.4",
+ "grapheme-splitter": "^1.0.4",
+ "ignore": "^5.2.0",
+ "natural-compare-lite": "^1.4.0",
+ "semver": "^7.3.7",
+ "tsutils": "^3.21.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "@typescript-eslint/parser": "^5.0.0",
+ "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/parser": {
+ "version": "5.59.8",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.8.tgz",
+ "integrity": "sha512-AnR19RjJcpjoeGojmwZtCwBX/RidqDZtzcbG3xHrmz0aHHoOcbWnpDllenRDmDvsV0RQ6+tbb09/kyc+UT9Orw==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/scope-manager": "5.59.8",
+ "@typescript-eslint/types": "5.59.8",
+ "@typescript-eslint/typescript-estree": "5.59.8",
+ "debug": "^4.3.4"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/scope-manager": {
+ "version": "5.59.8",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.8.tgz",
+ "integrity": "sha512-/w08ndCYI8gxGf+9zKf1vtx/16y8MHrZs5/tnjHhMLNSixuNcJavSX4wAiPf4aS5x41Es9YPCn44MIe4cxIlig==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/types": "5.59.8",
+ "@typescript-eslint/visitor-keys": "5.59.8"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/type-utils": {
+ "version": "5.59.8",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.59.8.tgz",
+ "integrity": "sha512-+5M518uEIHFBy3FnyqZUF3BMP+AXnYn4oyH8RF012+e7/msMY98FhGL5SrN29NQ9xDgvqCgYnsOiKp1VjZ/fpA==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/typescript-estree": "5.59.8",
+ "@typescript-eslint/utils": "5.59.8",
+ "debug": "^4.3.4",
+ "tsutils": "^3.21.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "*"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/types": {
+ "version": "5.59.8",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.8.tgz",
+ "integrity": "sha512-+uWuOhBTj/L6awoWIg0BlWy0u9TyFpCHrAuQ5bNfxDaZ1Ppb3mx6tUigc74LHcbHpOHuOTOJrBoAnhdHdaea1w==",
+ "dev": true,
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree": {
+ "version": "5.59.8",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.8.tgz",
+ "integrity": "sha512-Jy/lPSDJGNow14vYu6IrW790p7HIf/SOV1Bb6lZ7NUkLc2iB2Z9elESmsaUtLw8kVqogSbtLH9tut5GCX1RLDg==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/types": "5.59.8",
+ "@typescript-eslint/visitor-keys": "5.59.8",
+ "debug": "^4.3.4",
+ "globby": "^11.1.0",
+ "is-glob": "^4.0.3",
+ "semver": "^7.3.7",
+ "tsutils": "^3.21.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/utils": {
+ "version": "5.59.8",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.8.tgz",
+ "integrity": "sha512-Tr65630KysnNn9f9G7ROF3w1b5/7f6QVCJ+WK9nhIocWmx9F+TmCAcglF26Vm7z8KCTwoKcNEBZrhlklla3CKg==",
+ "dev": true,
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.2.0",
+ "@types/json-schema": "^7.0.9",
+ "@types/semver": "^7.3.12",
+ "@typescript-eslint/scope-manager": "5.59.8",
+ "@typescript-eslint/types": "5.59.8",
+ "@typescript-eslint/typescript-estree": "5.59.8",
+ "eslint-scope": "^5.1.1",
+ "semver": "^7.3.7"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ }
+ },
+ "node_modules/@typescript-eslint/visitor-keys": {
+ "version": "5.59.8",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.8.tgz",
+ "integrity": "sha512-pJhi2ms0x0xgloT7xYabil3SGGlojNNKjK/q6dB3Ey0uJLMjK2UDGJvHieiyJVW/7C3KI+Z4Q3pEHkm4ejA+xQ==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/types": "5.59.8",
+ "eslint-visitor-keys": "^3.3.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@vitejs/plugin-react-swc": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-react-swc/-/plugin-react-swc-3.3.1.tgz",
+ "integrity": "sha512-ZoYjGxMniXP7X+5ry/W1tpY7w0OeLUEsBF5RHFPmAhpgwwNWie8OF4056MRXRi9QgvYYoZPDzdOXGK3wlCoTfQ==",
+ "dev": true,
+ "dependencies": {
+ "@swc/core": "^1.3.56"
+ },
+ "peerDependencies": {
+ "vite": "^4"
+ }
+ },
+ "node_modules/acorn": {
+ "version": "8.8.2",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
+ "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==",
+ "dev": true,
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-jsx": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+ "dev": true,
+ "peerDependencies": {
+ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ }
+ },
+ "node_modules/acorn-walk": {
+ "version": "8.2.0",
+ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
+ "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/any-promise": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
+ "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==",
+ "dev": true
+ },
+ "node_modules/anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "dev": true,
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/arg": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
+ "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==",
+ "dev": true
+ },
+ "node_modules/argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true
+ },
+ "node_modules/array-union": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
+ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
+ },
+ "node_modules/autoprefixer": {
+ "version": "10.4.14",
+ "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz",
+ "integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/autoprefixer"
+ }
+ ],
+ "dependencies": {
+ "browserslist": "^4.21.5",
+ "caniuse-lite": "^1.0.30001464",
+ "fraction.js": "^4.2.0",
+ "normalize-range": "^0.1.2",
+ "picocolors": "^1.0.0",
+ "postcss-value-parser": "^4.2.0"
+ },
+ "bin": {
+ "autoprefixer": "bin/autoprefixer"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ },
+ "peerDependencies": {
+ "postcss": "^8.1.0"
+ }
+ },
+ "node_modules/axios": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz",
+ "integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==",
+ "dependencies": {
+ "follow-redirects": "^1.15.0",
+ "form-data": "^4.0.0",
+ "proxy-from-env": "^1.1.0"
+ }
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true
+ },
+ "node_modules/binary-extensions": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "dev": true,
+ "dependencies": {
+ "fill-range": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/browserslist": {
+ "version": "4.21.7",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.7.tgz",
+ "integrity": "sha512-BauCXrQ7I2ftSqd2mvKHGo85XR0u7Ru3C/Hxsy/0TkfCtjrmAbPdzLGasmoiBxplpDXlPvdjX9u7srIMfgasNA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "dependencies": {
+ "caniuse-lite": "^1.0.30001489",
+ "electron-to-chromium": "^1.4.411",
+ "node-releases": "^2.0.12",
+ "update-browserslist-db": "^1.0.11"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ },
+ "engines": {
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ }
+ },
+ "node_modules/callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/camelcase-css": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
+ "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
+ "dev": true,
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/caniuse-lite": {
+ "version": "1.0.30001495",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001495.tgz",
+ "integrity": "sha512-F6x5IEuigtUfU5ZMQK2jsy5JqUUlEFRVZq8bO2a+ysq5K7jD6PPc9YXZj78xDNS3uNchesp1Jw47YXEqr+Viyg==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ]
+ },
+ "node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/chokidar": {
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
+ "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ ],
+ "dependencies": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ },
+ "engines": {
+ "node": ">= 8.10.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/chokidar/node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/colord": {
+ "version": "2.9.3",
+ "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz",
+ "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==",
+ "dev": true
+ },
+ "node_modules/combined-stream": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+ "dependencies": {
+ "delayed-stream": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/commander": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
+ "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
+ "dev": true,
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "dev": true
+ },
+ "node_modules/create-require": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
+ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
+ "dev": true
+ },
+ "node_modules/cross-spawn": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
+ "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+ "dev": true,
+ "dependencies": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/css-selector-tokenizer": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.8.0.tgz",
+ "integrity": "sha512-Jd6Ig3/pe62/qe5SBPTN8h8LeUg/pT4lLgtavPf7updwwHpvFzxvOQBHYj2LZDMjUnBzgvIUSjRcf6oT5HzHFg==",
+ "dev": true,
+ "dependencies": {
+ "cssesc": "^3.0.0",
+ "fastparse": "^1.1.2"
+ }
+ },
+ "node_modules/cssesc": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
+ "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
+ "dev": true,
+ "bin": {
+ "cssesc": "bin/cssesc"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/csstype": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",
+ "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ=="
+ },
+ "node_modules/daisyui": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/daisyui/-/daisyui-3.1.0.tgz",
+ "integrity": "sha512-G4dz/bRZVvlhQ/FtezXSg0rXOXzDJ0PcnMqeLSwCYNWXxf46fNJ8LWeV5qwsYOdJbXiXoZLnwyy+BsNoWZ+Bjg==",
+ "dev": true,
+ "dependencies": {
+ "colord": "^2.9",
+ "css-selector-tokenizer": "^0.8",
+ "postcss-js": "^4",
+ "tailwindcss": "^3"
+ },
+ "engines": {
+ "node": ">=16.9.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/daisyui"
+ },
+ "peerDependencies": {
+ "postcss": "^8"
+ }
+ },
+ "node_modules/debug": {
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+ "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+ "dev": true,
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/deep-is": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
+ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
+ "dev": true
+ },
+ "node_modules/delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/didyoumean": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
+ "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==",
+ "dev": true
+ },
+ "node_modules/diff": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
+ "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.3.1"
+ }
+ },
+ "node_modules/dir-glob": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
+ "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
+ "dev": true,
+ "dependencies": {
+ "path-type": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/dlv": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
+ "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
+ "dev": true
+ },
+ "node_modules/doctrine": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+ "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+ "dev": true,
+ "dependencies": {
+ "esutils": "^2.0.2"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/electron-to-chromium": {
+ "version": "1.4.425",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.425.tgz",
+ "integrity": "sha512-wv1NufHxu11zfDbY4fglYQApMswleE9FL/DSeyOyauVXDZ+Kco96JK/tPfBUaDqfRarYp2WH2hJ/5UnVywp9Jg==",
+ "dev": true
+ },
+ "node_modules/esbuild": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz",
+ "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "optionalDependencies": {
+ "@esbuild/android-arm": "0.17.19",
+ "@esbuild/android-arm64": "0.17.19",
+ "@esbuild/android-x64": "0.17.19",
+ "@esbuild/darwin-arm64": "0.17.19",
+ "@esbuild/darwin-x64": "0.17.19",
+ "@esbuild/freebsd-arm64": "0.17.19",
+ "@esbuild/freebsd-x64": "0.17.19",
+ "@esbuild/linux-arm": "0.17.19",
+ "@esbuild/linux-arm64": "0.17.19",
+ "@esbuild/linux-ia32": "0.17.19",
+ "@esbuild/linux-loong64": "0.17.19",
+ "@esbuild/linux-mips64el": "0.17.19",
+ "@esbuild/linux-ppc64": "0.17.19",
+ "@esbuild/linux-riscv64": "0.17.19",
+ "@esbuild/linux-s390x": "0.17.19",
+ "@esbuild/linux-x64": "0.17.19",
+ "@esbuild/netbsd-x64": "0.17.19",
+ "@esbuild/openbsd-x64": "0.17.19",
+ "@esbuild/sunos-x64": "0.17.19",
+ "@esbuild/win32-arm64": "0.17.19",
+ "@esbuild/win32-ia32": "0.17.19",
+ "@esbuild/win32-x64": "0.17.19"
+ }
+ },
+ "node_modules/escalade": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
+ "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/escape-string-regexp": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/eslint": {
+ "version": "8.41.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.41.0.tgz",
+ "integrity": "sha512-WQDQpzGBOP5IrXPo4Hc0814r4/v2rrIsB0rhT7jtunIalgg6gYXWhRMOejVO8yH21T/FGaxjmFjBMNqcIlmH1Q==",
+ "dev": true,
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.2.0",
+ "@eslint-community/regexpp": "^4.4.0",
+ "@eslint/eslintrc": "^2.0.3",
+ "@eslint/js": "8.41.0",
+ "@humanwhocodes/config-array": "^0.11.8",
+ "@humanwhocodes/module-importer": "^1.0.1",
+ "@nodelib/fs.walk": "^1.2.8",
+ "ajv": "^6.10.0",
+ "chalk": "^4.0.0",
+ "cross-spawn": "^7.0.2",
+ "debug": "^4.3.2",
+ "doctrine": "^3.0.0",
+ "escape-string-regexp": "^4.0.0",
+ "eslint-scope": "^7.2.0",
+ "eslint-visitor-keys": "^3.4.1",
+ "espree": "^9.5.2",
+ "esquery": "^1.4.2",
+ "esutils": "^2.0.2",
+ "fast-deep-equal": "^3.1.3",
+ "file-entry-cache": "^6.0.1",
+ "find-up": "^5.0.0",
+ "glob-parent": "^6.0.2",
+ "globals": "^13.19.0",
+ "graphemer": "^1.4.0",
+ "ignore": "^5.2.0",
+ "import-fresh": "^3.0.0",
+ "imurmurhash": "^0.1.4",
+ "is-glob": "^4.0.0",
+ "is-path-inside": "^3.0.3",
+ "js-yaml": "^4.1.0",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "levn": "^0.4.1",
+ "lodash.merge": "^4.6.2",
+ "minimatch": "^3.1.2",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.9.1",
+ "strip-ansi": "^6.0.1",
+ "strip-json-comments": "^3.1.0",
+ "text-table": "^0.2.0"
+ },
+ "bin": {
+ "eslint": "bin/eslint.js"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint-config-prettier": {
+ "version": "8.8.0",
+ "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz",
+ "integrity": "sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==",
+ "dev": true,
+ "bin": {
+ "eslint-config-prettier": "bin/cli.js"
+ },
+ "peerDependencies": {
+ "eslint": ">=7.0.0"
+ }
+ },
+ "node_modules/eslint-plugin-prettier": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz",
+ "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==",
+ "dev": true,
+ "dependencies": {
+ "prettier-linter-helpers": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "peerDependencies": {
+ "eslint": ">=7.28.0",
+ "prettier": ">=2.0.0"
+ },
+ "peerDependenciesMeta": {
+ "eslint-config-prettier": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/eslint-plugin-react-hooks": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz",
+ "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0"
+ }
+ },
+ "node_modules/eslint-plugin-react-refresh": {
+ "version": "0.3.5",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.3.5.tgz",
+ "integrity": "sha512-61qNIsc7fo9Pp/mju0J83kzvLm0Bsayu7OQSLEoJxLDCBjIIyb87bkzufoOvdDxLkSlMfkF7UxomC4+eztUBSA==",
+ "dev": true,
+ "peerDependencies": {
+ "eslint": ">=7"
+ }
+ },
+ "node_modules/eslint-scope": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
+ "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
+ "dev": true,
+ "dependencies": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^4.1.1"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/eslint-visitor-keys": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz",
+ "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==",
+ "dev": true,
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint/node_modules/eslint-scope": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz",
+ "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==",
+ "dev": true,
+ "dependencies": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint/node_modules/estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/espree": {
+ "version": "9.5.2",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz",
+ "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==",
+ "dev": true,
+ "dependencies": {
+ "acorn": "^8.8.0",
+ "acorn-jsx": "^5.3.2",
+ "eslint-visitor-keys": "^3.4.1"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/esquery": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz",
+ "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==",
+ "dev": true,
+ "dependencies": {
+ "estraverse": "^5.1.0"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/esquery/node_modules/estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/esrecurse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+ "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+ "dev": true,
+ "dependencies": {
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/esrecurse/node_modules/estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/estraverse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
+ "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/esutils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+ "dev": true
+ },
+ "node_modules/fast-diff": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz",
+ "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==",
+ "dev": true
+ },
+ "node_modules/fast-glob": {
+ "version": "3.2.12",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz",
+ "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==",
+ "dev": true,
+ "dependencies": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.2",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.4"
+ },
+ "engines": {
+ "node": ">=8.6.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/fast-json-stable-stringify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "dev": true
+ },
+ "node_modules/fast-levenshtein": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
+ "dev": true
+ },
+ "node_modules/fastparse": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz",
+ "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==",
+ "dev": true
+ },
+ "node_modules/fastq": {
+ "version": "1.15.0",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
+ "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==",
+ "dev": true,
+ "dependencies": {
+ "reusify": "^1.0.4"
+ }
+ },
+ "node_modules/file-entry-cache": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
+ "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
+ "dev": true,
+ "dependencies": {
+ "flat-cache": "^3.0.4"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "dev": true,
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/find-up": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+ "dev": true,
+ "dependencies": {
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/flat-cache": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
+ "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
+ "dev": true,
+ "dependencies": {
+ "flatted": "^3.1.0",
+ "rimraf": "^3.0.2"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ }
+ },
+ "node_modules/flatted": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz",
+ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
+ "dev": true
+ },
+ "node_modules/follow-redirects": {
+ "version": "1.15.2",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
+ "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/RubenVerborgh"
+ }
+ ],
+ "engines": {
+ "node": ">=4.0"
+ },
+ "peerDependenciesMeta": {
+ "debug": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/form-data": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
+ "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/fraction.js": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz",
+ "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "type": "patreon",
+ "url": "https://www.patreon.com/infusion"
+ }
+ },
+ "node_modules/fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+ "dev": true
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "dev": true,
+ "hasInstallScript": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
+ "dev": true
+ },
+ "node_modules/glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "dev": true,
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+ "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+ "dev": true,
+ "dependencies": {
+ "is-glob": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/globals": {
+ "version": "13.20.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz",
+ "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==",
+ "dev": true,
+ "dependencies": {
+ "type-fest": "^0.20.2"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/globby": {
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
+ "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
+ "dev": true,
+ "dependencies": {
+ "array-union": "^2.1.0",
+ "dir-glob": "^3.0.1",
+ "fast-glob": "^3.2.9",
+ "ignore": "^5.2.0",
+ "merge2": "^1.4.1",
+ "slash": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/goober": {
+ "version": "2.1.13",
+ "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.13.tgz",
+ "integrity": "sha512-jFj3BQeleOoy7t93E9rZ2de+ScC4lQICLwiAQmKMg9F6roKGaLSHoCDYKkWlSafg138jejvq/mTdvmnwDQgqoQ==",
+ "peerDependencies": {
+ "csstype": "^3.0.10"
+ }
+ },
+ "node_modules/grapheme-splitter": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
+ "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
+ "dev": true
+ },
+ "node_modules/graphemer": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
+ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
+ "dev": true
+ },
+ "node_modules/has": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+ "dev": true,
+ "dependencies": {
+ "function-bind": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ignore": {
+ "version": "5.2.4",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
+ "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
+ "dev": true,
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/import-fresh": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+ "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+ "dev": true,
+ "dependencies": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.19"
+ }
+ },
+ "node_modules/inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+ "dev": true,
+ "dependencies": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true
+ },
+ "node_modules/is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dev": true,
+ "dependencies": {
+ "binary-extensions": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-core-module": {
+ "version": "2.12.1",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz",
+ "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==",
+ "dev": true,
+ "dependencies": {
+ "has": "^1.0.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/is-path-inside": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
+ "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+ "dev": true
+ },
+ "node_modules/jiti": {
+ "version": "1.18.2",
+ "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.18.2.tgz",
+ "integrity": "sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==",
+ "dev": true,
+ "bin": {
+ "jiti": "bin/jiti.js"
+ }
+ },
+ "node_modules/js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
+ },
+ "node_modules/js-yaml": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+ "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+ "dev": true,
+ "dependencies": {
+ "argparse": "^2.0.1"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true
+ },
+ "node_modules/json-stable-stringify-without-jsonify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
+ "dev": true
+ },
+ "node_modules/levn": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+ "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+ "dev": true,
+ "dependencies": {
+ "prelude-ls": "^1.2.1",
+ "type-check": "~0.4.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/lilconfig": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
+ "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/lines-and-columns": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
+ "dev": true
+ },
+ "node_modules/locate-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+ "dev": true,
+ "dependencies": {
+ "p-locate": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/lodash.merge": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+ "dev": true
+ },
+ "node_modules/loose-envify": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+ "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+ "dependencies": {
+ "js-tokens": "^3.0.0 || ^4.0.0"
+ },
+ "bin": {
+ "loose-envify": "cli.js"
+ }
+ },
+ "node_modules/lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "dev": true,
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/make-error": {
+ "version": "1.3.6",
+ "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
+ "dev": true
+ },
+ "node_modules/merge2": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/micromatch": {
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
+ "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
+ "dev": true,
+ "dependencies": {
+ "braces": "^3.0.2",
+ "picomatch": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "dependencies": {
+ "mime-db": "1.52.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ },
+ "node_modules/mz": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
+ "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
+ "dev": true,
+ "dependencies": {
+ "any-promise": "^1.0.0",
+ "object-assign": "^4.0.1",
+ "thenify-all": "^1.0.0"
+ }
+ },
+ "node_modules/nanoid": {
+ "version": "3.3.6",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
+ "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
+ "node_modules/natural-compare": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
+ "dev": true
+ },
+ "node_modules/natural-compare-lite": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz",
+ "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==",
+ "dev": true
+ },
+ "node_modules/node-releases": {
+ "version": "2.0.12",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.12.tgz",
+ "integrity": "sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==",
+ "dev": true
+ },
+ "node_modules/normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/normalize-range": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
+ "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/nuka-carousel": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/nuka-carousel/-/nuka-carousel-6.0.3.tgz",
+ "integrity": "sha512-DYxCTp4xIv9/vfrfOr9FAmYizMr7AefL7mbqsBaBTwdrZ77mAsR/SNZtk+/KHJSuH+9gZLrugj/RC6qM8MJr+Q==",
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=18.0.0",
+ "react-dom": ">=18.0.0"
+ }
+ },
+ "node_modules/object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object-hash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
+ "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
+ "dev": true,
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "dev": true,
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/optionator": {
+ "version": "0.9.1",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
+ "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
+ "dev": true,
+ "dependencies": {
+ "deep-is": "^0.1.3",
+ "fast-levenshtein": "^2.0.6",
+ "levn": "^0.4.1",
+ "prelude-ls": "^1.2.1",
+ "type-check": "^0.4.0",
+ "word-wrap": "^1.2.3"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "dev": true,
+ "dependencies": {
+ "yocto-queue": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-locate": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+ "dev": true,
+ "dependencies": {
+ "p-limit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/parent-module": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+ "dev": true,
+ "dependencies": {
+ "callsites": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-parse": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+ "dev": true
+ },
+ "node_modules/path-type": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/picocolors": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
+ "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
+ "dev": true
+ },
+ "node_modules/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/pirates": {
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz",
+ "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==",
+ "dev": true,
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/postcss": {
+ "version": "8.4.24",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz",
+ "integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "dependencies": {
+ "nanoid": "^3.3.6",
+ "picocolors": "^1.0.0",
+ "source-map-js": "^1.0.2"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/postcss-import": {
+ "version": "15.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz",
+ "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==",
+ "dev": true,
+ "dependencies": {
+ "postcss-value-parser": "^4.0.0",
+ "read-cache": "^1.0.0",
+ "resolve": "^1.1.7"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.0.0"
+ }
+ },
+ "node_modules/postcss-js": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz",
+ "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==",
+ "dev": true,
+ "dependencies": {
+ "camelcase-css": "^2.0.1"
+ },
+ "engines": {
+ "node": "^12 || ^14 || >= 16"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.21"
+ }
+ },
+ "node_modules/postcss-load-config": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.1.tgz",
+ "integrity": "sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==",
+ "dev": true,
+ "dependencies": {
+ "lilconfig": "^2.0.5",
+ "yaml": "^2.1.1"
+ },
+ "engines": {
+ "node": ">= 14"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ "peerDependencies": {
+ "postcss": ">=8.0.9",
+ "ts-node": ">=9.0.0"
+ },
+ "peerDependenciesMeta": {
+ "postcss": {
+ "optional": true
+ },
+ "ts-node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/postcss-nested": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz",
+ "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==",
+ "dev": true,
+ "dependencies": {
+ "postcss-selector-parser": "^6.0.11"
+ },
+ "engines": {
+ "node": ">=12.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ "peerDependencies": {
+ "postcss": "^8.2.14"
+ }
+ },
+ "node_modules/postcss-selector-parser": {
+ "version": "6.0.13",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz",
+ "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==",
+ "dev": true,
+ "dependencies": {
+ "cssesc": "^3.0.0",
+ "util-deprecate": "^1.0.2"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/postcss-value-parser": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
+ "dev": true
+ },
+ "node_modules/prelude-ls": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/prettier": {
+ "version": "2.8.8",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
+ "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
+ "dev": true,
+ "bin": {
+ "prettier": "bin-prettier.js"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ },
+ "funding": {
+ "url": "https://github.com/prettier/prettier?sponsor=1"
+ }
+ },
+ "node_modules/prettier-linter-helpers": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz",
+ "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==",
+ "dev": true,
+ "dependencies": {
+ "fast-diff": "^1.1.2"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/prettier-plugin-tailwindcss": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.3.0.tgz",
+ "integrity": "sha512-009/Xqdy7UmkcTBpwlq7jsViDqXAYSOMLDrHAdTMlVZOrKfM2o9Ci7EMWTMZ7SkKBFTG04UM9F9iM2+4i6boDA==",
+ "dev": true,
+ "engines": {
+ "node": ">=12.17.0"
+ },
+ "peerDependencies": {
+ "@ianvs/prettier-plugin-sort-imports": "*",
+ "@prettier/plugin-pug": "*",
+ "@shopify/prettier-plugin-liquid": "*",
+ "@shufo/prettier-plugin-blade": "*",
+ "@trivago/prettier-plugin-sort-imports": "*",
+ "prettier": ">=2.2.0",
+ "prettier-plugin-astro": "*",
+ "prettier-plugin-css-order": "*",
+ "prettier-plugin-import-sort": "*",
+ "prettier-plugin-jsdoc": "*",
+ "prettier-plugin-marko": "*",
+ "prettier-plugin-organize-attributes": "*",
+ "prettier-plugin-organize-imports": "*",
+ "prettier-plugin-style-order": "*",
+ "prettier-plugin-svelte": "*",
+ "prettier-plugin-twig-melody": "*"
+ },
+ "peerDependenciesMeta": {
+ "@ianvs/prettier-plugin-sort-imports": {
+ "optional": true
+ },
+ "@prettier/plugin-pug": {
+ "optional": true
+ },
+ "@shopify/prettier-plugin-liquid": {
+ "optional": true
+ },
+ "@shufo/prettier-plugin-blade": {
+ "optional": true
+ },
+ "@trivago/prettier-plugin-sort-imports": {
+ "optional": true
+ },
+ "prettier-plugin-astro": {
+ "optional": true
+ },
+ "prettier-plugin-css-order": {
+ "optional": true
+ },
+ "prettier-plugin-import-sort": {
+ "optional": true
+ },
+ "prettier-plugin-jsdoc": {
+ "optional": true
+ },
+ "prettier-plugin-marko": {
+ "optional": true
+ },
+ "prettier-plugin-organize-attributes": {
+ "optional": true
+ },
+ "prettier-plugin-organize-imports": {
+ "optional": true
+ },
+ "prettier-plugin-style-order": {
+ "optional": true
+ },
+ "prettier-plugin-svelte": {
+ "optional": true
+ },
+ "prettier-plugin-twig-melody": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/proxy-from-env": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
+ },
+ "node_modules/punycode": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
+ "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/queue-microtask": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/react": {
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
+ "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
+ "dependencies": {
+ "loose-envify": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/react-dom": {
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
+ "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==",
+ "dependencies": {
+ "loose-envify": "^1.1.0",
+ "scheduler": "^0.23.0"
+ },
+ "peerDependencies": {
+ "react": "^18.2.0"
+ }
+ },
+ "node_modules/react-hot-toast": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.4.1.tgz",
+ "integrity": "sha512-j8z+cQbWIM5LY37pR6uZR6D4LfseplqnuAO4co4u8917hBUvXlEqyP1ZzqVLcqoyUesZZv/ImreoCeHVDpE5pQ==",
+ "dependencies": {
+ "goober": "^2.1.10"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "react": ">=16",
+ "react-dom": ">=16"
+ }
+ },
+ "node_modules/react-icons": {
+ "version": "4.9.0",
+ "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.9.0.tgz",
+ "integrity": "sha512-ijUnFr//ycebOqujtqtV9PFS7JjhWg0QU6ykURVHuL4cbofvRCf3f6GMn9+fBktEFQOIVZnuAYLZdiyadRQRFg==",
+ "peerDependencies": {
+ "react": "*"
+ }
+ },
+ "node_modules/react-router": {
+ "version": "6.11.2",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.11.2.tgz",
+ "integrity": "sha512-74z9xUSaSX07t3LM+pS6Un0T55ibUE/79CzfZpy5wsPDZaea1F8QkrsiyRnA2YQ7LwE/umaydzXZV80iDCPkMg==",
+ "dependencies": {
+ "@remix-run/router": "1.6.2"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "peerDependencies": {
+ "react": ">=16.8"
+ }
+ },
+ "node_modules/react-router-dom": {
+ "version": "6.11.2",
+ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.11.2.tgz",
+ "integrity": "sha512-JNbKtAeh1VSJQnH6RvBDNhxNwemRj7KxCzc5jb7zvDSKRnPWIFj9pO+eXqjM69gQJ0r46hSz1x4l9y0651DKWw==",
+ "dependencies": {
+ "@remix-run/router": "1.6.2",
+ "react-router": "6.11.2"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "peerDependencies": {
+ "react": ">=16.8",
+ "react-dom": ">=16.8"
+ }
+ },
+ "node_modules/read-cache": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
+ "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
+ "dev": true,
+ "dependencies": {
+ "pify": "^2.3.0"
+ }
+ },
+ "node_modules/readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "dev": true,
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
+ "node_modules/resolve": {
+ "version": "1.22.2",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz",
+ "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==",
+ "dev": true,
+ "dependencies": {
+ "is-core-module": "^2.11.0",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
+ },
+ "bin": {
+ "resolve": "bin/resolve"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/reusify": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+ "dev": true,
+ "engines": {
+ "iojs": ">=1.0.0",
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rimraf": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+ "dev": true,
+ "dependencies": {
+ "glob": "^7.1.3"
+ },
+ "bin": {
+ "rimraf": "bin.js"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/rollup": {
+ "version": "3.23.0",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.23.0.tgz",
+ "integrity": "sha512-h31UlwEi7FHihLe1zbk+3Q7z1k/84rb9BSwmBSr/XjOCEaBJ2YyedQDuM0t/kfOS0IxM+vk1/zI9XxYj9V+NJQ==",
+ "dev": true,
+ "bin": {
+ "rollup": "dist/bin/rollup"
+ },
+ "engines": {
+ "node": ">=14.18.0",
+ "npm": ">=8.0.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/run-parallel": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+ "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "dependencies": {
+ "queue-microtask": "^1.2.2"
+ }
+ },
+ "node_modules/scheduler": {
+ "version": "0.23.0",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
+ "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==",
+ "dependencies": {
+ "loose-envify": "^1.1.0"
+ }
+ },
+ "node_modules/semver": {
+ "version": "7.5.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz",
+ "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==",
+ "dev": true,
+ "dependencies": {
+ "lru-cache": "^6.0.0"
+ },
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "dev": true,
+ "dependencies": {
+ "shebang-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/slash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/source-map-js": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
+ "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-json-comments": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/sucrase": {
+ "version": "3.32.0",
+ "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.32.0.tgz",
+ "integrity": "sha512-ydQOU34rpSyj2TGyz4D2p8rbktIOZ8QY9s+DGLvFU1i5pWJE8vkpruCjGCMHsdXwnD7JDcS+noSwM/a7zyNFDQ==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.2",
+ "commander": "^4.0.0",
+ "glob": "7.1.6",
+ "lines-and-columns": "^1.1.6",
+ "mz": "^2.7.0",
+ "pirates": "^4.0.1",
+ "ts-interface-checker": "^0.1.9"
+ },
+ "bin": {
+ "sucrase": "bin/sucrase",
+ "sucrase-node": "bin/sucrase-node"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/sucrase/node_modules/glob": {
+ "version": "7.1.6",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+ "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+ "dev": true,
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/supports-preserve-symlinks-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/tailwindcss": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.2.tgz",
+ "integrity": "sha512-9jPkMiIBXvPc2KywkraqsUfbfj+dHDb+JPWtSJa9MLFdrPyazI7q6WX2sUrm7R9eVR7qqv3Pas7EvQFzxKnI6w==",
+ "dev": true,
+ "dependencies": {
+ "@alloc/quick-lru": "^5.2.0",
+ "arg": "^5.0.2",
+ "chokidar": "^3.5.3",
+ "didyoumean": "^1.2.2",
+ "dlv": "^1.1.3",
+ "fast-glob": "^3.2.12",
+ "glob-parent": "^6.0.2",
+ "is-glob": "^4.0.3",
+ "jiti": "^1.18.2",
+ "lilconfig": "^2.1.0",
+ "micromatch": "^4.0.5",
+ "normalize-path": "^3.0.0",
+ "object-hash": "^3.0.0",
+ "picocolors": "^1.0.0",
+ "postcss": "^8.4.23",
+ "postcss-import": "^15.1.0",
+ "postcss-js": "^4.0.1",
+ "postcss-load-config": "^4.0.1",
+ "postcss-nested": "^6.0.1",
+ "postcss-selector-parser": "^6.0.11",
+ "postcss-value-parser": "^4.2.0",
+ "resolve": "^1.22.2",
+ "sucrase": "^3.32.0"
+ },
+ "bin": {
+ "tailwind": "lib/cli.js",
+ "tailwindcss": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/text-table": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
+ "dev": true
+ },
+ "node_modules/thenify": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
+ "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
+ "dev": true,
+ "dependencies": {
+ "any-promise": "^1.0.0"
+ }
+ },
+ "node_modules/thenify-all": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
+ "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==",
+ "dev": true,
+ "dependencies": {
+ "thenify": ">= 3.1.0 < 4"
+ },
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/ts-interface-checker": {
+ "version": "0.1.13",
+ "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
+ "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==",
+ "dev": true
+ },
+ "node_modules/ts-node": {
+ "version": "10.9.1",
+ "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz",
+ "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==",
+ "dev": true,
+ "dependencies": {
+ "@cspotcode/source-map-support": "^0.8.0",
+ "@tsconfig/node10": "^1.0.7",
+ "@tsconfig/node12": "^1.0.7",
+ "@tsconfig/node14": "^1.0.0",
+ "@tsconfig/node16": "^1.0.2",
+ "acorn": "^8.4.1",
+ "acorn-walk": "^8.1.1",
+ "arg": "^4.1.0",
+ "create-require": "^1.1.0",
+ "diff": "^4.0.1",
+ "make-error": "^1.1.1",
+ "v8-compile-cache-lib": "^3.0.1",
+ "yn": "3.1.1"
+ },
+ "bin": {
+ "ts-node": "dist/bin.js",
+ "ts-node-cwd": "dist/bin-cwd.js",
+ "ts-node-esm": "dist/bin-esm.js",
+ "ts-node-script": "dist/bin-script.js",
+ "ts-node-transpile-only": "dist/bin-transpile.js",
+ "ts-script": "dist/bin-script-deprecated.js"
+ },
+ "peerDependencies": {
+ "@swc/core": ">=1.2.50",
+ "@swc/wasm": ">=1.2.50",
+ "@types/node": "*",
+ "typescript": ">=2.7"
+ },
+ "peerDependenciesMeta": {
+ "@swc/core": {
+ "optional": true
+ },
+ "@swc/wasm": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/ts-node/node_modules/arg": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
+ "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
+ "dev": true
+ },
+ "node_modules/tslib": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+ "dev": true
+ },
+ "node_modules/tsutils": {
+ "version": "3.21.0",
+ "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
+ "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
+ "dev": true,
+ "dependencies": {
+ "tslib": "^1.8.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ },
+ "peerDependencies": {
+ "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta"
+ }
+ },
+ "node_modules/type-check": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+ "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+ "dev": true,
+ "dependencies": {
+ "prelude-ls": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/type-fest": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "5.0.4",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz",
+ "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==",
+ "dev": true,
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=12.20"
+ }
+ },
+ "node_modules/update-browserslist-db": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz",
+ "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "dependencies": {
+ "escalade": "^3.1.1",
+ "picocolors": "^1.0.0"
+ },
+ "bin": {
+ "update-browserslist-db": "cli.js"
+ },
+ "peerDependencies": {
+ "browserslist": ">= 4.21.0"
+ }
+ },
+ "node_modules/uri-js": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+ "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+ "dev": true,
+ "dependencies": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "node_modules/use-sync-external-store": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
+ "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
+ }
+ },
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+ "dev": true
+ },
+ "node_modules/v8-compile-cache-lib": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
+ "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
+ "dev": true
+ },
+ "node_modules/vite": {
+ "version": "4.3.9",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz",
+ "integrity": "sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==",
+ "dev": true,
+ "dependencies": {
+ "esbuild": "^0.17.5",
+ "postcss": "^8.4.23",
+ "rollup": "^3.21.0"
+ },
+ "bin": {
+ "vite": "bin/vite.js"
+ },
+ "engines": {
+ "node": "^14.18.0 || >=16.0.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ },
+ "peerDependencies": {
+ "@types/node": ">= 14",
+ "less": "*",
+ "sass": "*",
+ "stylus": "*",
+ "sugarss": "*",
+ "terser": "^5.4.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "less": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ },
+ "stylus": {
+ "optional": true
+ },
+ "sugarss": {
+ "optional": true
+ },
+ "terser": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/word-wrap": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
+ "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "dev": true
+ },
+ "node_modules/yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+ "dev": true
+ },
+ "node_modules/yaml": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz",
+ "integrity": "sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==",
+ "dev": true,
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/yn": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
+ "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/yocto-queue": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/zustand": {
+ "version": "4.3.8",
+ "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.3.8.tgz",
+ "integrity": "sha512-4h28KCkHg5ii/wcFFJ5Fp+k1J3gJoasaIbppdgZFO4BPJnsNxL0mQXBSFgOgAdCdBj35aDTPvdAJReTMntFPGg==",
+ "dependencies": {
+ "use-sync-external-store": "1.2.0"
+ },
+ "engines": {
+ "node": ">=12.7.0"
+ },
+ "peerDependencies": {
+ "immer": ">=9.0",
+ "react": ">=16.8"
+ },
+ "peerDependenciesMeta": {
+ "immer": {
+ "optional": true
+ },
+ "react": {
+ "optional": true
+ }
+ }
+ }
+ },
+ "dependencies": {
+ "@alloc/quick-lru": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
+ "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==",
+ "dev": true
+ },
+ "@cspotcode/source-map-support": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
+ "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
+ "dev": true,
+ "requires": {
+ "@jridgewell/trace-mapping": "0.3.9"
+ },
+ "dependencies": {
+ "@jridgewell/trace-mapping": {
+ "version": "0.3.9",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
+ "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
+ "dev": true,
+ "requires": {
+ "@jridgewell/resolve-uri": "^3.0.3",
+ "@jridgewell/sourcemap-codec": "^1.4.10"
+ }
+ }
+ }
+ },
+ "@esbuild/android-arm": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz",
+ "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/android-arm64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz",
+ "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/android-x64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz",
+ "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/darwin-arm64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz",
+ "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/darwin-x64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz",
+ "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/freebsd-arm64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz",
+ "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/freebsd-x64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz",
+ "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/linux-arm": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz",
+ "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/linux-arm64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz",
+ "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/linux-ia32": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz",
+ "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/linux-loong64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz",
+ "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/linux-mips64el": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz",
+ "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/linux-ppc64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz",
+ "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/linux-riscv64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz",
+ "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/linux-s390x": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz",
+ "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/linux-x64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz",
+ "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/netbsd-x64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz",
+ "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/openbsd-x64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz",
+ "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/sunos-x64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz",
+ "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/win32-arm64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz",
+ "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/win32-ia32": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz",
+ "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/win32-x64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz",
+ "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==",
+ "dev": true,
+ "optional": true
+ },
+ "@eslint-community/eslint-utils": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
+ "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==",
+ "dev": true,
+ "requires": {
+ "eslint-visitor-keys": "^3.3.0"
+ }
+ },
+ "@eslint-community/regexpp": {
+ "version": "4.5.1",
+ "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz",
+ "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==",
+ "dev": true
+ },
+ "@eslint/eslintrc": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz",
+ "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==",
+ "dev": true,
+ "requires": {
+ "ajv": "^6.12.4",
+ "debug": "^4.3.2",
+ "espree": "^9.5.2",
+ "globals": "^13.19.0",
+ "ignore": "^5.2.0",
+ "import-fresh": "^3.2.1",
+ "js-yaml": "^4.1.0",
+ "minimatch": "^3.1.2",
+ "strip-json-comments": "^3.1.1"
+ }
+ },
+ "@eslint/js": {
+ "version": "8.41.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.41.0.tgz",
+ "integrity": "sha512-LxcyMGxwmTh2lY9FwHPGWOHmYFCZvbrFCBZL4FzSSsxsRPuhrYUg/49/0KDfW8tnIEaEHtfmn6+NPN+1DqaNmA==",
+ "dev": true
+ },
+ "@humanwhocodes/config-array": {
+ "version": "0.11.8",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz",
+ "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==",
+ "dev": true,
+ "requires": {
+ "@humanwhocodes/object-schema": "^1.2.1",
+ "debug": "^4.1.1",
+ "minimatch": "^3.0.5"
+ }
+ },
+ "@humanwhocodes/module-importer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
+ "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
+ "dev": true
+ },
+ "@humanwhocodes/object-schema": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
+ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
+ "dev": true
+ },
+ "@jridgewell/gen-mapping": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
+ "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==",
+ "dev": true,
+ "requires": {
+ "@jridgewell/set-array": "^1.0.1",
+ "@jridgewell/sourcemap-codec": "^1.4.10",
+ "@jridgewell/trace-mapping": "^0.3.9"
+ }
+ },
+ "@jridgewell/resolve-uri": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
+ "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
+ "dev": true
+ },
+ "@jridgewell/set-array": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
+ "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
+ "dev": true
+ },
+ "@jridgewell/sourcemap-codec": {
+ "version": "1.4.15",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
+ "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
+ "dev": true
+ },
+ "@jridgewell/trace-mapping": {
+ "version": "0.3.18",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz",
+ "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==",
+ "dev": true,
+ "requires": {
+ "@jridgewell/resolve-uri": "3.1.0",
+ "@jridgewell/sourcemap-codec": "1.4.14"
+ },
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": {
+ "version": "1.4.14",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
+ "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
+ "dev": true
+ }
+ }
+ },
+ "@nodelib/fs.scandir": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+ "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+ "dev": true,
+ "requires": {
+ "@nodelib/fs.stat": "2.0.5",
+ "run-parallel": "^1.1.9"
+ }
+ },
+ "@nodelib/fs.stat": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+ "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+ "dev": true
+ },
+ "@nodelib/fs.walk": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+ "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+ "dev": true,
+ "requires": {
+ "@nodelib/fs.scandir": "2.1.5",
+ "fastq": "^1.6.0"
+ }
+ },
+ "@remix-run/router": {
+ "version": "1.6.2",
+ "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.6.2.tgz",
+ "integrity": "sha512-LzqpSrMK/3JBAVBI9u3NWtOhWNw5AMQfrUFYB0+bDHTSw17z++WJLsPsxAuK+oSddsxk4d7F/JcdDPM1M5YAhA=="
+ },
+ "@swc/core": {
+ "version": "1.3.61",
+ "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.61.tgz",
+ "integrity": "sha512-p58Ltdjo7Yy8CU3zK0cp4/eAgy5qkHs35znGedqVGPiA67cuYZM63DuTfmyrOntMRwQnaFkMLklDAPCizDdDng==",
+ "dev": true,
+ "requires": {
+ "@swc/core-darwin-arm64": "1.3.61",
+ "@swc/core-darwin-x64": "1.3.61",
+ "@swc/core-linux-arm-gnueabihf": "1.3.61",
+ "@swc/core-linux-arm64-gnu": "1.3.61",
+ "@swc/core-linux-arm64-musl": "1.3.61",
+ "@swc/core-linux-x64-gnu": "1.3.61",
+ "@swc/core-linux-x64-musl": "1.3.61",
+ "@swc/core-win32-arm64-msvc": "1.3.61",
+ "@swc/core-win32-ia32-msvc": "1.3.61",
+ "@swc/core-win32-x64-msvc": "1.3.61"
+ }
+ },
+ "@swc/core-darwin-arm64": {
+ "version": "1.3.61",
+ "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.61.tgz",
+ "integrity": "sha512-Ra1CZIYYyIp/Y64VcKyaLjIPUwT83JmGduvHu8vhUZOvWV4dWL4s5DrcxQVaQJjjb7Z2N/IUYYS55US1TGnxZw==",
+ "dev": true,
+ "optional": true
+ },
+ "@swc/core-darwin-x64": {
+ "version": "1.3.61",
+ "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.61.tgz",
+ "integrity": "sha512-LUia75UByUFkYH1Ddw7IE0X9usNVGJ7aL6+cgOTju7P0dsU0f8h/OGc/GDfp1E4qnKxDCJE+GwDRLoi4SjIxpg==",
+ "dev": true,
+ "optional": true
+ },
+ "@swc/core-linux-arm-gnueabihf": {
+ "version": "1.3.61",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.61.tgz",
+ "integrity": "sha512-aalPlicYxHAn2PxNlo3JFEZkMXzCtUwjP27AgMqnfV4cSz7Omo56OtC+413e/kGyCH86Er9gJRQQsxNKP8Qbsg==",
+ "dev": true,
+ "optional": true
+ },
+ "@swc/core-linux-arm64-gnu": {
+ "version": "1.3.61",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.61.tgz",
+ "integrity": "sha512-9hGdsbQrYNPo1c7YzWF57yl17bsIuuEQi3I1fOFSv3puL3l5M/C/oCD0Bz6IdKh6mEDC5UNJE4LWtV1gFA995A==",
+ "dev": true,
+ "optional": true
+ },
+ "@swc/core-linux-arm64-musl": {
+ "version": "1.3.61",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.61.tgz",
+ "integrity": "sha512-mVmcNfFQRP4SYbGC08IPB3B9Xox+VpGIQqA3Qg7LMCcejLAQLi4Lfe8CDvvBPlQzXHso0Cv+BicJnQVKs8JLOA==",
+ "dev": true,
+ "optional": true
+ },
+ "@swc/core-linux-x64-gnu": {
+ "version": "1.3.61",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.61.tgz",
+ "integrity": "sha512-ZkRHs7GEikN6JiVL1/stvq9BVHKrSKoRn9ulVK2hMr+mAGNOKm3Y06NSzOO+BWwMaFOgnO2dWlszCUICsQ0kpg==",
+ "dev": true,
+ "optional": true
+ },
+ "@swc/core-linux-x64-musl": {
+ "version": "1.3.61",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.61.tgz",
+ "integrity": "sha512-zK7VqQ5JlK20+7fxI4AgvIUckeZyX0XIbliGXNMR3i+39SJq1vs9scYEmq8VnAfvNdMU5BG+DewbFJlMfCtkxQ==",
+ "dev": true,
+ "optional": true
+ },
+ "@swc/core-win32-arm64-msvc": {
+ "version": "1.3.61",
+ "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.61.tgz",
+ "integrity": "sha512-e9kVVPk5iVNhO41TvLvcExDHn5iATQ5/M4U7/CdcC7s0fK19TKSEUqkdoTLIJvHBFhgR7w3JJSErfnauO0xXoA==",
+ "dev": true,
+ "optional": true
+ },
+ "@swc/core-win32-ia32-msvc": {
+ "version": "1.3.61",
+ "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.61.tgz",
+ "integrity": "sha512-7cJULfa6HvKqvFh6M/f7mKiNRhE2AjgFUCZfdOuy5r8vbtpk+qBK94TXwaDjJYDUGKzDVZw/tJ1eN4Y9n9Ls/Q==",
+ "dev": true,
+ "optional": true
+ },
+ "@swc/core-win32-x64-msvc": {
+ "version": "1.3.61",
+ "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.61.tgz",
+ "integrity": "sha512-Jx8S+21WcKF/wlhW+sYpystWUyymDTEsbBpOgBRpXZelakVcNBCIIYSZOKW/A9PwWTpu6S8yvbs9nUOzKiVPqA==",
+ "dev": true,
+ "optional": true
+ },
+ "@tsconfig/node10": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz",
+ "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==",
+ "dev": true
+ },
+ "@tsconfig/node12": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
+ "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
+ "dev": true
+ },
+ "@tsconfig/node14": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
+ "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
+ "dev": true
+ },
+ "@tsconfig/node16": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
+ "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
+ "dev": true
+ },
+ "@types/json-schema": {
+ "version": "7.0.12",
+ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz",
+ "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==",
+ "dev": true
+ },
+ "@types/node": {
+ "version": "20.2.5",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.2.5.tgz",
+ "integrity": "sha512-JJulVEQXmiY9Px5axXHeYGLSjhkZEnD+MDPDGbCbIAbMslkKwmygtZFy1X6s/075Yo94sf8GuSlFfPzysQrWZQ==",
+ "dev": true
+ },
+ "@types/prop-types": {
+ "version": "15.7.5",
+ "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
+ "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==",
+ "dev": true
+ },
+ "@types/react": {
+ "version": "18.2.7",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.7.tgz",
+ "integrity": "sha512-ojrXpSH2XFCmHm7Jy3q44nXDyN54+EYKP2lBhJ2bqfyPj6cIUW/FZW/Csdia34NQgq7KYcAlHi5184m4X88+yw==",
+ "dev": true,
+ "requires": {
+ "@types/prop-types": "*",
+ "@types/scheduler": "*",
+ "csstype": "^3.0.2"
+ }
+ },
+ "@types/react-dom": {
+ "version": "18.2.4",
+ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.4.tgz",
+ "integrity": "sha512-G2mHoTMTL4yoydITgOGwWdWMVd8sNgyEP85xVmMKAPUBwQWm9wBPQUmvbeF4V3WBY1P7mmL4BkjQ0SqUpf1snw==",
+ "dev": true,
+ "requires": {
+ "@types/react": "*"
+ }
+ },
+ "@types/scheduler": {
+ "version": "0.16.3",
+ "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz",
+ "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==",
+ "dev": true
+ },
+ "@types/semver": {
+ "version": "7.5.0",
+ "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz",
+ "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==",
+ "dev": true
+ },
+ "@typescript-eslint/eslint-plugin": {
+ "version": "5.59.8",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.8.tgz",
+ "integrity": "sha512-JDMOmhXteJ4WVKOiHXGCoB96ADWg9q7efPWHRViT/f09bA8XOMLAVHHju3l0MkZnG1izaWXYmgvQcUjTRcpShQ==",
+ "dev": true,
+ "requires": {
+ "@eslint-community/regexpp": "^4.4.0",
+ "@typescript-eslint/scope-manager": "5.59.8",
+ "@typescript-eslint/type-utils": "5.59.8",
+ "@typescript-eslint/utils": "5.59.8",
+ "debug": "^4.3.4",
+ "grapheme-splitter": "^1.0.4",
+ "ignore": "^5.2.0",
+ "natural-compare-lite": "^1.4.0",
+ "semver": "^7.3.7",
+ "tsutils": "^3.21.0"
+ }
+ },
+ "@typescript-eslint/parser": {
+ "version": "5.59.8",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.8.tgz",
+ "integrity": "sha512-AnR19RjJcpjoeGojmwZtCwBX/RidqDZtzcbG3xHrmz0aHHoOcbWnpDllenRDmDvsV0RQ6+tbb09/kyc+UT9Orw==",
+ "dev": true,
+ "requires": {
+ "@typescript-eslint/scope-manager": "5.59.8",
+ "@typescript-eslint/types": "5.59.8",
+ "@typescript-eslint/typescript-estree": "5.59.8",
+ "debug": "^4.3.4"
+ }
+ },
+ "@typescript-eslint/scope-manager": {
+ "version": "5.59.8",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.8.tgz",
+ "integrity": "sha512-/w08ndCYI8gxGf+9zKf1vtx/16y8MHrZs5/tnjHhMLNSixuNcJavSX4wAiPf4aS5x41Es9YPCn44MIe4cxIlig==",
+ "dev": true,
+ "requires": {
+ "@typescript-eslint/types": "5.59.8",
+ "@typescript-eslint/visitor-keys": "5.59.8"
+ }
+ },
+ "@typescript-eslint/type-utils": {
+ "version": "5.59.8",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.59.8.tgz",
+ "integrity": "sha512-+5M518uEIHFBy3FnyqZUF3BMP+AXnYn4oyH8RF012+e7/msMY98FhGL5SrN29NQ9xDgvqCgYnsOiKp1VjZ/fpA==",
+ "dev": true,
+ "requires": {
+ "@typescript-eslint/typescript-estree": "5.59.8",
+ "@typescript-eslint/utils": "5.59.8",
+ "debug": "^4.3.4",
+ "tsutils": "^3.21.0"
+ }
+ },
+ "@typescript-eslint/types": {
+ "version": "5.59.8",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.8.tgz",
+ "integrity": "sha512-+uWuOhBTj/L6awoWIg0BlWy0u9TyFpCHrAuQ5bNfxDaZ1Ppb3mx6tUigc74LHcbHpOHuOTOJrBoAnhdHdaea1w==",
+ "dev": true
+ },
+ "@typescript-eslint/typescript-estree": {
+ "version": "5.59.8",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.8.tgz",
+ "integrity": "sha512-Jy/lPSDJGNow14vYu6IrW790p7HIf/SOV1Bb6lZ7NUkLc2iB2Z9elESmsaUtLw8kVqogSbtLH9tut5GCX1RLDg==",
+ "dev": true,
+ "requires": {
+ "@typescript-eslint/types": "5.59.8",
+ "@typescript-eslint/visitor-keys": "5.59.8",
+ "debug": "^4.3.4",
+ "globby": "^11.1.0",
+ "is-glob": "^4.0.3",
+ "semver": "^7.3.7",
+ "tsutils": "^3.21.0"
+ }
+ },
+ "@typescript-eslint/utils": {
+ "version": "5.59.8",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.8.tgz",
+ "integrity": "sha512-Tr65630KysnNn9f9G7ROF3w1b5/7f6QVCJ+WK9nhIocWmx9F+TmCAcglF26Vm7z8KCTwoKcNEBZrhlklla3CKg==",
+ "dev": true,
+ "requires": {
+ "@eslint-community/eslint-utils": "^4.2.0",
+ "@types/json-schema": "^7.0.9",
+ "@types/semver": "^7.3.12",
+ "@typescript-eslint/scope-manager": "5.59.8",
+ "@typescript-eslint/types": "5.59.8",
+ "@typescript-eslint/typescript-estree": "5.59.8",
+ "eslint-scope": "^5.1.1",
+ "semver": "^7.3.7"
+ }
+ },
+ "@typescript-eslint/visitor-keys": {
+ "version": "5.59.8",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.8.tgz",
+ "integrity": "sha512-pJhi2ms0x0xgloT7xYabil3SGGlojNNKjK/q6dB3Ey0uJLMjK2UDGJvHieiyJVW/7C3KI+Z4Q3pEHkm4ejA+xQ==",
+ "dev": true,
+ "requires": {
+ "@typescript-eslint/types": "5.59.8",
+ "eslint-visitor-keys": "^3.3.0"
+ }
+ },
+ "@vitejs/plugin-react-swc": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-react-swc/-/plugin-react-swc-3.3.1.tgz",
+ "integrity": "sha512-ZoYjGxMniXP7X+5ry/W1tpY7w0OeLUEsBF5RHFPmAhpgwwNWie8OF4056MRXRi9QgvYYoZPDzdOXGK3wlCoTfQ==",
+ "dev": true,
+ "requires": {
+ "@swc/core": "^1.3.56"
+ }
+ },
+ "acorn": {
+ "version": "8.8.2",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
+ "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==",
+ "dev": true
+ },
+ "acorn-jsx": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+ "dev": true,
+ "requires": {}
+ },
+ "acorn-walk": {
+ "version": "8.2.0",
+ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
+ "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
+ "dev": true
+ },
+ "ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
+ "requires": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^2.0.1"
+ }
+ },
+ "any-promise": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
+ "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==",
+ "dev": true
+ },
+ "anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "dev": true,
+ "requires": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ }
+ },
+ "arg": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
+ "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==",
+ "dev": true
+ },
+ "argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true
+ },
+ "array-union": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
+ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+ "dev": true
+ },
+ "asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
+ },
+ "autoprefixer": {
+ "version": "10.4.14",
+ "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz",
+ "integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==",
+ "dev": true,
+ "requires": {
+ "browserslist": "^4.21.5",
+ "caniuse-lite": "^1.0.30001464",
+ "fraction.js": "^4.2.0",
+ "normalize-range": "^0.1.2",
+ "picocolors": "^1.0.0",
+ "postcss-value-parser": "^4.2.0"
+ }
+ },
+ "axios": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz",
+ "integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==",
+ "requires": {
+ "follow-redirects": "^1.15.0",
+ "form-data": "^4.0.0",
+ "proxy-from-env": "^1.1.0"
+ }
+ },
+ "balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true
+ },
+ "binary-extensions": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
+ "dev": true
+ },
+ "brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "requires": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "braces": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "dev": true,
+ "requires": {
+ "fill-range": "^7.0.1"
+ }
+ },
+ "browserslist": {
+ "version": "4.21.7",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.7.tgz",
+ "integrity": "sha512-BauCXrQ7I2ftSqd2mvKHGo85XR0u7Ru3C/Hxsy/0TkfCtjrmAbPdzLGasmoiBxplpDXlPvdjX9u7srIMfgasNA==",
+ "dev": true,
+ "requires": {
+ "caniuse-lite": "^1.0.30001489",
+ "electron-to-chromium": "^1.4.411",
+ "node-releases": "^2.0.12",
+ "update-browserslist-db": "^1.0.11"
+ }
+ },
+ "callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+ "dev": true
+ },
+ "camelcase-css": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
+ "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
+ "dev": true
+ },
+ "caniuse-lite": {
+ "version": "1.0.30001495",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001495.tgz",
+ "integrity": "sha512-F6x5IEuigtUfU5ZMQK2jsy5JqUUlEFRVZq8bO2a+ysq5K7jD6PPc9YXZj78xDNS3uNchesp1Jw47YXEqr+Viyg==",
+ "dev": true
+ },
+ "chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ }
+ },
+ "chokidar": {
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
+ "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
+ "dev": true,
+ "requires": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "fsevents": "~2.3.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ },
+ "dependencies": {
+ "glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "requires": {
+ "is-glob": "^4.0.1"
+ }
+ }
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "colord": {
+ "version": "2.9.3",
+ "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz",
+ "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==",
+ "dev": true
+ },
+ "combined-stream": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+ "requires": {
+ "delayed-stream": "~1.0.0"
+ }
+ },
+ "commander": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
+ "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
+ "dev": true
+ },
+ "concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "dev": true
+ },
+ "create-require": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
+ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
+ "dev": true
+ },
+ "cross-spawn": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
+ "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+ "dev": true,
+ "requires": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ }
+ },
+ "css-selector-tokenizer": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.8.0.tgz",
+ "integrity": "sha512-Jd6Ig3/pe62/qe5SBPTN8h8LeUg/pT4lLgtavPf7updwwHpvFzxvOQBHYj2LZDMjUnBzgvIUSjRcf6oT5HzHFg==",
+ "dev": true,
+ "requires": {
+ "cssesc": "^3.0.0",
+ "fastparse": "^1.1.2"
+ }
+ },
+ "cssesc": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
+ "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
+ "dev": true
+ },
+ "csstype": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",
+ "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ=="
+ },
+ "daisyui": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/daisyui/-/daisyui-3.1.0.tgz",
+ "integrity": "sha512-G4dz/bRZVvlhQ/FtezXSg0rXOXzDJ0PcnMqeLSwCYNWXxf46fNJ8LWeV5qwsYOdJbXiXoZLnwyy+BsNoWZ+Bjg==",
+ "dev": true,
+ "requires": {
+ "colord": "^2.9",
+ "css-selector-tokenizer": "^0.8",
+ "postcss-js": "^4",
+ "tailwindcss": "^3"
+ }
+ },
+ "debug": {
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+ "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+ "dev": true,
+ "requires": {
+ "ms": "2.1.2"
+ }
+ },
+ "deep-is": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
+ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
+ "dev": true
+ },
+ "delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="
+ },
+ "didyoumean": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
+ "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==",
+ "dev": true
+ },
+ "diff": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
+ "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
+ "dev": true
+ },
+ "dir-glob": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
+ "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
+ "dev": true,
+ "requires": {
+ "path-type": "^4.0.0"
+ }
+ },
+ "dlv": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
+ "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
+ "dev": true
+ },
+ "doctrine": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+ "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+ "dev": true,
+ "requires": {
+ "esutils": "^2.0.2"
+ }
+ },
+ "electron-to-chromium": {
+ "version": "1.4.425",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.425.tgz",
+ "integrity": "sha512-wv1NufHxu11zfDbY4fglYQApMswleE9FL/DSeyOyauVXDZ+Kco96JK/tPfBUaDqfRarYp2WH2hJ/5UnVywp9Jg==",
+ "dev": true
+ },
+ "esbuild": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz",
+ "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==",
+ "dev": true,
+ "requires": {
+ "@esbuild/android-arm": "0.17.19",
+ "@esbuild/android-arm64": "0.17.19",
+ "@esbuild/android-x64": "0.17.19",
+ "@esbuild/darwin-arm64": "0.17.19",
+ "@esbuild/darwin-x64": "0.17.19",
+ "@esbuild/freebsd-arm64": "0.17.19",
+ "@esbuild/freebsd-x64": "0.17.19",
+ "@esbuild/linux-arm": "0.17.19",
+ "@esbuild/linux-arm64": "0.17.19",
+ "@esbuild/linux-ia32": "0.17.19",
+ "@esbuild/linux-loong64": "0.17.19",
+ "@esbuild/linux-mips64el": "0.17.19",
+ "@esbuild/linux-ppc64": "0.17.19",
+ "@esbuild/linux-riscv64": "0.17.19",
+ "@esbuild/linux-s390x": "0.17.19",
+ "@esbuild/linux-x64": "0.17.19",
+ "@esbuild/netbsd-x64": "0.17.19",
+ "@esbuild/openbsd-x64": "0.17.19",
+ "@esbuild/sunos-x64": "0.17.19",
+ "@esbuild/win32-arm64": "0.17.19",
+ "@esbuild/win32-ia32": "0.17.19",
+ "@esbuild/win32-x64": "0.17.19"
+ }
+ },
+ "escalade": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
+ "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+ "dev": true
+ },
+ "escape-string-regexp": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+ "dev": true
+ },
+ "eslint": {
+ "version": "8.41.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.41.0.tgz",
+ "integrity": "sha512-WQDQpzGBOP5IrXPo4Hc0814r4/v2rrIsB0rhT7jtunIalgg6gYXWhRMOejVO8yH21T/FGaxjmFjBMNqcIlmH1Q==",
+ "dev": true,
+ "requires": {
+ "@eslint-community/eslint-utils": "^4.2.0",
+ "@eslint-community/regexpp": "^4.4.0",
+ "@eslint/eslintrc": "^2.0.3",
+ "@eslint/js": "8.41.0",
+ "@humanwhocodes/config-array": "^0.11.8",
+ "@humanwhocodes/module-importer": "^1.0.1",
+ "@nodelib/fs.walk": "^1.2.8",
+ "ajv": "^6.10.0",
+ "chalk": "^4.0.0",
+ "cross-spawn": "^7.0.2",
+ "debug": "^4.3.2",
+ "doctrine": "^3.0.0",
+ "escape-string-regexp": "^4.0.0",
+ "eslint-scope": "^7.2.0",
+ "eslint-visitor-keys": "^3.4.1",
+ "espree": "^9.5.2",
+ "esquery": "^1.4.2",
+ "esutils": "^2.0.2",
+ "fast-deep-equal": "^3.1.3",
+ "file-entry-cache": "^6.0.1",
+ "find-up": "^5.0.0",
+ "glob-parent": "^6.0.2",
+ "globals": "^13.19.0",
+ "graphemer": "^1.4.0",
+ "ignore": "^5.2.0",
+ "import-fresh": "^3.0.0",
+ "imurmurhash": "^0.1.4",
+ "is-glob": "^4.0.0",
+ "is-path-inside": "^3.0.3",
+ "js-yaml": "^4.1.0",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "levn": "^0.4.1",
+ "lodash.merge": "^4.6.2",
+ "minimatch": "^3.1.2",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.9.1",
+ "strip-ansi": "^6.0.1",
+ "strip-json-comments": "^3.1.0",
+ "text-table": "^0.2.0"
+ },
+ "dependencies": {
+ "eslint-scope": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz",
+ "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==",
+ "dev": true,
+ "requires": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^5.2.0"
+ }
+ },
+ "estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "dev": true
+ }
+ }
+ },
+ "eslint-config-prettier": {
+ "version": "8.8.0",
+ "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz",
+ "integrity": "sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==",
+ "dev": true,
+ "requires": {}
+ },
+ "eslint-plugin-prettier": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz",
+ "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==",
+ "dev": true,
+ "requires": {
+ "prettier-linter-helpers": "^1.0.0"
+ }
+ },
+ "eslint-plugin-react-hooks": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz",
+ "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==",
+ "dev": true,
+ "requires": {}
+ },
+ "eslint-plugin-react-refresh": {
+ "version": "0.3.5",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.3.5.tgz",
+ "integrity": "sha512-61qNIsc7fo9Pp/mju0J83kzvLm0Bsayu7OQSLEoJxLDCBjIIyb87bkzufoOvdDxLkSlMfkF7UxomC4+eztUBSA==",
+ "dev": true,
+ "requires": {}
+ },
+ "eslint-scope": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
+ "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
+ "dev": true,
+ "requires": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^4.1.1"
+ }
+ },
+ "eslint-visitor-keys": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz",
+ "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==",
+ "dev": true
+ },
+ "espree": {
+ "version": "9.5.2",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz",
+ "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==",
+ "dev": true,
+ "requires": {
+ "acorn": "^8.8.0",
+ "acorn-jsx": "^5.3.2",
+ "eslint-visitor-keys": "^3.4.1"
+ }
+ },
+ "esquery": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz",
+ "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==",
+ "dev": true,
+ "requires": {
+ "estraverse": "^5.1.0"
+ },
+ "dependencies": {
+ "estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "dev": true
+ }
+ }
+ },
+ "esrecurse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+ "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+ "dev": true,
+ "requires": {
+ "estraverse": "^5.2.0"
+ },
+ "dependencies": {
+ "estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "dev": true
+ }
+ }
+ },
+ "estraverse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
+ "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
+ "dev": true
+ },
+ "esutils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+ "dev": true
+ },
+ "fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+ "dev": true
+ },
+ "fast-diff": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz",
+ "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==",
+ "dev": true
+ },
+ "fast-glob": {
+ "version": "3.2.12",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz",
+ "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==",
+ "dev": true,
+ "requires": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.2",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.4"
+ },
+ "dependencies": {
+ "glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "requires": {
+ "is-glob": "^4.0.1"
+ }
+ }
+ }
+ },
+ "fast-json-stable-stringify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "dev": true
+ },
+ "fast-levenshtein": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
+ "dev": true
+ },
+ "fastparse": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz",
+ "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==",
+ "dev": true
+ },
+ "fastq": {
+ "version": "1.15.0",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
+ "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==",
+ "dev": true,
+ "requires": {
+ "reusify": "^1.0.4"
+ }
+ },
+ "file-entry-cache": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
+ "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
+ "dev": true,
+ "requires": {
+ "flat-cache": "^3.0.4"
+ }
+ },
+ "fill-range": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "dev": true,
+ "requires": {
+ "to-regex-range": "^5.0.1"
+ }
+ },
+ "find-up": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+ "dev": true,
+ "requires": {
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
+ }
+ },
+ "flat-cache": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
+ "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
+ "dev": true,
+ "requires": {
+ "flatted": "^3.1.0",
+ "rimraf": "^3.0.2"
+ }
+ },
+ "flatted": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz",
+ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
+ "dev": true
+ },
+ "follow-redirects": {
+ "version": "1.15.2",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
+ "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA=="
+ },
+ "form-data": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
+ "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
+ "requires": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "mime-types": "^2.1.12"
+ }
+ },
+ "fraction.js": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz",
+ "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==",
+ "dev": true
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+ "dev": true
+ },
+ "fsevents": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "dev": true,
+ "optional": true
+ },
+ "function-bind": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
+ "dev": true
+ },
+ "glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "dev": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "glob-parent": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+ "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+ "dev": true,
+ "requires": {
+ "is-glob": "^4.0.3"
+ }
+ },
+ "globals": {
+ "version": "13.20.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz",
+ "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==",
+ "dev": true,
+ "requires": {
+ "type-fest": "^0.20.2"
+ }
+ },
+ "globby": {
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
+ "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
+ "dev": true,
+ "requires": {
+ "array-union": "^2.1.0",
+ "dir-glob": "^3.0.1",
+ "fast-glob": "^3.2.9",
+ "ignore": "^5.2.0",
+ "merge2": "^1.4.1",
+ "slash": "^3.0.0"
+ }
+ },
+ "goober": {
+ "version": "2.1.13",
+ "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.13.tgz",
+ "integrity": "sha512-jFj3BQeleOoy7t93E9rZ2de+ScC4lQICLwiAQmKMg9F6roKGaLSHoCDYKkWlSafg138jejvq/mTdvmnwDQgqoQ==",
+ "requires": {}
+ },
+ "grapheme-splitter": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
+ "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
+ "dev": true
+ },
+ "graphemer": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
+ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
+ "dev": true
+ },
+ "has": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+ "dev": true,
+ "requires": {
+ "function-bind": "^1.1.1"
+ }
+ },
+ "has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true
+ },
+ "ignore": {
+ "version": "5.2.4",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
+ "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
+ "dev": true
+ },
+ "import-fresh": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+ "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+ "dev": true,
+ "requires": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ }
+ },
+ "imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+ "dev": true
+ },
+ "inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+ "dev": true,
+ "requires": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true
+ },
+ "is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dev": true,
+ "requires": {
+ "binary-extensions": "^2.0.0"
+ }
+ },
+ "is-core-module": {
+ "version": "2.12.1",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz",
+ "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==",
+ "dev": true,
+ "requires": {
+ "has": "^1.0.3"
+ }
+ },
+ "is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true
+ },
+ "is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
+ "requires": {
+ "is-extglob": "^2.1.1"
+ }
+ },
+ "is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true
+ },
+ "is-path-inside": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
+ "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
+ "dev": true
+ },
+ "isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+ "dev": true
+ },
+ "jiti": {
+ "version": "1.18.2",
+ "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.18.2.tgz",
+ "integrity": "sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==",
+ "dev": true
+ },
+ "js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
+ },
+ "js-yaml": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+ "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+ "dev": true,
+ "requires": {
+ "argparse": "^2.0.1"
+ }
+ },
+ "json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true
+ },
+ "json-stable-stringify-without-jsonify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
+ "dev": true
+ },
+ "levn": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+ "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+ "dev": true,
+ "requires": {
+ "prelude-ls": "^1.2.1",
+ "type-check": "~0.4.0"
+ }
+ },
+ "lilconfig": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
+ "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==",
+ "dev": true
+ },
+ "lines-and-columns": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
+ "dev": true
+ },
+ "locate-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+ "dev": true,
+ "requires": {
+ "p-locate": "^5.0.0"
+ }
+ },
+ "lodash.merge": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+ "dev": true
+ },
+ "loose-envify": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+ "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+ "requires": {
+ "js-tokens": "^3.0.0 || ^4.0.0"
+ }
+ },
+ "lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "dev": true,
+ "requires": {
+ "yallist": "^4.0.0"
+ }
+ },
+ "make-error": {
+ "version": "1.3.6",
+ "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
+ "dev": true
+ },
+ "merge2": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+ "dev": true
+ },
+ "micromatch": {
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
+ "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
+ "dev": true,
+ "requires": {
+ "braces": "^3.0.2",
+ "picomatch": "^2.3.1"
+ }
+ },
+ "mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
+ },
+ "mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "requires": {
+ "mime-db": "1.52.0"
+ }
+ },
+ "minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "requires": {
+ "brace-expansion": "^1.1.7"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ },
+ "mz": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
+ "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
+ "dev": true,
+ "requires": {
+ "any-promise": "^1.0.0",
+ "object-assign": "^4.0.1",
+ "thenify-all": "^1.0.0"
+ }
+ },
+ "nanoid": {
+ "version": "3.3.6",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
+ "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
+ "dev": true
+ },
+ "natural-compare": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
+ "dev": true
+ },
+ "natural-compare-lite": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz",
+ "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==",
+ "dev": true
+ },
+ "node-releases": {
+ "version": "2.0.12",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.12.tgz",
+ "integrity": "sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==",
+ "dev": true
+ },
+ "normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "dev": true
+ },
+ "normalize-range": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
+ "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==",
+ "dev": true
+ },
+ "nuka-carousel": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/nuka-carousel/-/nuka-carousel-6.0.3.tgz",
+ "integrity": "sha512-DYxCTp4xIv9/vfrfOr9FAmYizMr7AefL7mbqsBaBTwdrZ77mAsR/SNZtk+/KHJSuH+9gZLrugj/RC6qM8MJr+Q==",
+ "requires": {}
+ },
+ "object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+ "dev": true
+ },
+ "object-hash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
+ "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
+ "dev": true
+ },
+ "once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "dev": true,
+ "requires": {
+ "wrappy": "1"
+ }
+ },
+ "optionator": {
+ "version": "0.9.1",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
+ "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
+ "dev": true,
+ "requires": {
+ "deep-is": "^0.1.3",
+ "fast-levenshtein": "^2.0.6",
+ "levn": "^0.4.1",
+ "prelude-ls": "^1.2.1",
+ "type-check": "^0.4.0",
+ "word-wrap": "^1.2.3"
+ }
+ },
+ "p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "dev": true,
+ "requires": {
+ "yocto-queue": "^0.1.0"
+ }
+ },
+ "p-locate": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+ "dev": true,
+ "requires": {
+ "p-limit": "^3.0.2"
+ }
+ },
+ "parent-module": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+ "dev": true,
+ "requires": {
+ "callsites": "^3.0.0"
+ }
+ },
+ "path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true
+ },
+ "path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+ "dev": true
+ },
+ "path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "dev": true
+ },
+ "path-parse": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+ "dev": true
+ },
+ "path-type": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+ "dev": true
+ },
+ "picocolors": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
+ "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
+ "dev": true
+ },
+ "picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "dev": true
+ },
+ "pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
+ "dev": true
+ },
+ "pirates": {
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz",
+ "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==",
+ "dev": true
+ },
+ "postcss": {
+ "version": "8.4.24",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz",
+ "integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==",
+ "dev": true,
+ "requires": {
+ "nanoid": "^3.3.6",
+ "picocolors": "^1.0.0",
+ "source-map-js": "^1.0.2"
+ }
+ },
+ "postcss-import": {
+ "version": "15.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz",
+ "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==",
+ "dev": true,
+ "requires": {
+ "postcss-value-parser": "^4.0.0",
+ "read-cache": "^1.0.0",
+ "resolve": "^1.1.7"
+ }
+ },
+ "postcss-js": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz",
+ "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==",
+ "dev": true,
+ "requires": {
+ "camelcase-css": "^2.0.1"
+ }
+ },
+ "postcss-load-config": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.1.tgz",
+ "integrity": "sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==",
+ "dev": true,
+ "requires": {
+ "lilconfig": "^2.0.5",
+ "yaml": "^2.1.1"
+ }
+ },
+ "postcss-nested": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz",
+ "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==",
+ "dev": true,
+ "requires": {
+ "postcss-selector-parser": "^6.0.11"
+ }
+ },
+ "postcss-selector-parser": {
+ "version": "6.0.13",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz",
+ "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==",
+ "dev": true,
+ "requires": {
+ "cssesc": "^3.0.0",
+ "util-deprecate": "^1.0.2"
+ }
+ },
+ "postcss-value-parser": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
+ "dev": true
+ },
+ "prelude-ls": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+ "dev": true
+ },
+ "prettier": {
+ "version": "2.8.8",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
+ "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
+ "dev": true
+ },
+ "prettier-linter-helpers": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz",
+ "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==",
+ "dev": true,
+ "requires": {
+ "fast-diff": "^1.1.2"
+ }
+ },
+ "prettier-plugin-tailwindcss": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.3.0.tgz",
+ "integrity": "sha512-009/Xqdy7UmkcTBpwlq7jsViDqXAYSOMLDrHAdTMlVZOrKfM2o9Ci7EMWTMZ7SkKBFTG04UM9F9iM2+4i6boDA==",
+ "dev": true,
+ "requires": {}
+ },
+ "proxy-from-env": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
+ },
+ "punycode": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
+ "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==",
+ "dev": true
+ },
+ "queue-microtask": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+ "dev": true
+ },
+ "react": {
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
+ "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
+ "requires": {
+ "loose-envify": "^1.1.0"
+ }
+ },
+ "react-dom": {
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
+ "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==",
+ "requires": {
+ "loose-envify": "^1.1.0",
+ "scheduler": "^0.23.0"
+ }
+ },
+ "react-hot-toast": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.4.1.tgz",
+ "integrity": "sha512-j8z+cQbWIM5LY37pR6uZR6D4LfseplqnuAO4co4u8917hBUvXlEqyP1ZzqVLcqoyUesZZv/ImreoCeHVDpE5pQ==",
+ "requires": {
+ "goober": "^2.1.10"
+ }
+ },
+ "react-icons": {
+ "version": "4.9.0",
+ "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.9.0.tgz",
+ "integrity": "sha512-ijUnFr//ycebOqujtqtV9PFS7JjhWg0QU6ykURVHuL4cbofvRCf3f6GMn9+fBktEFQOIVZnuAYLZdiyadRQRFg==",
+ "requires": {}
+ },
+ "react-router": {
+ "version": "6.11.2",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.11.2.tgz",
+ "integrity": "sha512-74z9xUSaSX07t3LM+pS6Un0T55ibUE/79CzfZpy5wsPDZaea1F8QkrsiyRnA2YQ7LwE/umaydzXZV80iDCPkMg==",
+ "requires": {
+ "@remix-run/router": "1.6.2"
+ }
+ },
+ "react-router-dom": {
+ "version": "6.11.2",
+ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.11.2.tgz",
+ "integrity": "sha512-JNbKtAeh1VSJQnH6RvBDNhxNwemRj7KxCzc5jb7zvDSKRnPWIFj9pO+eXqjM69gQJ0r46hSz1x4l9y0651DKWw==",
+ "requires": {
+ "@remix-run/router": "1.6.2",
+ "react-router": "6.11.2"
+ }
+ },
+ "read-cache": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
+ "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
+ "dev": true,
+ "requires": {
+ "pify": "^2.3.0"
+ }
+ },
+ "readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "dev": true,
+ "requires": {
+ "picomatch": "^2.2.1"
+ }
+ },
+ "resolve": {
+ "version": "1.22.2",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz",
+ "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==",
+ "dev": true,
+ "requires": {
+ "is-core-module": "^2.11.0",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
+ }
+ },
+ "resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "dev": true
+ },
+ "reusify": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+ "dev": true
+ },
+ "rimraf": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ },
+ "rollup": {
+ "version": "3.23.0",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.23.0.tgz",
+ "integrity": "sha512-h31UlwEi7FHihLe1zbk+3Q7z1k/84rb9BSwmBSr/XjOCEaBJ2YyedQDuM0t/kfOS0IxM+vk1/zI9XxYj9V+NJQ==",
+ "dev": true,
+ "requires": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "run-parallel": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+ "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+ "dev": true,
+ "requires": {
+ "queue-microtask": "^1.2.2"
+ }
+ },
+ "scheduler": {
+ "version": "0.23.0",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
+ "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==",
+ "requires": {
+ "loose-envify": "^1.1.0"
+ }
+ },
+ "semver": {
+ "version": "7.5.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz",
+ "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==",
+ "dev": true,
+ "requires": {
+ "lru-cache": "^6.0.0"
+ }
+ },
+ "shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "dev": true,
+ "requires": {
+ "shebang-regex": "^3.0.0"
+ }
+ },
+ "shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "dev": true
+ },
+ "slash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+ "dev": true
+ },
+ "source-map-js": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
+ "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
+ "dev": true
+ },
+ "strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^5.0.1"
+ }
+ },
+ "strip-json-comments": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+ "dev": true
+ },
+ "sucrase": {
+ "version": "3.32.0",
+ "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.32.0.tgz",
+ "integrity": "sha512-ydQOU34rpSyj2TGyz4D2p8rbktIOZ8QY9s+DGLvFU1i5pWJE8vkpruCjGCMHsdXwnD7JDcS+noSwM/a7zyNFDQ==",
+ "dev": true,
+ "requires": {
+ "@jridgewell/gen-mapping": "^0.3.2",
+ "commander": "^4.0.0",
+ "glob": "7.1.6",
+ "lines-and-columns": "^1.1.6",
+ "mz": "^2.7.0",
+ "pirates": "^4.0.1",
+ "ts-interface-checker": "^0.1.9"
+ },
+ "dependencies": {
+ "glob": {
+ "version": "7.1.6",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+ "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+ "dev": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ }
+ }
+ },
+ "supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
+ },
+ "supports-preserve-symlinks-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+ "dev": true
+ },
+ "tailwindcss": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.2.tgz",
+ "integrity": "sha512-9jPkMiIBXvPc2KywkraqsUfbfj+dHDb+JPWtSJa9MLFdrPyazI7q6WX2sUrm7R9eVR7qqv3Pas7EvQFzxKnI6w==",
+ "dev": true,
+ "requires": {
+ "@alloc/quick-lru": "^5.2.0",
+ "arg": "^5.0.2",
+ "chokidar": "^3.5.3",
+ "didyoumean": "^1.2.2",
+ "dlv": "^1.1.3",
+ "fast-glob": "^3.2.12",
+ "glob-parent": "^6.0.2",
+ "is-glob": "^4.0.3",
+ "jiti": "^1.18.2",
+ "lilconfig": "^2.1.0",
+ "micromatch": "^4.0.5",
+ "normalize-path": "^3.0.0",
+ "object-hash": "^3.0.0",
+ "picocolors": "^1.0.0",
+ "postcss": "^8.4.23",
+ "postcss-import": "^15.1.0",
+ "postcss-js": "^4.0.1",
+ "postcss-load-config": "^4.0.1",
+ "postcss-nested": "^6.0.1",
+ "postcss-selector-parser": "^6.0.11",
+ "postcss-value-parser": "^4.2.0",
+ "resolve": "^1.22.2",
+ "sucrase": "^3.32.0"
+ }
+ },
+ "text-table": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
+ "dev": true
+ },
+ "thenify": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
+ "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
+ "dev": true,
+ "requires": {
+ "any-promise": "^1.0.0"
+ }
+ },
+ "thenify-all": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
+ "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==",
+ "dev": true,
+ "requires": {
+ "thenify": ">= 3.1.0 < 4"
+ }
+ },
+ "to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "requires": {
+ "is-number": "^7.0.0"
+ }
+ },
+ "ts-interface-checker": {
+ "version": "0.1.13",
+ "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
+ "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==",
+ "dev": true
+ },
+ "ts-node": {
+ "version": "10.9.1",
+ "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz",
+ "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==",
+ "dev": true,
+ "requires": {
+ "@cspotcode/source-map-support": "^0.8.0",
+ "@tsconfig/node10": "^1.0.7",
+ "@tsconfig/node12": "^1.0.7",
+ "@tsconfig/node14": "^1.0.0",
+ "@tsconfig/node16": "^1.0.2",
+ "acorn": "^8.4.1",
+ "acorn-walk": "^8.1.1",
+ "arg": "^4.1.0",
+ "create-require": "^1.1.0",
+ "diff": "^4.0.1",
+ "make-error": "^1.1.1",
+ "v8-compile-cache-lib": "^3.0.1",
+ "yn": "3.1.1"
+ },
+ "dependencies": {
+ "arg": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
+ "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
+ "dev": true
+ }
+ }
+ },
+ "tslib": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+ "dev": true
+ },
+ "tsutils": {
+ "version": "3.21.0",
+ "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
+ "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
+ "dev": true,
+ "requires": {
+ "tslib": "^1.8.1"
+ }
+ },
+ "type-check": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+ "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+ "dev": true,
+ "requires": {
+ "prelude-ls": "^1.2.1"
+ }
+ },
+ "type-fest": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+ "dev": true
+ },
+ "typescript": {
+ "version": "5.0.4",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz",
+ "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==",
+ "dev": true
+ },
+ "update-browserslist-db": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz",
+ "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==",
+ "dev": true,
+ "requires": {
+ "escalade": "^3.1.1",
+ "picocolors": "^1.0.0"
+ }
+ },
+ "uri-js": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+ "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+ "dev": true,
+ "requires": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "use-sync-external-store": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
+ "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
+ "requires": {}
+ },
+ "util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+ "dev": true
+ },
+ "v8-compile-cache-lib": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
+ "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
+ "dev": true
+ },
+ "vite": {
+ "version": "4.3.9",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz",
+ "integrity": "sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==",
+ "dev": true,
+ "requires": {
+ "esbuild": "^0.17.5",
+ "fsevents": "~2.3.2",
+ "postcss": "^8.4.23",
+ "rollup": "^3.21.0"
+ }
+ },
+ "which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
+ "requires": {
+ "isexe": "^2.0.0"
+ }
+ },
+ "word-wrap": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
+ "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
+ "dev": true
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "dev": true
+ },
+ "yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+ "dev": true
+ },
+ "yaml": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz",
+ "integrity": "sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==",
+ "dev": true
+ },
+ "yn": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
+ "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
+ "dev": true
+ },
+ "yocto-queue": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+ "dev": true
+ },
+ "zustand": {
+ "version": "4.3.8",
+ "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.3.8.tgz",
+ "integrity": "sha512-4h28KCkHg5ii/wcFFJ5Fp+k1J3gJoasaIbppdgZFO4BPJnsNxL0mQXBSFgOgAdCdBj35aDTPvdAJReTMntFPGg==",
+ "requires": {
+ "use-sync-external-store": "1.2.0"
+ }
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 00000000..66129049
--- /dev/null
+++ b/package.json
@@ -0,0 +1,43 @@
+{
+ "name": "kdt5-m5",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "tsc && vite build",
+ "lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
+ "preview": "vite preview"
+ },
+ "dependencies": {
+ "nuka-carousel": "^6.0.3",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0",
+ "react-hot-toast": "^2.4.1",
+ "react-icons": "^4.9.0",
+ "react-router-dom": "^6.11.2",
+ "zustand": "^4.3.8"
+ },
+ "devDependencies": {
+ "@types/node": "^20.2.5",
+ "@types/react": "^18.0.37",
+ "@types/react-dom": "^18.0.11",
+ "@typescript-eslint/eslint-plugin": "^5.59.0",
+ "@typescript-eslint/parser": "^5.59.0",
+ "@vitejs/plugin-react-swc": "^3.0.0",
+ "autoprefixer": "^10.4.14",
+ "daisyui": "^3.0.20",
+ "eslint": "^8.41.0",
+ "eslint-config-prettier": "^8.8.0",
+ "eslint-plugin-prettier": "^4.2.1",
+ "eslint-plugin-react-hooks": "^4.6.0",
+ "eslint-plugin-react-refresh": "^0.3.4",
+ "postcss": "^8.4.24",
+ "prettier": "^2.8.8",
+ "prettier-plugin-tailwindcss": "^0.3.0",
+ "tailwindcss": "^3.3.2",
+ "ts-node": "^10.9.1",
+ "typescript": "^5.0.2",
+ "vite": "^4.3.9"
+ }
+}
diff --git a/postcss.config.js b/postcss.config.js
new file mode 100644
index 00000000..2e7af2b7
--- /dev/null
+++ b/postcss.config.js
@@ -0,0 +1,6 @@
+export default {
+ plugins: {
+ tailwindcss: {},
+ autoprefixer: {},
+ },
+}
diff --git a/public/defaultProfile.jpg b/public/defaultProfile.jpg
new file mode 100644
index 00000000..c146f1ce
Binary files /dev/null and b/public/defaultProfile.jpg differ
diff --git a/public/defaultThumb.jpg b/public/defaultThumb.jpg
new file mode 100644
index 00000000..8e84d66e
Binary files /dev/null and b/public/defaultThumb.jpg differ
diff --git a/public/favicon.ico b/public/favicon.ico
new file mode 100644
index 00000000..36f1309c
Binary files /dev/null and b/public/favicon.ico differ
diff --git a/public/mainIcon.png b/public/mainIcon.png
new file mode 100644
index 00000000..6f44fa07
Binary files /dev/null and b/public/mainIcon.png differ
diff --git a/public/mainlogo.png b/public/mainlogo.png
new file mode 100644
index 00000000..93ec14a7
Binary files /dev/null and b/public/mainlogo.png differ
diff --git a/public/products/dummy.jpg b/public/products/dummy.jpg
new file mode 100644
index 00000000..65518424
Binary files /dev/null and b/public/products/dummy.jpg differ
diff --git a/public/readme/main.png b/public/readme/main.png
new file mode 100644
index 00000000..cd8fdd31
Binary files /dev/null and b/public/readme/main.png differ
diff --git "a/public/readme/\352\261\260\353\236\230\353\202\264\354\227\255.png" "b/public/readme/\352\261\260\353\236\230\353\202\264\354\227\255.png"
new file mode 100644
index 00000000..e8242584
Binary files /dev/null and "b/public/readme/\352\261\260\353\236\230\353\202\264\354\227\255.png" differ
diff --git "a/public/readme/\352\262\200\354\203\211.png" "b/public/readme/\352\262\200\354\203\211.png"
new file mode 100644
index 00000000..42145feb
Binary files /dev/null and "b/public/readme/\352\262\200\354\203\211.png" differ
diff --git "a/public/readme/\352\263\204\354\242\214 \354\241\260\355\232\214.png" "b/public/readme/\352\263\204\354\242\214 \354\241\260\355\232\214.png"
new file mode 100644
index 00000000..1c705d29
Binary files /dev/null and "b/public/readme/\352\263\204\354\242\214 \354\241\260\355\232\214.png" differ
diff --git "a/public/readme/\352\263\204\354\242\214\354\227\260\352\262\260.png" "b/public/readme/\352\263\204\354\242\214\354\227\260\352\262\260.png"
new file mode 100644
index 00000000..5ef57023
Binary files /dev/null and "b/public/readme/\352\263\204\354\242\214\354\227\260\352\262\260.png" differ
diff --git "a/public/readme/\352\265\254\353\247\244\353\202\264\354\227\255.png" "b/public/readme/\352\265\254\353\247\244\353\202\264\354\227\255.png"
new file mode 100644
index 00000000..acd56977
Binary files /dev/null and "b/public/readme/\352\265\254\353\247\244\353\202\264\354\227\255.png" differ
diff --git "a/public/readme/\353\202\264\354\240\225\353\263\264.png" "b/public/readme/\353\202\264\354\240\225\353\263\264.png"
new file mode 100644
index 00000000..e992c214
Binary files /dev/null and "b/public/readme/\353\202\264\354\240\225\353\263\264.png" differ
diff --git "a/public/readme/\353\241\234\352\267\270\354\235\270.png" "b/public/readme/\353\241\234\352\267\270\354\235\270.png"
new file mode 100644
index 00000000..366257c9
Binary files /dev/null and "b/public/readme/\353\241\234\352\267\270\354\235\270.png" differ
diff --git "a/public/readme/\353\241\234\353\224\251.gif" "b/public/readme/\353\241\234\353\224\251.gif"
new file mode 100644
index 00000000..b3ad6fe5
Binary files /dev/null and "b/public/readme/\353\241\234\353\224\251.gif" differ
diff --git "a/public/readme/\353\252\250\353\223\240\354\240\234\355\222\210.png" "b/public/readme/\353\252\250\353\223\240\354\240\234\355\222\210.png"
new file mode 100644
index 00000000..3b704b3c
Binary files /dev/null and "b/public/readme/\353\252\250\353\223\240\354\240\234\355\222\210.png" differ
diff --git "a/public/readme/\354\203\201\354\204\270\355\216\230\354\235\264\354\247\200.png" "b/public/readme/\354\203\201\354\204\270\355\216\230\354\235\264\354\247\200.png"
new file mode 100644
index 00000000..ef1d0954
Binary files /dev/null and "b/public/readme/\354\203\201\354\204\270\355\216\230\354\235\264\354\247\200.png" differ
diff --git "a/public/readme/\354\203\201\355\222\210\352\264\200\353\246\254.png" "b/public/readme/\354\203\201\355\222\210\352\264\200\353\246\254.png"
new file mode 100644
index 00000000..613234c1
Binary files /dev/null and "b/public/readme/\354\203\201\355\222\210\352\264\200\353\246\254.png" differ
diff --git "a/public/readme/\354\203\201\355\222\210\354\210\230\354\240\225.png" "b/public/readme/\354\203\201\355\222\210\354\210\230\354\240\225.png"
new file mode 100644
index 00000000..92dca3e7
Binary files /dev/null and "b/public/readme/\354\203\201\355\222\210\354\210\230\354\240\225.png" differ
diff --git "a/public/readme/\354\203\201\355\222\210\354\266\224\352\260\200.png" "b/public/readme/\354\203\201\355\222\210\354\266\224\352\260\200.png"
new file mode 100644
index 00000000..3d1d09fa
Binary files /dev/null and "b/public/readme/\354\203\201\355\222\210\354\266\224\352\260\200.png" differ
diff --git "a/public/readme/\354\227\260\352\264\200\354\203\201\355\222\210.png" "b/public/readme/\354\227\260\352\264\200\354\203\201\355\222\210.png"
new file mode 100644
index 00000000..d807c1cd
Binary files /dev/null and "b/public/readme/\354\227\260\352\264\200\354\203\201\355\222\210.png" differ
diff --git "a/public/readme/\354\271\264\355\205\214\352\263\240\353\246\254\353\263\204.png" "b/public/readme/\354\271\264\355\205\214\352\263\240\353\246\254\353\263\204.png"
new file mode 100644
index 00000000..7e523c6d
Binary files /dev/null and "b/public/readme/\354\271\264\355\205\214\352\263\240\353\246\254\353\263\204.png" differ
diff --git "a/public/readme/\355\232\214\354\233\220\352\260\200\354\236\205.png" "b/public/readme/\355\232\214\354\233\220\352\260\200\354\236\205.png"
new file mode 100644
index 00000000..b330415b
Binary files /dev/null and "b/public/readme/\355\232\214\354\233\220\352\260\200\354\236\205.png" differ
diff --git "a/public/readme/\355\232\214\354\233\220\354\240\225\353\263\264.png" "b/public/readme/\355\232\214\354\233\220\354\240\225\353\263\264.png"
new file mode 100644
index 00000000..6a7fe14c
Binary files /dev/null and "b/public/readme/\355\232\214\354\233\220\354\240\225\353\263\264.png" differ
diff --git a/public/slider/mainSlide0.jpg b/public/slider/mainSlide0.jpg
new file mode 100644
index 00000000..055729d6
Binary files /dev/null and b/public/slider/mainSlide0.jpg differ
diff --git a/public/slider/mainSlide1.jpg b/public/slider/mainSlide1.jpg
new file mode 100644
index 00000000..5279dfdc
Binary files /dev/null and b/public/slider/mainSlide1.jpg differ
diff --git a/public/slider/mainSlide2.jpg b/public/slider/mainSlide2.jpg
new file mode 100644
index 00000000..bec48c89
Binary files /dev/null and b/public/slider/mainSlide2.jpg differ
diff --git a/public/slider/mainSlide3.jpg b/public/slider/mainSlide3.jpg
new file mode 100644
index 00000000..27c4e054
Binary files /dev/null and b/public/slider/mainSlide3.jpg differ
diff --git a/public/slider/mainSlide4.jpg b/public/slider/mainSlide4.jpg
new file mode 100644
index 00000000..e2e7ed1a
Binary files /dev/null and b/public/slider/mainSlide4.jpg differ
diff --git a/public/soldout.png b/public/soldout.png
new file mode 100644
index 00000000..39e88840
Binary files /dev/null and b/public/soldout.png differ
diff --git a/src/App.tsx b/src/App.tsx
new file mode 100644
index 00000000..8be54eed
--- /dev/null
+++ b/src/App.tsx
@@ -0,0 +1,82 @@
+import { Route, Routes } from 'react-router-dom';
+import Layout from '@/components/Layout';
+import Home from '@/routes/Home';
+import NotFound from '@/routes/NotFound';
+import Login from '@/routes/Login';
+import Admin from '@/routes/admin/Admin';
+import AddProduct from '@/routes/admin/AddProduct';
+import ProtectedRoute from '@/routes/ProtectedRoute';
+import MyAccount from '@/routes/myAccount/MyAccount';
+import AdminClients from '@/routes/admin/AdminClients';
+import ChangeName from '@/routes/myAccount/ChangeName';
+import ChangePassword from '@/routes/myAccount/ChangePassword';
+import Info from '@/routes/myAccount/Info';
+import AdminProduct from '@/routes/admin/AdminProducts';
+import ConnectBankAccount from '@/routes/myAccount/bank/ConnectBankAccount';
+import Products from '@/routes/Products';
+import ProductDetail from '@/routes/ProductDetail';
+import BankAccounts from '@/routes/myAccount/bank/BankAccounts';
+import SearchProducts from '@/routes/SearchProducts';
+import OrderList from '@/routes/myAccount/OrderList';
+import AllTransactions from '@/routes/admin/AllTransactions';
+import OrderDetail from '@/routes/myAccount/OrderDetail';
+import EditProduct from '@/routes/admin/EditProduct';
+import LogoutNeededRoute from '@/routes/LogoutNeededRoute';
+import SignUp from '@/routes/SignUp';
+
+export default function App() {
+ return (
+
+ }>
+ {/* ํ */}
+ } />
+ } />
+ } />
+ }
+ />
+ {/* ๋ก๊ทธ์ธ */}
+ } />}
+ />
+ {/* ํ์๊ฐ์
*/}
+ } />}
+ />
+ {/* ๋ด ์ ๋ณด */}
+ } />}
+ >
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+
+ {/* ๊ด๋ฆฌ์ */}
+ } />}
+ >
+ {/*์ ์ ๊ด๋ฆฌ*/}
+ } />
+ {/*์ํ๊ด๋ฆฌ*/}
+ } />
+ {/*์ํ์ถ๊ฐ*/}
+ } />
+ {/*์ํ์์ */}
+ } />
+ {/*๊ฑฐ๋๋ด์ญ*/}
+ } />
+
+ } />
+
+
+ );
+}
diff --git a/src/api/adminApi.ts b/src/api/adminApi.ts
new file mode 100644
index 00000000..9982e34b
--- /dev/null
+++ b/src/api/adminApi.ts
@@ -0,0 +1,227 @@
+import { API_URL, HEADERS } from '@/constants/constants';
+const MASTER_HEADERS = {
+ ...HEADERS,
+ masterKey: 'true',
+};
+
+export const addProduct = async (productData: AddProductData) => {
+ try {
+ const response = await fetch(`${API_URL}/products`, {
+ method: 'POST',
+ headers: MASTER_HEADERS,
+ body: JSON.stringify(productData),
+ });
+ if (response.ok) {
+ const data: AddProductResponseValue = await response.json();
+ return {
+ data,
+ statusCode: response.status,
+ message: `${data.title}๋ฅผ ์ถ๊ฐํ์์ต๋๋ค.`,
+ };
+ }
+ const errorMessage: string = await response.json();
+ return {
+ data: null,
+ statusCode: response.status,
+ message: errorMessage,
+ };
+ } catch (error) {
+ console.log('Error while adding product: ', error);
+ return {
+ data: null,
+ statusCode: 400,
+ message: '์ํ์ ์ถ๊ฐ ์ค ์๋ฌ๋ฐ์, ์ ์ ํ ๋ค์ ์๋ํด ์ฃผ์ธ์',
+ };
+ }
+};
+
+// ์์ ์์
+export const updateProduct = async (
+ productId: string,
+ updateData: UpdateProductBodyData
+) => {
+ try {
+ const response = await fetch(`${API_URL}/products/${productId}`, {
+ method: 'PUT',
+ headers: MASTER_HEADERS,
+ body: JSON.stringify(updateData),
+ });
+ if (response.ok) {
+ const data: UpdatedProduct = await response.json();
+ return {
+ data,
+ statusCode: response.status,
+ message: `${data.title} ์ํ์ ์์ ํ์์ต๋๋ค.`,
+ };
+ }
+ const errorMessage = await response.json();
+ return {
+ data: null,
+ statusCode: response.status,
+ message: errorMessage,
+ };
+ } catch (error) {
+ console.log('error while updating a product');
+ return {
+ data: null,
+ statusCode: 400,
+ message: '์ ํ ์์ ์ค ์๋ฌ๋ฐ์, ์ ์ ํ ๋ค์ ์๋ํด ์ฃผ์ธ์.',
+ };
+ }
+};
+
+export const deleteProduct = async (productId: string) => {
+ try {
+ const response = await fetch(`${API_URL}/products/${productId}`, {
+ method: 'DELETE',
+ headers: MASTER_HEADERS,
+ });
+ if (response.ok) {
+ const data: true = await response.json();
+ return {
+ data,
+ statusCode: response.status,
+ message: '',
+ };
+ }
+ const errorMessage: string = await response.json();
+ return {
+ data: null,
+ statusCode: response.status,
+ message: errorMessage,
+ };
+ } catch (error) {
+ return {
+ data: null,
+ statusCode: 400,
+ message: '์ํ ์ญ์ ์ค ์๋ฌ๋ฐ์, ์ ์ ํ ๋ค์ ์๋ํด ์ฃผ์ธ์.',
+ };
+ }
+};
+
+// ์ ์ ์กฐํ
+export const getClients = async () => {
+ try {
+ const res = await fetch(`${API_URL}/auth/users`, {
+ method: 'GET',
+ headers: MASTER_HEADERS,
+ });
+ // ์ ์ ๋ค ์กฐํ๊ฐ ์ฑ๊ณตํ ๊ฒฝ์ฐ
+ if (res.ok) {
+ const data: Client[] = await res.json();
+ return {
+ data,
+ statusCode: res.status,
+ message: '',
+ };
+ }
+ // ์ ์ ๋ค ์กฐํ๊ฐ ์คํจํ ๊ฒฝ์ฐ(masterkey๊ฐ ์๋๊ฒฝ์ฐ)
+ const errorMessage: string = await res.json();
+ return {
+ data: null,
+ statusCode: res.status,
+ message: errorMessage,
+ };
+ // ๊ธฐํ ์ค๋ฅ(url์ด ์๋ชป๋๊ฒฝ์ฐ, ์๋ฒ๋ค์ด)
+ } catch (error) {
+ console.log('Error while getUser: ', error);
+ return {
+ data: null,
+ statusCode: 400,
+ message: 'ํ์ ์กฐํ ์ค ์๋ฌ๋ฐ์, ์ ์ ํ ๋ค์ ์๋ํด ์ฃผ์ธ์.',
+ };
+ }
+};
+
+// ์ํ ์กฐํ
+export async function getProducts() {
+ try {
+ const res = await fetch(`${API_URL}/products`, {
+ method: 'GET',
+ headers: MASTER_HEADERS,
+ });
+ if (res.ok) {
+ const data: Product[] = await res.json();
+ return {
+ data,
+ statusCode: res.status,
+ message: '',
+ };
+ }
+ const error: string = await res.json();
+ return {
+ data: null,
+ statusCode: res.status,
+ message: error,
+ };
+ } catch (error) {
+ return {
+ data: null,
+ statusCode: 400,
+ message: '์ํ ๋ชฉ๋ก ์กฐํ ์ค ์ค๋ฅ ๋ฐ์, ์ ์ ํ ๋ค์ ์๋ํด ์ฃผ์ธ์.',
+ };
+ }
+}
+
+export async function getProductDetail(productId: string) {
+ try {
+ const res = await fetch(`${API_URL}/products/${productId}`, {
+ method: 'GET',
+ headers: MASTER_HEADERS,
+ });
+ if (res.ok) {
+ const data: ProductDetail = await res.json();
+ return {
+ data,
+ statusCode: res.status,
+ message: '',
+ };
+ }
+ const errorMessage: string = await res.json();
+ return {
+ data: null,
+ statusCode: res.status,
+ message: errorMessage,
+ };
+ } catch (error) {
+ console.log('error while getting a product', error);
+ return {
+ data: null,
+ statusCode: 400,
+ message: '๊ฐ๋ณ ์ํ ์กฐํ ์ค ์๋ฌ๋ฐ์, ์ ์ ํ ๋ค์ ์๋ํด ์ฃผ์ธ์.',
+ };
+ }
+}
+
+export const getAllTransactions = async () => {
+ try {
+ const response = await fetch(`${API_URL}/products/transactions/all`, {
+ method: 'GET',
+ headers: MASTER_HEADERS,
+ });
+
+ if (response.ok) {
+ const data: TransactionDetail[] = await response.json();
+ return {
+ data,
+ statusCode: response.status,
+ message: '',
+ };
+ }
+
+ const errorMessage: string = await response.json();
+ return {
+ data: null,
+ statusCode: response.status,
+ message: errorMessage,
+ };
+ } catch (error) {
+ console.log('Error while fetching all transactions: ', error);
+ return {
+ data: null,
+ statusCode: 400,
+ message:
+ '์ ์ฒด ๊ฑฐ๋ ๋ด์ญ์ ๋ถ๋ฌ์ค๋ ์ค ์ค๋ฅ ๋ฐ์, ์ ์ ํ ๋ค์ ์๋ํด ์ฃผ์ธ์.',
+ };
+ }
+};
diff --git a/src/api/authApi.ts b/src/api/authApi.ts
new file mode 100644
index 00000000..6cd32138
--- /dev/null
+++ b/src/api/authApi.ts
@@ -0,0 +1,203 @@
+import { API_URL, HEADERS } from '@/constants/constants';
+
+// 1. ๋ก๊ทธ์ธ
+export const signIn = async (loginData: {
+ email: string;
+ password: string;
+}) => {
+ try {
+ const response = await fetch(`${API_URL}/auth/login`, {
+ method: 'POST',
+ headers: HEADERS,
+ body: JSON.stringify({
+ email: loginData.email,
+ password: loginData.password,
+ }),
+ });
+ // ๋ก๊ทธ์ธ ์ฑ๊ณต
+ if (response.ok) {
+ const data: UserResponseValue = await response.json();
+ return {
+ data,
+ statusCode: response.status, //200
+ message: `${data.user.displayName}๋ ์ฆ๊ฑฐ์ด ์ผํ ๋์ธ์!`,
+ };
+ }
+ // ๋ก๊ทธ์ธ ์คํจ(์๋ ์ด๋ฉ์ผ or ๋น๋ฒ ์
๋ ฅ ์ค๋ฅ or ์ ํจ์ฑ ์ค๋ฅ(ํด๋ผ์ด์ธํธ์์ ์ ํจ์ฑ๊ฒ์ฌํจ) or apiํค๊ฐ ์๋ชป๋ ๊ฒฝ์ฐ)
+ const errorMessage: string = await response.json();
+ return { data: null, statusCode: response.status, message: errorMessage };
+
+ // ๊ธฐํ ์ค๋ฅ(์๋ฒ ๋ฌธ์ , url์ด ์๋ชป๋ ๊ฒฝ์ฐ)
+ } catch (error) {
+ console.log('Error while login: ', error);
+ return {
+ data: null,
+ statusCode: 400,
+ message: '๋ก๊ทธ์ธ ๋์ค ์ค๋ฅ๋ฐ์, ์ ์ ํ ๋ค์ ์๋ํด ์ฃผ์ธ์.',
+ };
+ }
+};
+
+// 2. ํ์๊ฐ์
+export const signUp = async (signUpData: {
+ email: string;
+ password: string;
+ displayName: string;
+ profileImgBase64?: string;
+}) => {
+ try {
+ const response = await fetch(`${API_URL}/auth/signup`, {
+ method: 'POST',
+ headers: HEADERS,
+ body: JSON.stringify({
+ email: signUpData.email,
+ password: signUpData.password,
+ displayName: signUpData.displayName,
+ profileImgBase64: signUpData.profileImgBase64,
+ }),
+ });
+ // ํ์๊ฐ์
์ฑ๊ณต
+ if (response.ok) {
+ const data: UserResponseValue = await response.json();
+ return {
+ data,
+ statusCode: response.status,
+ message: `${data.user.displayName}๋ ์ฆ๊ฑฐ์ด ์ผํ ๋์ธ์!`,
+ };
+ }
+ // ํ์๊ฐ์
์คํจ(์ด๋ฏธ ๋ฑ๋ก๋ ์ด๋ฉ์ผ or ์ ํจ์ฑ ์ค๋ฅ(ํด๋ผ์ด์ธํธ ์ ํจ์ฑ์์ ๋ง์) or apikey์ค๋ฅ)
+ const errorMessage: string = await response.json();
+ return { data: null, statusCode: response.status, message: errorMessage };
+
+ // ๊ธฐํ ์ค๋ฅ(์๋ฒ ๋ฌธ์ , url์ด ์๋ชป๋ ๊ฒฝ์ฐ)
+ } catch (error) {
+ console.log('Error while signup: ', error);
+ return {
+ data: null,
+ statusCode: 400,
+ message: 'ํ์๊ฐ์
๋์ค ์๋ฌ ๋ฐ์, ์ ์ ํ ๋ค์ ์๋ํด ์ฃผ์ธ์.',
+ };
+ }
+};
+
+// 3. ๋ก๊ทธ์์
+export const logOut = async (accessToken: string) => {
+ // accessToken ์ด ์๋ค๋ฉด ๋ก๊ทธ์์์ํ์ด๋ฏ๋ก ํจ์ ์ข
๋ฃ
+ try {
+ const response = await fetch(`${API_URL}/auth/logout`, {
+ method: 'POST',
+ headers: {
+ ...HEADERS,
+ Authorization: `Bearer ${accessToken}`,
+ },
+ });
+ if (response.ok) {
+ const data: true = await response.json(); // ๋น์ฐํ true
+ return {
+ data,
+ statusCode: response.status, //200
+ message: '์๋
ํ๊ฐ์ธ์!๐๏ธ๐๏ธ',
+ };
+ }
+ const errorMessage: string = await response.json();
+ return {
+ data: null,
+ statusCode: response.status,
+ message: errorMessage,
+ };
+ } catch (error) {
+ console.log('error while logout');
+ return {
+ data: null,
+ statusCode: 400,
+ message: '๋ก๊ทธ์์ ๋์ค ์๋ฌ ๋ฐ์, ์ ์ ํ ๋ค์ ์๋ํด ์ฃผ์ธ์.',
+ };
+ }
+};
+
+// 4. ์ธ์ฆํ์ธ
+export const authenticate = async (accessToken: string | null) => {
+ // ํ ํฐ์ด ์๋ ๊ฒฝ์ฐ
+ if (!accessToken) {
+ localStorage.removeItem('user');
+ return { data: null, statusCode: 400, message: '๋ก๊ทธ์ธ ํด์ฃผ์ธ์' };
+ }
+
+ // ํ ํฐ์ด ์๋๊ฒฝ์ฐ
+ try {
+ const response = await fetch(`${API_URL}/auth/me`, {
+ method: 'POST',
+ headers: {
+ ...HEADERS,
+ Authorization: `Bearer ${accessToken}`,
+ },
+ });
+
+ // ์ ํจํ ํ ํฐ์ด ๋ง๋ ๊ฒฝ์ฐ
+ if (response.ok) {
+ const data: AuthenticateResponseValue = await response.json();
+ return { data, statusCode: response.status, message: '' };
+ }
+
+ // ์ ํจํ ํ ํฐ์ด ์๋๊ฒฝ์ฐ(expired ๋๋ ์์์ ํ ํฐ์ ์
๋ ฅํ ๊ฒฝ์ฐ)
+ const errorMessage: string = await response.json();
+ return { data: null, statusCode: response.status, message: errorMessage };
+ // ๊ธฐํ ์ค๋ฅ(์๋ฒ ๋ฌธ์ , url์ด ์๋ชป๋ ๊ฒฝ์ฐ)
+ } catch (error) {
+ console.log('Error while authenticate: ', error);
+ return {
+ data: null,
+ statusCode: 400,
+ message: '์ธ์ฆ ๋์ค ์๋ฌ ๋ฐ์, ์ ์ ํ ๋ค์ ์๋ํด ์ฃผ์ธ์.',
+ };
+ }
+};
+
+// 5. ์ฌ์ฉ์ ์ ๋ณด์์
+export const editUser = async (
+ accessToken: string,
+ editData: {
+ displayName?: string;
+ profileImgBase64?: string;
+ oldPassword?: string;
+ newPassword?: string;
+ }
+) => {
+ try {
+ const response = await fetch(`${API_URL}/auth/user`, {
+ method: 'PUT',
+ headers: {
+ ...HEADERS,
+ Authorization: `Bearer ${accessToken}`,
+ },
+ body: JSON.stringify({
+ displayName: editData.displayName,
+ oldPassword: editData.oldPassword,
+ newPassword: editData.newPassword,
+ profileImgBase64: editData.profileImgBase64,
+ }),
+ });
+ if (response.ok) {
+ const data: UpdatedUserResponseValue = await response.json();
+ return {
+ data,
+ statusCode: response.status,
+ message: '',
+ };
+ }
+ // ๊ธฐ์กด ๋น๋ฒ์ด ์๋ง๋๊ฒฝ์ฐ, ๋ฑ๋ฑ
+ const errorMessage: string = await response.json();
+ return {
+ data: null,
+ statusCode: response.status,
+ message: errorMessage,
+ };
+ } catch (error) {
+ console.log('Error while EditUser: ', error);
+ return {
+ data: null,
+ statusCode: 400,
+ message: 'ํ์์ ๋ณด ์์ ๋์ค ์ค๋ฅ๋ฐ์, ์ ์ ํ ๋ค์ ์๋ํด ์ฃผ์ธ์.',
+ };
+ }
+};
diff --git a/src/api/bankApi.ts b/src/api/bankApi.ts
new file mode 100644
index 00000000..2ed86e46
--- /dev/null
+++ b/src/api/bankApi.ts
@@ -0,0 +1,153 @@
+import { API_URL, HEADERS } from '@/constants/constants';
+
+// ์ ํ ๊ฐ๋ฅํ ์ํ ๋ชฉ๋ก ์กฐํ
+export const getBankList = async (accessToken: string) => {
+ try {
+ const response = await fetch(`${API_URL}/account/banks`, {
+ method: 'GET',
+ headers: {
+ ...HEADERS,
+ Authorization: `Bearer ${accessToken}`,
+ },
+ });
+ if (response.ok) {
+ const data: Bank[] = await response.json();
+ return {
+ data,
+ statusCode: response.status,
+ message: '',
+ };
+ }
+ const errorMessage: string = await response.json();
+ return {
+ data: null,
+ statusCode: response.status,
+ message: errorMessage,
+ };
+ } catch (error) {
+ console.log('error while getting banks', error);
+ return {
+ data: null,
+ statusCode: 400,
+ message: '์ํ ๋ชฉ๋ก ์กฐํ ์ค ์๋ฌ ๋ฐ์, ์ ์ ํ ๋ค์ ์๋ํด ์ฃผ์ธ์.',
+ };
+ }
+};
+
+// ๊ณ์ข ๋ชฉ๋ก ๋ฐ ์์ก ์กฐํ
+export const getAccountListAndBalance = async (accessToken: string) => {
+ try {
+ const response = await fetch(`${API_URL}/account`, {
+ method: 'GET',
+ headers: {
+ ...HEADERS,
+ Authorization: `Bearer ${accessToken}`,
+ },
+ });
+ if (response.ok) {
+ const data: AccountsAndBalance = await response.json();
+ return {
+ data,
+ statusCode: response.status,
+ message: '',
+ };
+ }
+ const errorMessage: string = await response.json();
+ return {
+ data: null,
+ statusCode: response.status,
+ message: errorMessage,
+ };
+ } catch (error) {
+ console.log('error while getting account lists and balance', error);
+ return {
+ data: null,
+ statusCode: 400,
+ message: '๊ณ์ข ์กฐํ ์ค ์๋ฌ ๋ฐ์, ์ ์ ํ ๋ค์ ์๋ํด ์ฃผ์ธ์.',
+ };
+ }
+};
+
+// ๊ณ์ข ์ฐ๊ฒฐ
+export const connectAccount = async (
+ requestBody: {
+ bankCode: string;
+ accountNumber: string;
+ phoneNumber: string;
+ signature: boolean;
+ },
+ accessToken: string
+) => {
+ try {
+ const response = await fetch(`${API_URL}/account`, {
+ method: 'POST',
+ headers: {
+ ...HEADERS,
+ Authorization: `Bearer ${accessToken}`,
+ },
+ body: JSON.stringify(requestBody),
+ });
+ if (response.ok) {
+ const data: UserAccount = await response.json();
+ return {
+ data,
+ statusCode: response.status,
+ message: `${data.bankName}๊ณ์ข๋ฅผ ์ถ๊ฐํ์
จ์ต๋๋ค.`,
+ };
+ }
+ const errorMessage: string = await response.json();
+ return {
+ data: null,
+ statusCode: response.status,
+ message: errorMessage,
+ };
+ } catch (error) {
+ console.log('error while conncting bank account', error);
+ return {
+ data: null,
+ statusCode: 400,
+ message: '๊ณ์ข ์ถ๊ฐ ์ค ์๋ฌ๋ฐ์, ์ ์ ํ ๋ค์ ์๋ํด ์ฃผ์ธ์.',
+ };
+ }
+};
+
+// ๊ณ์ข ํด์ง
+export const deleteAccount = async (
+ requestBody: {
+ accountId: string;
+ signature: boolean;
+ },
+ accessToken: string
+) => {
+ try {
+ const response = await fetch(`${API_URL}/account`, {
+ method: 'DELETE',
+ headers: {
+ ...HEADERS,
+ Authorization: `Bearer ${accessToken}`,
+ },
+ body: JSON.stringify(requestBody),
+ });
+ if (response.ok) {
+ const data: true = await response.json();
+ return {
+ data,
+ statusCode: response.status,
+ message: '',
+ };
+ }
+ const errorMessage: string = await response.json();
+ return {
+ data: null,
+ statusCode: response.status,
+ message: errorMessage,
+ };
+ } catch (error) {
+ console.log('error while deleting an account', error);
+ return {
+ data: null,
+ statusCode: 400,
+ message: '๊ณ์ข ์ญ์ ์ค ์๋ฌ๋ฐ์, ์ ์ ํ ๋ค์ ์๋ํด ์ฃผ์ธ์.',
+ };
+ }
+};
diff --git a/src/api/transactionApi.ts b/src/api/transactionApi.ts
new file mode 100644
index 00000000..e7e5573c
--- /dev/null
+++ b/src/api/transactionApi.ts
@@ -0,0 +1,171 @@
+// ์ ํ ๊ฑฐ๋์ ๊ด๋ จ๋ api
+
+import { API_URL, HEADERS } from '@/constants/constants';
+
+export async function searchProducts({ searchText }: { searchText: string }) {
+ try {
+ const response = await fetch(`${API_URL}/products/search`, {
+ method: 'POST',
+ headers: HEADERS,
+ body: JSON.stringify({ searchText }),
+ });
+ if (response.ok) {
+ const data: Product[] = await response.json();
+ return { data, statusCode: response.status, message: '' };
+ }
+ const errorMessage: string = await response.json();
+ return { data: null, statusCode: response.status, message: errorMessage };
+ } catch (error) {
+ console.log('Error while searching products: ', error);
+ return {
+ data: null,
+ statusCode: 400,
+ message: '์ํ ๊ฒ์ ๋์ค ์๋ฌ๋ฐ์, ์ ์ ํ ๋ค์ ์๋ํด ์ฃผ์ธ์.',
+ };
+ }
+}
+
+export async function buyProduct(
+ productId: string,
+ accountId: string,
+ accessToken: string
+) {
+ try {
+ const requestBody = {
+ productId,
+ accountId,
+ };
+
+ const response = await fetch(`${API_URL}/products/buy`, {
+ method: 'POST',
+ headers: {
+ ...HEADERS,
+ Authorization: `Bearer ${accessToken}`,
+ },
+ body: JSON.stringify(requestBody),
+ });
+
+ if (response.ok) {
+ const data: true = await response.json();
+ return { data, statusCode: response.status, message: '' };
+ }
+
+ const errorMessage: string = await response.json();
+ return { data: null, statusCode: response.status, message: errorMessage };
+ } catch (error) {
+ console.log('Error while buyProduct: ', error);
+ return {
+ data: null,
+ statusCode: 400,
+ message: '์ ํ ๊ฑฐ๋ ๋์ค ์๋ฌ ๋ฐ์, ์ ์ ํ ๋ค์ ์๋ํด ์ฃผ์ธ์.',
+ };
+ }
+}
+
+export async function getOrderList(accessToken: string) {
+ try {
+ const response = await fetch(`${API_URL}/products/transactions/details`, {
+ method: 'GET',
+ headers: {
+ ...HEADERS,
+ Authorization: `Bearer ${accessToken}`,
+ },
+ });
+ if (response.ok) {
+ const data: TransactionDetail[] = await response.json();
+ return { data, statusCode: response.status, message: '' };
+ }
+ const errorMessage: string = await response.json();
+ return { data: null, statusCode: response.status, message: errorMessage };
+ } catch (error) {
+ console.log('Error while getting order list: ', error);
+ return {
+ data: null,
+ statusCode: 400,
+ message: '์ฃผ๋ฌธ๋ด์ญ ์กฐํ ์ค ์๋ฌ ๋ฐ์, ์ ์ ํ ๋ค์ ์๋ํด ์ฃผ์ธ์.',
+ };
+ }
+}
+
+export async function getOrderDetail(accessToken: string, detailId: string) {
+ try {
+ const response = await fetch(`${API_URL}/products/transactions/detail`, {
+ method: 'POST',
+ headers: {
+ ...HEADERS,
+ Authorization: `Bearer ${accessToken}`,
+ },
+ body: JSON.stringify({ detailId }),
+ });
+ if (response.ok) {
+ const data: TransactionDetail = await response.json();
+ return { data, statusCode: response.status, message: '' };
+ }
+ const errorMessage: string = await response.json();
+ return { data: null, statusCode: response.status, message: errorMessage };
+ } catch (error) {
+ console.log('Error while getting transaction detail: ', error);
+ return {
+ data: null,
+ statusCode: 400,
+ message: '๊ฑฐ๋ ๋ด์ญ ์์ธ ์กฐํ ์ค ์๋ฌ ๋ฐ์, ์ ์ ํ ๋ค์ ์๋ํด ์ฃผ์ธ์.',
+ };
+ }
+}
+
+export const confirmOrder = async (accessToken: string, detailId: string) => {
+ try {
+ const res = await fetch(`${API_URL}/products/ok`, {
+ method: 'POST',
+ headers: {
+ ...HEADERS,
+ Authorization: `Bearer ${accessToken}`,
+ },
+ body: JSON.stringify({ detailId }),
+ });
+
+ if (res.ok) {
+ const data: true = await res.json();
+ return { data, statusCode: res.status, message: '' };
+ }
+ const errorMessage: string = await res.json();
+ return { data: null, statusCode: res.status, message: errorMessage };
+ } catch (error) {
+ console.log('Error while confirming a order: ', error);
+ return {
+ data: null,
+ statusCode: 400,
+ message: '๊ตฌ๋งคํ์ ์๋ ์ค ์๋ฌ ๋ฐ์, ์ ์ ํ ๋ค์ ์๋ํด ์ฃผ์ธ์.',
+ };
+ }
+};
+// ์ ํ์ญ์ api
+export async function cancelOrder(detailId: string, accessToken: string) {
+ try {
+ console.log(detailId, accessToken);
+ const response = await fetch(
+ 'https://asia-northeast3-heropy-api.cloudfunctions.net/api/products/cancel',
+ {
+ method: 'POST',
+ headers: {
+ ...HEADERS,
+ Authorization: `Bearer ${accessToken}`,
+ },
+ body: JSON.stringify({ detailId }),
+ }
+ );
+ if (response.ok) {
+ const data: true = await response.json();
+ return { data, statusCode: response.status, message: 'success' };
+ }
+ const errorMessage: string = await response.json();
+ return { data: null, statusCode: response.status, message: errorMessage };
+ } catch (error) {
+ console.log('error while cancelling order', error);
+ return {
+ data: null,
+ statusCode: 400,
+ message: '๊ฑฐ๋ ์ทจ์ ์ค ์๋ฌ๋ฐ์ ์ ์ํ ๋ค์ ์๋ํด ์ฃผ์ธ์.',
+ };
+ }
+}
diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx
new file mode 100644
index 00000000..fff9e081
--- /dev/null
+++ b/src/components/Footer.tsx
@@ -0,0 +1,17 @@
+export default function Footer() {
+ return (
+
+ );
+}
diff --git a/src/components/ImageSlider.tsx b/src/components/ImageSlider.tsx
new file mode 100644
index 00000000..996776c6
--- /dev/null
+++ b/src/components/ImageSlider.tsx
@@ -0,0 +1,42 @@
+import { SLIDES } from '@/constants/constants';
+import Carousel from 'nuka-carousel';
+import { useNavigate } from 'react-router-dom';
+
+export default function ImageSlider() {
+ const navigate = useNavigate();
+ return (
+
+ {SLIDES.map((slide) => (
+ navigate(`${slide.href}`)}
+ />
+ ))}
+
+ );
+}
diff --git a/src/components/Layout.tsx b/src/components/Layout.tsx
new file mode 100644
index 00000000..e1f17267
--- /dev/null
+++ b/src/components/Layout.tsx
@@ -0,0 +1,23 @@
+import { Outlet } from 'react-router-dom';
+import Navbar from '@/components/Navbar';
+import { Toaster } from 'react-hot-toast';
+import Footer from '@/components/Footer';
+
+export default function Layout() {
+ return (
+ <>
+
+
+ >
+ );
+}
diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx
new file mode 100644
index 00000000..5a5bf6df
--- /dev/null
+++ b/src/components/Navbar.tsx
@@ -0,0 +1,88 @@
+/* eslint-disable react-hooks/exhaustive-deps */
+import { Link } from 'react-router-dom';
+import { userStore } from '@/store';
+import Search from '@/components/Search';
+import SubNavbar from '@/components/SubNavbar';
+import { SUB_MENUS } from '@/constants/constants';
+import ProfileImage from '@/components/ui/ProfileImage';
+import { useState } from 'react';
+import { logOut } from '@/api/authApi';
+import LoadingSpinner from '@/components/ui/LoadingSpinner';
+import toast from 'react-hot-toast';
+
+export default function Navbar() {
+ // store์์ ํ์ํ ๋ฉ์๋(๋ก๊ทธ์์, ์ธ์ฆ), ์ ์ ธ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ด
+ const { userInfo, setUser } = userStore();
+ const [isLogoutting, setIsLogoutting] = useState(false);
+
+ const handleLogout = async () => {
+ setIsLogoutting(true);
+ toast.loading('๋ก๊ทธ์์ ์ค', { id: 'logout' });
+ const res = await logOut(userInfo?.accessToken as string);
+ // ๋ก๊ทธ์์์ฑ๊ณต
+ if (res.statusCode === 200) {
+ toast.success(res.message, { id: 'logout' });
+ setIsLogoutting(false);
+ // ํด๋ผ์ด์ธํธ์ ์ ์ญ user๋ฅผ null๋ก
+ setUser(null);
+ // ๋ก์ปฌ์ ์ฅ์ user์ญ์
+ localStorage.removeItem('user');
+ return;
+ }
+ // ๋ก๊ทธ์์ ์คํจ
+ toast.error(res.message, { id: 'logout' });
+ setIsLogoutting(false);
+ };
+
+ return (
+ <>
+
+
+
+
+
+
+ {/* ์ ์ ธ๊ฐ ๋ก๊ทธ์ธ ์ฌ๋ถ */}
+ {userInfo ? (
+ // ๋ก๊ทธ์ธ ๋์ด์๋ ๊ฒฝ์ฐ
+ <>
+ -
+
+ {isLogoutting ? (
+
+ ) : (
+ '๋ก๊ทธ์์'
+ )}
+
+
+
+ {/* ๊ด๋ฆฌ์ ์ฌ๋ถ */}
+ {userInfo.isAdmin ? (
+ // ๊ด๋ฆฌ์์ธ ๊ฒฝ์ฐ
+ ๊ด๋ฆฌ์
+ ) : (
+ // ๊ด๋ฆฌ์๊ฐ ์๋๊ฒฝ์ฐ
+ <>>
+ )}
+
+ {/* ๋ก๊ทธ์ธํ ํ์์ ๋ณด */}
+ {userInfo.user.displayName}๋
+
+ >
+ ) : (
+ // ๋ก๊ทธ์ธ์ด ๋์ด์์ง ์์ ๊ฒฝ์ฐ
+ <>
+ -
+ ๋ก๊ทธ์ธ
+
+ -
+ ํ์๊ฐ์
+
+ >
+ )}
+
+
+
+ >
+ );
+}
diff --git a/src/components/Search.tsx b/src/components/Search.tsx
new file mode 100644
index 00000000..46c948f2
--- /dev/null
+++ b/src/components/Search.tsx
@@ -0,0 +1,44 @@
+import { useState } from 'react';
+import { BiSearch } from 'react-icons/bi';
+import { useNavigate } from 'react-router-dom';
+
+export default function Search() {
+ const navigate = useNavigate();
+ // ๊ฒ์์ด๋ฅผ state์ ์ ์ฅ
+ const [searchText, setSearchText] = useState('');
+
+ // ๊ฒ์ input์์ ๋ณํ๊ฐ ๋ฐ์ํ ๋ ์
๋ ฅ๊ฐ์ state์ ์ ์ฅ
+ const handleChange = (event: React.ChangeEvent) => {
+ setSearchText(event.target.value);
+ };
+
+ // ๊ฒ์(๊ฒ์ ์์ด์ฝ์ ๋๋ฅด๊ฑฐ๋ ์ํฐ๋ฅผ ๋๋ ์ ๋)
+ const handleSearch = async (event: React.FormEvent) => {
+ event.preventDefault();
+ if (searchText.trim() === '') {
+ setSearchText('');
+ return;
+ }
+ navigate(`/products/search`, { state: searchText });
+ setSearchText('');
+ return;
+ };
+
+ return (
+
+ );
+}
diff --git a/src/components/SingleUser.tsx b/src/components/SingleUser.tsx
new file mode 100644
index 00000000..b84d477e
--- /dev/null
+++ b/src/components/SingleUser.tsx
@@ -0,0 +1,36 @@
+import ProfileImage from '@/components/ui/ProfileImage';
+
+interface SingleUserProps {
+ email: string;
+ displayName: string;
+ profileImg: string;
+ spentMoney: number;
+}
+
+export default function SingleUser({
+ email,
+ displayName,
+ profileImg,
+ spentMoney,
+}: SingleUserProps) {
+ return (
+
+
+
+ |
+ {email} |
+ {displayName} |
+
+ {spentMoney >= 300000 ? (
+ spentMoney >= 500000 ? (
+ ๐ฐVVIP๐ฐ
+ ) : (
+ ๐ฐVIP
+ )
+ ) : (
+ '์ผ๋ฐํ์'
+ )}
+ |
+
+ );
+}
diff --git a/src/components/SubNavbar.tsx b/src/components/SubNavbar.tsx
new file mode 100644
index 00000000..266996ab
--- /dev/null
+++ b/src/components/SubNavbar.tsx
@@ -0,0 +1,29 @@
+import { Link } from 'react-router-dom';
+
+interface SubNavbarProps {
+ menus: {
+ label: string;
+ href: string;
+ }[];
+ gray?: boolean;
+}
+
+export default function SubNavbar({ menus, gray }: SubNavbarProps) {
+ return (
+
+ );
+}
diff --git a/src/components/product/ProductBar.tsx b/src/components/product/ProductBar.tsx
new file mode 100644
index 00000000..57cbc2fb
--- /dev/null
+++ b/src/components/product/ProductBar.tsx
@@ -0,0 +1,62 @@
+import { DICTIONARY_SHOES, PRODUCT_BRAND } from '@/constants/constants';
+import Breadcrumbs from '@/components/ui/Breadcrumbs';
+import SectionTitle from '@/components/ui/SectionTitle';
+import Button from '@/components/ui/Button';
+import ProductSortOptions from '@/components/product/ProductSortOptions';
+
+interface ProductBarProps {
+ searchText?: string;
+ category?: string;
+ productNumber?: number;
+ handleBrand?: (brandValue: string) => void;
+ selectedBrand?: string;
+ handleSortByPrice: (sort: string) => void;
+ brand?: string;
+}
+
+export default function ProductBar({
+ searchText,
+ category,
+ productNumber,
+ handleBrand,
+ selectedBrand,
+ handleSortByPrice,
+ brand,
+}: ProductBarProps) {
+ return (
+
+ {searchText ? (
+
+ ) : (
+ <>
+
+ >
+ )}
+
+
+
+
+
+
์ด {productNumber} ๊ฐ
+
+
+
+ {searchText ? (
+ <>>
+ ) : (
+
+ {PRODUCT_BRAND.map((brand) => (
+
+ )}
+
+ );
+}
diff --git a/src/components/product/ProductCard.tsx b/src/components/product/ProductCard.tsx
new file mode 100644
index 00000000..6ac4db92
--- /dev/null
+++ b/src/components/product/ProductCard.tsx
@@ -0,0 +1,47 @@
+import { priceBeforeDiscount } from '@/lib/ceilPrice';
+
+interface ProductCardProps {
+ title: string;
+ price: number;
+ thumbnail: string | null;
+ discountRate: number;
+ isSoldOut: boolean;
+}
+
+export default function ProductCard({
+ discountRate,
+ price,
+ thumbnail,
+ title,
+ isSoldOut,
+}: ProductCardProps) {
+ return (
+
+
+
+ {title}
+
+
+ {price.toLocaleString('ko-KR')}์
+
+ {priceBeforeDiscount(price, discountRate)}์
+
+
+
+
+ );
+}
diff --git a/src/components/product/ProductSection.tsx b/src/components/product/ProductSection.tsx
new file mode 100644
index 00000000..0ffd9230
--- /dev/null
+++ b/src/components/product/ProductSection.tsx
@@ -0,0 +1,155 @@
+import { useEffect, useMemo, useState } from 'react';
+import { getProducts } from '@/api/adminApi';
+import { Link } from 'react-router-dom';
+import ProductBar from '@/components/product/ProductBar';
+import ProductCard from '@/components/product/ProductCard';
+import Skeleton from '@/components/ui/Skeleton';
+import toast from 'react-hot-toast';
+import SectionTitle from '@/components/ui/SectionTitle';
+
+interface ProductSectionProps {
+ category?: string;
+ related?: boolean;
+ productId?: string;
+ productTitle?: string;
+}
+
+export default function ProductSection({
+ category,
+ related,
+ productId,
+ productTitle,
+}: ProductSectionProps) {
+ const [products, setProducts] = useState();
+ const [isLoading, setIsLoading] = useState(false);
+ const [brand, setBrand] = useState('all');
+ const [sortByPrice, setSortByPrice] = useState('');
+
+ // ๊ฐ๊ฒฉ ์ ๋ ฌ ์ ํ
+ const handleSortByPrice = (sort: string) => {
+ setSortByPrice(sort);
+ };
+
+ // ๋ธ๋๋ ์ ํ
+ const handleBrand = (brandValue: string) => {
+ setBrand(brandValue);
+ };
+
+ useEffect(() => {
+ setBrand('all');
+ setIsLoading(true);
+ async function fetchData() {
+ const res = await getProducts();
+ if (res.statusCode === 200) {
+ // ์นดํ
๊ณ ๋ฆฌ์ ๋ฐ๋ผ์ products์ setting
+ const categoryFilteredProducts = (res.data as Product[]).filter(
+ (product) => (category ? product.tags[0] === category : product)
+ );
+ setProducts(categoryFilteredProducts);
+
+ // ์ค์ผ๋ ํค์ ๊ฐฏ์๋ฅผ ๋ฏธ๋ฆฌ ์๊ธฐ ์ํด ๋ก์ปฌ์ ์ฅ์์ ๊ฐ ์นดํ
๊ณ ๋ฆฌ๋ณ ์ํ์๋ฅผ ์ ์ฅ
+ localStorage.setItem(
+ category ? category : 'all',
+ JSON.stringify(categoryFilteredProducts.length)
+ );
+ setIsLoading(false);
+ return;
+ }
+ setIsLoading(false);
+ toast.error(res.message, { id: 'getProducts' });
+ }
+ fetchData();
+ }, [category]);
+
+ // ๋ก์ปฌ ์ ์ฅ์์ ์นดํ
๊ณ ๋ฆฌ๋ณ ์ํ ๊ฐฏ์๋ฅผ ๊ฐ์ ธ์ด / ์๋ ๊ฒฝ์ฐ 10๊ฐ
+ const skeletonLength = new Array(
+ JSON.parse(localStorage.getItem(category ? category : 'all') ?? '10')
+ ).fill(0);
+
+ // ํํฐ๋ง ์๋ฃ๋ ์ํ๋ค
+ const filteredProducts = useMemo(
+ () =>
+ products?.filter((product) =>
+ brand === 'all' ? product : product.tags[1] === brand
+ ),
+ [brand, products]
+ );
+ // ๊ฐ๊ฒฉ์ sorting
+ const sortedFilteredProducts = useMemo(
+ () =>
+ filteredProducts?.sort((a, b) =>
+ sortByPrice === 'lowPrice' ? a.price - b.price : b.price - a.price
+ ),
+ [filteredProducts, sortByPrice]
+ );
+
+ return (
+
+ {/* ProductDetail ์ปดํฌ๋ํธ์์ related ์ต์
์ props๋ก ์ ๋ฌํ ๊ฒฝ์ฐ */}
+ {related ? (
+
+ ) : (
+
+ )}
+
+
+ {isLoading ? (
+ <>
+ {skeletonLength.map((_el, inex) => (
+
+ ))}
+ >
+ ) : (
+ <>
+ {related // ProductDetail ์ปดํฌ๋ํธ์์ related ์ต์
์ props๋ก ์ ๋ฌํ ๊ฒฝ์ฐ
+ ? sortedFilteredProducts
+ ?.filter((product) => product.id !== productId) // ์๊ธฐ ์์ ์ ์ ์ธ
+ .sort(() => Math.random() - 0.5) // ์์ ์์ด์ ์ถ์ฒ ์๊ณ ๋ฆฌ์ฆ ์ฒ๋ผ ๋ณด์ด๊ฒ
+ .slice(0, 10) // ์์ 10๊ฐ๋ง ๋ณด์ฌ์ค
+ .map((product) => (
+ -
+
+
+
+
+ ))
+ : sortedFilteredProducts?.map((product) => (
+ -
+
+
+
+
+ ))}
+ >
+ )}
+
+
+ );
+}
diff --git a/src/components/product/ProductSortOptions.tsx b/src/components/product/ProductSortOptions.tsx
new file mode 100644
index 00000000..7f920d36
--- /dev/null
+++ b/src/components/product/ProductSortOptions.tsx
@@ -0,0 +1,23 @@
+import { PRODUCT_SORT } from '@/constants/constants';
+
+interface SortOptionsProps {
+ handleSortByPrice: (brandValue: string) => void;
+}
+
+export default function ProductSortOptions({
+ handleSortByPrice,
+}: SortOptionsProps) {
+ return (
+
+ {PRODUCT_SORT.map((sort) => (
+
handleSortByPrice(sort.value)}
+ >
+ {sort.name}
+
+ ))}
+
+ );
+}
diff --git a/src/components/ui/Breadcrumbs.tsx b/src/components/ui/Breadcrumbs.tsx
new file mode 100644
index 00000000..ef453789
--- /dev/null
+++ b/src/components/ui/Breadcrumbs.tsx
@@ -0,0 +1,37 @@
+import { DICTIONARY_SHOES } from '@/constants/constants';
+import { Link } from 'react-router-dom';
+
+interface BreadcrumbsProps {
+ category?: string;
+ brand?: string;
+ name?: string;
+}
+
+export default function Breadcrumbs({
+ category,
+ brand,
+ name,
+}: BreadcrumbsProps) {
+ return (
+ <>
+ {category ? (
+
+
+ ํฌ๋ ์ด์ง 11
+
+
+
+ {` / ${DICTIONARY_SHOES[category]}`}
+
+
+
{brand ? ` / ${brand}` : ''}
+
{name ? ` / ${name}` : ''}
+
+ ) : (
+
+ ํฌ๋ ์ด์ง 11
+
+ )}
+ >
+ );
+}
diff --git a/src/components/ui/Button.tsx b/src/components/ui/Button.tsx
new file mode 100644
index 00000000..17d4e5dd
--- /dev/null
+++ b/src/components/ui/Button.tsx
@@ -0,0 +1,35 @@
+interface ButtonProps {
+ text: string | JSX.Element;
+ secondary?: boolean;
+ value?: string;
+ onClick?: (
+ event: React.MouseEvent
+ ) => void | Promise;
+ disabled?: boolean;
+ submit?: boolean;
+}
+
+export default function Button({
+ text,
+ secondary,
+ disabled,
+ onClick,
+ value,
+ submit,
+}: ButtonProps) {
+ return (
+
+ );
+}
diff --git a/src/components/ui/CrazyLoading.tsx b/src/components/ui/CrazyLoading.tsx
new file mode 100644
index 00000000..01ec4b21
--- /dev/null
+++ b/src/components/ui/CrazyLoading.tsx
@@ -0,0 +1,11 @@
+export default function CrazyLoading() {
+ return (
+
+
+ CRAZY 1oad
+ 1
+ ng...
+
+
+ );
+}
diff --git a/src/components/ui/ImageUpload.tsx b/src/components/ui/ImageUpload.tsx
new file mode 100644
index 00000000..4c11dfa9
--- /dev/null
+++ b/src/components/ui/ImageUpload.tsx
@@ -0,0 +1,19 @@
+interface ImageUploadProps {
+ onChange: (event: React.ChangeEvent) => void;
+ name?: string;
+ korName: string;
+}
+
+export default function ImageUpload({
+ name,
+ onChange,
+ korName,
+}: ImageUploadProps) {
+ return (
+
+
+
+
+
+ );
+}
diff --git a/src/components/ui/Input.tsx b/src/components/ui/Input.tsx
new file mode 100644
index 00000000..b3f766ac
--- /dev/null
+++ b/src/components/ui/Input.tsx
@@ -0,0 +1,30 @@
+interface InputProps {
+ maxLength?: number;
+ placeholder?: string;
+ type?: string;
+ name: string;
+ value?: string | number;
+ onChange?: (event: React.ChangeEvent) => void;
+}
+
+export default function Input({
+ placeholder,
+ type,
+ name,
+ value,
+ maxLength,
+ onChange,
+}: InputProps) {
+ return (
+
+ );
+}
diff --git a/src/components/ui/LoadingSpinner.tsx b/src/components/ui/LoadingSpinner.tsx
new file mode 100644
index 00000000..d566851f
--- /dev/null
+++ b/src/components/ui/LoadingSpinner.tsx
@@ -0,0 +1,7 @@
+interface LoadingSpinnerProps {
+ color: 'white' | 'accent';
+}
+
+export default function LoadingSpinner({ color }: LoadingSpinnerProps) {
+ return ;
+}
diff --git a/src/components/ui/ProfileImage.tsx b/src/components/ui/ProfileImage.tsx
new file mode 100644
index 00000000..194d9f0c
--- /dev/null
+++ b/src/components/ui/ProfileImage.tsx
@@ -0,0 +1,16 @@
+interface ProfileImageProps {
+ src?: string | null;
+ small?: boolean;
+}
+
+export default function ProfileImage({ src, small }: ProfileImageProps) {
+ return (
+
+ );
+}
diff --git a/src/components/ui/SectionTitle.tsx b/src/components/ui/SectionTitle.tsx
new file mode 100644
index 00000000..d9b932b5
--- /dev/null
+++ b/src/components/ui/SectionTitle.tsx
@@ -0,0 +1,7 @@
+export default function SectionTitle({
+ text = '๋ชจ๋ ์ํ',
+}: {
+ text?: string;
+}) {
+ return {text}
;
+}
diff --git a/src/components/ui/Select.tsx b/src/components/ui/Select.tsx
new file mode 100644
index 00000000..f9192b56
--- /dev/null
+++ b/src/components/ui/Select.tsx
@@ -0,0 +1,38 @@
+import { IoIosArrowDown } from 'react-icons/io';
+
+interface SelectProps {
+ name: string;
+ options: {
+ name: string;
+ value: string;
+ }[];
+ onChange: (event: React.ChangeEvent) => void;
+ value: string;
+}
+
+export default function Select({
+ options,
+ onChange,
+ value,
+ name,
+}: SelectProps) {
+ return (
+
+
+
+
+
+
+ );
+}
diff --git a/src/components/ui/Skeleton.tsx b/src/components/ui/Skeleton.tsx
new file mode 100644
index 00000000..2a84bfea
--- /dev/null
+++ b/src/components/ui/Skeleton.tsx
@@ -0,0 +1,7 @@
+export default function Skeleton() {
+ return (
+
+ );
+}
diff --git a/src/constants/constants.ts b/src/constants/constants.ts
new file mode 100644
index 00000000..9b06d287
--- /dev/null
+++ b/src/constants/constants.ts
@@ -0,0 +1,159 @@
+// API
+export const API_URL =
+ 'https://asia-northeast3-heropy-api.cloudfunctions.net/api';
+
+export const HEADERS = {
+ 'content-type': 'application/json',
+ apikey: 'KDT5_nREmPe9B',
+ username: 'KDT5_Team1',
+};
+
+// ์ด๋ฏธ์ง ์ฌ๋ผ์ด๋
+
+export const SLIDES = [
+ {
+ id: 0,
+ href: '/products/soccer/PQDbxl8TerMV7dbcHjFM',
+ label: 'ํธ๋งํจ์ณ',
+ },
+ {
+ id: 1,
+ href: '/products/soccer/TswEFE3gibavTlGMFUuA',
+ label: '์๋๋ค์คํฌํ',
+ },
+ {
+ id: 2,
+ href: '#',
+ label: 'ํจ์บ ',
+ },
+ {
+ id: 3,
+ href: '/products/soccer/ea3COhwuw0YHtY5ADuyg',
+ label: '์๋๋ค์คํ๋ ๋ฐํฐ',
+ },
+ {
+ id: 4,
+ href: '/products/soccer/bZ5fc4ywRgWCxIJJEowC',
+ label: '๋์ดํค๋จธํ๋ฆฌ์ผ',
+ },
+];
+
+// ์ด๋๋ฏผ ์ด๋ฉ์ผ ๋ชฉ๋ก
+export const ADMINS = [
+ 'admin@naver.com',
+ 'admin1@naver.com',
+ 'admin2@naver.com',
+ 'admin3@naver.com',
+ 'admin4@naver.com',
+];
+
+export const EMAIL_REGEX =
+ /^[0-9a-zA-Z]([-_\\.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_\\.]?[0-9a-zA-Z])*\.[a-zA-Z]{2,3}$/i;
+
+export const SUB_MENUS = [
+ {
+ label: '์ถ๊ตฌํ',
+ href: '/products/soccer',
+ },
+ {
+ label: 'ํ์ดํ',
+ href: '/products/footsal',
+ },
+ {
+ label: '์ด๋ํ/์ฌ๋ฆฌํผ',
+ href: '/products/sneakers',
+ },
+];
+
+// myAccount nav menu
+export const SUB_MENUS_MYACCOUNT = [
+ {
+ label: '๋ด ์ ๋ณด',
+ href: '/myaccount/info',
+ },
+ {
+ label: '๋น๋ฐ๋ฒํธ ๋ณ๊ฒฝ',
+ href: '/myaccount/changepw',
+ },
+ {
+ label: '๊ณ์ข ์กฐํ / ํด์ง',
+ href: '/myaccount/accountList',
+ },
+ {
+ label: '๊ณ์ข ์ฐ๊ฒฐ',
+ href: '/myaccount/connectAccount',
+ },
+ {
+ label: '๊ตฌ๋งค ๋ด์ญ',
+ href: '/myaccount/orderList',
+ },
+];
+
+// admin ํจ๋ sub anvbar
+export const SUB_MENUS_ADMIN = [
+ {
+ label: 'ํ์ ์ ๋ณด',
+ href: '/admin/clients',
+ },
+ {
+ label: '์ํ ๊ด๋ฆฌ',
+ href: '/admin/products',
+ },
+ {
+ label: '์ํ ์ถ๊ฐ',
+ href: '/admin/addproduct',
+ },
+ {
+ label: '๊ฑฐ๋ ๋ด์ญ',
+ href: '/admin/alltransactions',
+ },
+];
+
+export const SELECT_CATEGORY = [
+ { name: '์นดํ
๊ณ ๋ฆฌ ์ ํ*', value: 'category' },
+ { name: '์ถ๊ตฌํ', value: 'soccer' },
+ { name: 'ํ์ดํ', value: 'footsal' },
+ { name: '์ด๋ํ/์ฌ๋ฆฌํผ', value: 'sneakers' },
+];
+export const SELECT_BRAND = [
+ { name: '๋ธ๋๋ ์ ํ*', value: 'brand' },
+ { name: '๋์ดํค', value: 'nike' },
+ { name: '์๋๋ค์ค', value: 'adidas' },
+ { name: '๋ฏธ์ฆ๋
ธ', value: 'mizno' },
+ { name: 'ํธ๋ง', value: 'puma' },
+];
+
+interface Translate {
+ [key: string]: string;
+}
+export const DICTIONARY_SHOES: Translate = {
+ soccer: '์ถ๊ตฌํ',
+ footsal: 'ํ์ดํ',
+ sneakers: '์ด๋ํ/์ฌ๋ฆฌํผ',
+};
+
+// ์ํ ์ ๋ณด
+export const BANKS = [
+ { name: 'KB๊ตญ๋ฏผ์ํ', code: '004', digits: [3, 2, 4, 3] },
+ { name: '์ ํ์ํ', code: '088', digits: [3, 3, 6] },
+ { name: '์ฐ๋ฆฌ์ํ', code: '020', digits: [4, 3, 6] },
+ { name: 'ํ๋์ํ', code: '081', digits: [3, 6, 5] },
+ { name: '์ผ์ด๋ฑ
ํฌ', code: '089', digits: [3, 3, 6] },
+ { name: '์นด์นด์ค๋ฑ
ํฌ', code: '090', digits: [4, 2, 7] },
+ { name: 'NH๋ํ์ํ', code: '011', digits: [3, 4, 4, 2] },
+];
+
+// ์ํ sorting ์ต์
+export const PRODUCT_SORT = [
+ { name: '๋ฎ์๊ฐ๊ฒฉ', value: 'lowPrice' },
+ { name: '๋์๊ฐ๊ฒฉ', value: 'highPrice' },
+];
+
+// ์ํ brand sorting ์ต์
+export const PRODUCT_BRAND = [
+ { name: '๋ชจ๋', value: 'all' },
+ { name: '๋์ดํค', value: 'nike' },
+ { name: '์๋๋ค์ค', value: 'adidas' },
+ { name: '๋ฏธ์ฆ๋
ธ', value: 'mizno' },
+ { name: 'ํธ๋ง', value: 'puma' },
+];
diff --git a/src/index.css b/src/index.css
new file mode 100644
index 00000000..ce9cf86d
--- /dev/null
+++ b/src/index.css
@@ -0,0 +1,53 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+.loading-white {
+ width: 30px;
+ height: 30px;
+ margin: auto;
+ border: 4px solid white;
+ border-top-color: transparent;
+ border-radius: 50%;
+ animation: loader 1s infinite;
+}
+.loading-accent {
+ width: 30px;
+ height: 30px;
+ margin: auto;
+ border: 4px solid #e41717;
+ border-top-color: transparent;
+ border-radius: 50%;
+ animation: loader 1s infinite;
+}
+@keyframes loader {
+ 0% {
+ transform: rotate(0deg);
+ }
+ 100% {
+ transform: rotate(360deg);
+ }
+}
+
+table {
+ width: 100%;
+ border-collapse: collapse;
+ table-layout: auto;
+}
+
+thead {
+ background-color: #efe9e9;
+}
+
+th,
+td {
+ padding: 16px 8px;
+ border: 1px solid #ddd;
+ text-align: center;
+}
+
+.toaster {
+ border: 2px solid #320b0b;
+ color: '#713200';
+ width: 500px;
+}
diff --git a/src/lib/ceilPrice.ts b/src/lib/ceilPrice.ts
new file mode 100644
index 00000000..63cba31b
--- /dev/null
+++ b/src/lib/ceilPrice.ts
@@ -0,0 +1,5 @@
+export function priceBeforeDiscount(price: number, discountRate: number) {
+ return (
+ Math.ceil((price * 100) / (100 - discountRate) / 1000) * 1000
+ ).toLocaleString('ko-KR');
+}
diff --git a/src/lib/time.ts b/src/lib/time.ts
new file mode 100644
index 00000000..ab470608
--- /dev/null
+++ b/src/lib/time.ts
@@ -0,0 +1,36 @@
+export function convertToMilliseconds(dateString: string) {
+ // Convert string to Date object
+ const date = new Date(dateString);
+
+ // Get timestamp in milliseconds
+ const timestampMs = date.getTime();
+
+ return timestampMs;
+}
+
+export function convertToHumanReadable(dateString: string) {
+ // Convert string to Date object
+ const date = new Date(dateString);
+
+ // Extract date components
+ const year = date.getFullYear();
+ const month = date.getMonth() + 1; // Months are zero-based
+ const day = date.getDate();
+
+ // Extract time components
+ const hours = date.getHours();
+ const minutes = date.getMinutes();
+
+ // Format the date and time
+ const formattedDate = `${year}.${month.toString().padStart(2, '0')}.${day
+ .toString()
+ .padStart(2, '0')}`;
+ const formattedTime = `${hours.toString().padStart(2, '0')}:${minutes
+ .toString()
+ .padStart(2, '0')}`;
+
+ // Combine the formatted date and time
+ const humanReadableDateTime = `${formattedDate} / ${formattedTime}`;
+
+ return humanReadableDateTime;
+}
diff --git a/src/main.tsx b/src/main.tsx
new file mode 100644
index 00000000..34671f92
--- /dev/null
+++ b/src/main.tsx
@@ -0,0 +1,13 @@
+import React from 'react';
+import ReactDOM from 'react-dom/client';
+import '@/index.css';
+import { BrowserRouter } from 'react-router-dom';
+import App from '@/App';
+
+ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
+
+
+
+
+
+);
diff --git a/src/routes/Home.tsx b/src/routes/Home.tsx
new file mode 100644
index 00000000..b5b5a692
--- /dev/null
+++ b/src/routes/Home.tsx
@@ -0,0 +1,12 @@
+/* eslint-disable react-hooks/exhaustive-deps */
+import ImageSlider from '@/components/ImageSlider';
+import ProductSection from '@/components/product/ProductSection';
+
+export default function Home() {
+ return (
+ <>
+
+
+ >
+ );
+}
diff --git a/src/routes/Login.tsx b/src/routes/Login.tsx
new file mode 100644
index 00000000..12af5685
--- /dev/null
+++ b/src/routes/Login.tsx
@@ -0,0 +1,111 @@
+/* eslint-disable react-hooks/exhaustive-deps */
+import { useState } from 'react';
+import { useNavigate } from 'react-router-dom';
+import { userStore } from '@/store';
+import { signIn } from '@/api/authApi';
+import { ADMINS, EMAIL_REGEX } from '@/constants/constants';
+import Input from '@/components/ui/Input';
+import Button from '@/components/ui/Button';
+import LoadingSpinner from '@/components/ui/LoadingSpinner';
+import SectionTitle from '@/components/ui/SectionTitle';
+import toast from 'react-hot-toast';
+
+export default function Login() {
+ // ์ ์ญ ๋ก์ปฌ ์ ์ ๋ฅผ ์ธํ
ํด์ฃผ๋ ํจ์
+ const { setUser } = userStore();
+
+ //๋ก๊ทธ์ธ ํ ์ง์ ์ ํ์ด์ง๋ก ์ด๋ํ๊ธฐ ์ํด
+ const navigate = useNavigate();
+
+ const [isSending, setIsSending] = useState(false);
+ const [loginData, setLoginData] = useState({ email: '', password: '' });
+
+ const handleChange = (event: React.ChangeEvent) => {
+ const { name, value } = event.target;
+ setLoginData({
+ ...loginData,
+ [name]: value,
+ });
+ };
+
+ const handleLogin = async (event: React.FormEvent) => {
+ // form์ด๋ฒคํธ์ ๊ธฐ๋ณธ ์๋ก๊ณ ์นจ์ ๋ง์
+ event.preventDefault();
+
+ // ์ด๋ฉ์ผ๊ณผ ๋น๋ฐ๋ฒํธ๋ฅผ ์
๋ ฅํ์ง ์์๊ฒฝ์ฐ
+ if (loginData.email.trim() === '' || loginData.password.trim() === '') {
+ toast.error('์ด๋ฉ์ผ ๋๋ ๋น๋ฐ๋ฒํธ๋ฅผ ์
๋ ฅํด์ฃผ์ธ์.', { id: 'login' });
+ return;
+ }
+
+ // ์ด๋ฉ์ผ์ ์ ํจ์ฑ ๊ฒ์ฌ
+ if (!EMAIL_REGEX.test(loginData.email)) {
+ toast.error('์ฌ๋ฐ๋ฅธ ์ด๋ฉ์ผ์ ์
๋ ฅํด์ฃผ์ธ์.', { id: 'login' });
+ return;
+ }
+
+ // ํต์ ์์
+ setIsSending(true);
+ toast.loading('๋ก๊ทธ์ธ ์ค', { id: 'login' });
+ const res = await signIn(loginData);
+
+ // ๋ก๊ทธ์ธ ์ฑ๊ณต
+ if (res.statusCode === 200) {
+ const user = res.data as UserResponseValue;
+ // ์ด๋๋ฏผ ์ฌ๋ถ ํ์ธ(๋ณด์์ ๋งค์ฐ ์์ข์)
+ const isAdmin = ADMINS.includes(user.user.email);
+ // // ๋ก์ปฌ ์ ์ฅ์์ user์ ๋ณด์ isAdmin์ ๋ฌธ์์ดํ์์ผ์ ์ ์ฅ
+ localStorage.setItem('user', JSON.stringify({ ...user, isAdmin }));
+ // ๋ก์ปฌ user์ ์ํ๋ ์ ์ฅ
+ setUser({ ...user, isAdmin });
+ setIsSending(false);
+ navigate(-1);
+ toast.success(isAdmin ? '์ฃผ์ธ๋ ์ค์
จ์ต๋๋ค!๐ธ๐ธ' : res.message, {
+ id: 'login',
+ });
+ return;
+ }
+
+ // ๋ก๊ทธ์ธ ์คํจ
+ const errorMessage = res.message;
+ toast.error(errorMessage, { id: 'login' }); //ํ ์คํธ ๋ฉ์ธ์ง
+ setIsSending(false);
+ };
+
+ return (
+
+ );
+}
diff --git a/src/routes/LogoutNeededRoute.tsx b/src/routes/LogoutNeededRoute.tsx
new file mode 100644
index 00000000..6b2b685b
--- /dev/null
+++ b/src/routes/LogoutNeededRoute.tsx
@@ -0,0 +1,15 @@
+import { Navigate } from 'react-router-dom';
+import { userStore } from '@/store';
+
+type LogoutNeededRouteProps = {
+ element: React.ReactNode;
+};
+
+export default function LogoutNeededRoute({ element }: LogoutNeededRouteProps) {
+ const { userInfo } = userStore();
+
+ if (userInfo) {
+ return ;
+ }
+ return <>{element}>;
+}
diff --git a/src/routes/NotFound.tsx b/src/routes/NotFound.tsx
new file mode 100644
index 00000000..4df7f61e
--- /dev/null
+++ b/src/routes/NotFound.tsx
@@ -0,0 +1,20 @@
+import Button from '@/components/ui/Button';
+import { useNavigate } from 'react-router-dom';
+
+export default function NotFound() {
+ const navigate = useNavigate();
+ return (
+
+
+
404
+
+ ํ๋น ํ์ด์ง๋ ์กด์ฌํ์ง ์์ต๋๋ค.
+
+
+ Sorry, the page you are looking for does not exist.
+
+
+
+ );
+}
diff --git a/src/routes/ProductDetail.tsx b/src/routes/ProductDetail.tsx
new file mode 100644
index 00000000..df042b85
--- /dev/null
+++ b/src/routes/ProductDetail.tsx
@@ -0,0 +1,242 @@
+/* eslint-disable react-hooks/exhaustive-deps */
+import { getProductDetail } from '@/api/adminApi';
+import SectionTitle from '@/components/ui/SectionTitle';
+import { useEffect, useMemo, useState } from 'react';
+import { getAccountListAndBalance } from '@/api/bankApi';
+import { userStore } from '@/store';
+import { buyProduct } from '@/api/transactionApi';
+import { useNavigate, useParams } from 'react-router-dom';
+import Button from '@/components/ui/Button';
+import toast from 'react-hot-toast';
+import CrazyLoading from '@/components/ui/CrazyLoading';
+import Breadcrumbs from '@/components/ui/Breadcrumbs';
+import Select from '@/components/ui/Select';
+import LoadingSpinner from '@/components/ui/LoadingSpinner';
+import { AiOutlineEdit } from 'react-icons/ai';
+import ProductSection from '@/components/product/ProductSection';
+import { priceBeforeDiscount } from '@/lib/ceilPrice';
+
+export default function ProductDetail() {
+ const navigate = useNavigate();
+ const { productId } = useParams();
+ const [isLoading, setIsLoading] = useState(false);
+ const [product, setProduct] = useState();
+ const [accounts, setAccounts] = useState([]);
+ const { userInfo } = userStore();
+ const [selectedAccount, setSelectedAccount] = useState('');
+ const [isPurchasing, setIsPurchasing] = useState(false);
+
+ useEffect(() => {
+ async function fetchData() {
+ setIsLoading(true);
+ const res = await getProductDetail(productId as string);
+ if (res.statusCode === 200) {
+ setProduct(res.data as ProductDetail);
+ setIsLoading(false);
+ return;
+ }
+ toast.error(res.message, { id: 'getProduct' });
+ navigate('/');
+ setIsLoading(false);
+ }
+ fetchData();
+ }, [productId]);
+
+ useEffect(() => {
+ async function fetchData() {
+ const res = await getAccountListAndBalance(
+ userInfo?.accessToken as string
+ );
+ if (res.statusCode === 200) {
+ setAccounts((res.data as AccountsAndBalance).accounts);
+ return;
+ }
+ }
+ fetchData();
+ }, [userInfo?.accessToken, isPurchasing]);
+
+ const accountOptions = useMemo(
+ () =>
+ accounts.length > 0
+ ? [
+ { name: '๊ฒฐ์ ํ ๊ณ์ข ์ ํ', value: '' },
+ ...accounts.map((account) => ({
+ name: `${account.bankName} / ${
+ account.accountNumber
+ } / ์์ก : ${account.balance.toLocaleString('ko-KR')}์`,
+ value: account.id,
+ })),
+ ]
+ : [{ name: '๊ณ์ข๋ฅผ ๋จผ์ ๋ฑ๋กํด์ฃผ์ธ์', value: '' }],
+ [accounts]
+ );
+
+ const handlePurchase = async () => {
+ if (!selectedAccount) {
+ toast.error('๊ณ์ข๋ฅผ ์ ํํด์ฃผ์ธ์.', { id: 'buyProduct' });
+ return;
+ }
+ setIsPurchasing(true);
+ toast.loading('๊ฒฐ์ ์์ฒญ ์ค...', { id: 'buyProduct' });
+ const res = await buyProduct(
+ productId as string,
+ selectedAccount,
+ userInfo?.accessToken as string
+ );
+ if (res.statusCode === 200) {
+ setIsPurchasing(false);
+ toast.success(`${product?.title}๋ฅผ ๊ตฌ๋งคํ์์ต๋๋ค!`, {
+ id: 'buyProduct',
+ });
+ return;
+ }
+ setIsPurchasing(false);
+ toast.error(res.message, { id: 'buyProduct' });
+ };
+
+ const toEditPage = (productId: string, productTitle: string) => {
+ navigate('/admin/editproduct', { state: { productId, productTitle } });
+ };
+
+ const handleAlarm = () => {
+ setIsPurchasing(true);
+ setTimeout(() => {
+ toast.success(`${product?.title} ์
๊ณ ์ ์๋ฆผ๋ฌธ์ ๋ฐ์ก!`);
+ setIsPurchasing(false);
+ }, 500);
+ };
+
+ return (
+
+ {isLoading ? (
+
+ ) : (
+
+
+
+
+
+
+
+
+
+ {product?.title}
+ {userInfo?.isAdmin ? (
+
+ toEditPage(
+ product?.id as string,
+ product?.title as string
+ )
+ }
+ />
+ ) : (
+ <>>
+ )}
+
+
+
+ {product?.price.toLocaleString('ko-KR')}์
+
+ {product?.discountRate === 0 ? (
+ <>>
+ ) : (
+ <>
+
+ {priceBeforeDiscount(
+ product?.price as number,
+ product?.discountRate as number
+ )}
+ ์
+
+
+ {product?.discountRate}%
+
+ >
+ )}
+
+
{product?.description}
+ {userInfo ? (
+
+
+ ) : (
+
+
+
+
+
+
+
+
+ )}
+
+ );
+}
diff --git a/src/routes/Products.tsx b/src/routes/Products.tsx
new file mode 100644
index 00000000..31905d14
--- /dev/null
+++ b/src/routes/Products.tsx
@@ -0,0 +1,12 @@
+import { Navigate, useParams } from 'react-router-dom';
+import ProductSection from '@/components/product/ProductSection';
+
+export default function Products() {
+ const { category } = useParams();
+
+ if (category && ['soccer', 'footsal', 'sneakers'].includes(category)) {
+ return ;
+ }
+ // ์์๋ก ์นดํ
๊ณ ๋ฆฌ๋ฅผ ์
๋ ฅํ์ฌ ์ด๋ํ๋ ค๊ณ ํ๋ ๊ฒฝ์ฐ
+ return ;
+}
diff --git a/src/routes/ProtectedRoute.tsx b/src/routes/ProtectedRoute.tsx
new file mode 100644
index 00000000..2ecb89cb
--- /dev/null
+++ b/src/routes/ProtectedRoute.tsx
@@ -0,0 +1,22 @@
+import { Navigate } from 'react-router-dom';
+import { userStore } from '@/store';
+
+interface ProtectedRouteProps {
+ element: React.ReactNode;
+ adminRequired?: boolean;
+}
+
+export default function ProtectedRoute({
+ element,
+ adminRequired,
+}: ProtectedRouteProps) {
+ const { userInfo } = userStore();
+
+ if (!userInfo) {
+ return ;
+ }
+ if (adminRequired && !userInfo.isAdmin) {
+ return ;
+ }
+ return <>{element}>;
+}
diff --git a/src/routes/SearchProducts.tsx b/src/routes/SearchProducts.tsx
new file mode 100644
index 00000000..83a07a2f
--- /dev/null
+++ b/src/routes/SearchProducts.tsx
@@ -0,0 +1,87 @@
+import { useEffect, useMemo, useState } from 'react';
+import { Link, useLocation } from 'react-router-dom';
+import ProductBar from '@/components/product/ProductBar';
+import ProductCard from '@/components/product/ProductCard';
+import { searchProducts } from '@/api/transactionApi';
+import CrazyLoading from '@/components/ui/CrazyLoading';
+
+export default function SearchProducts() {
+ const { state: searchText } = useLocation();
+ const [message, setMessage] = useState('');
+ const [products, setProducts] = useState([]);
+ const [isLoading, setIsLoading] = useState(false);
+ const [sortByPrice, setSortByPrice] = useState('');
+
+ // ๊ฐ๊ฒฉ ์ ๋ ฌ ์ ํ
+ const handleSortByPrice = (sort: string) => {
+ setSortByPrice(sort);
+ };
+
+ useEffect(() => {
+ async function fetchData() {
+ setProducts([]);
+ setMessage('');
+ setIsLoading(true);
+ const res = await searchProducts({ searchText: searchText });
+ if (res.statusCode === 200) {
+ const products = res.data as Product[];
+ if (products.length === 0) {
+ setMessage(`'${searchText}' ๊ฒ์๊ฒฐ๊ณผ๊ฐ ์์ต๋๋ค.`);
+ setIsLoading(false);
+ return;
+ }
+ setProducts(products);
+ setIsLoading(false);
+ return;
+ }
+ setMessage(res.message);
+ setIsLoading(false);
+ }
+ fetchData();
+ }, [searchText]);
+
+ // ๊ฐ๊ฒฉ์ sorting
+ const sortedSearchedProducts = useMemo(
+ () =>
+ products?.sort((a, b) =>
+ sortByPrice === 'lowPrice' ? a.price - b.price : b.price - a.price
+ ),
+ [products, sortByPrice]
+ );
+
+ return (
+ <>
+ {isLoading ? (
+
+ ) : (
+
+
+
+ {sortedSearchedProducts?.map((product) => (
+ -
+
+
+
+
+ ))}
+
+ {message}
+
+ )}
+ >
+ );
+}
diff --git a/src/routes/SignUp.tsx b/src/routes/SignUp.tsx
new file mode 100644
index 00000000..7b7b499f
--- /dev/null
+++ b/src/routes/SignUp.tsx
@@ -0,0 +1,171 @@
+import { useState } from 'react';
+import { useNavigate } from 'react-router-dom';
+import { userStore } from '@/store';
+import { signUp } from '@/api/authApi';
+import { EMAIL_REGEX } from '@/constants/constants';
+import Button from '@/components/ui/Button';
+import Input from '@/components/ui/Input';
+import LoadingSpinner from '@/components/ui/LoadingSpinner';
+import ImageUpload from '@/components/ui/ImageUpload';
+import SectionTitle from '@/components/ui/SectionTitle';
+import toast from 'react-hot-toast';
+
+export default function SignUp() {
+ const navigate = useNavigate();
+ const { setUser } = userStore();
+
+ const [signUpData, setSignData] = useState({
+ email: '',
+ password: '',
+ passwordRepeat: '',
+ displayName: '',
+ profileImgBase64: '',
+ });
+
+ const [isSending, setIsSending] = useState(false);
+
+ const handleChange = (event: React.ChangeEvent) => {
+ const { name, value } = event.target;
+ // ์ด๋ฏธ์ง ํ์ผ ๋ค๋ฃจ๋ ๋ก์ง
+ if (name === 'profileImgBase64') {
+ const files = event.target.files as FileList;
+ const reader = new FileReader();
+ reader.readAsDataURL(files[0]);
+ reader.onloadend = () => {
+ setSignData({ ...signUpData, [name]: reader.result as string });
+ };
+ }
+ setSignData((prevData) => ({
+ ...prevData,
+ [name]: value,
+ }));
+ };
+
+ const handleSubmit = async (event: React.FormEvent) => {
+ event.preventDefault();
+
+ // ์ด๋ฉ์ผ or ๋น๋ฐ๋ฒํธ or ์ด๋ฆ์ ์
๋ ฅํ์ง ์์๊ฒฝ์ฐ
+ if (
+ signUpData.email.trim() === '' ||
+ signUpData.password.trim() === '' ||
+ signUpData.displayName.trim() === ''
+ ) {
+ toast.error('์ด๋ฉ์ผ, ๋น๋ฐ๋ฒํธ, ๋๋ค์์ ๋ชจ๋ ์
๋ ฅํด์ฃผ์ธ์.', {
+ id: 'signUp',
+ });
+ return;
+ }
+
+ // ์ด๋ฉ์ผ์ ์ ํจ์ฑ ๊ฒ์ฌ
+ if (!EMAIL_REGEX.test(signUpData.email)) {
+ toast.error('์ฌ๋ฐ๋ฅธ ์ด๋ฉ์ผ์ ์
๋ ฅํด์ฃผ์ธ์.', {
+ id: 'signUp',
+ });
+ return;
+ }
+
+ // ๋น๋ฒ 8์๋ฆฌ ์ ํจ์ฑ๊ฒ์ฌ
+ if (signUpData.password.length < 7) {
+ toast.error('๋น๋ฐ๋ฒํธ๋ฅผ 8์๋ฆฌ ์ด์ ์
๋ ฅํด์ฃผ์ธ์.', {
+ id: 'signUp',
+ });
+ return;
+ }
+
+ // ์ด๋ฆ ๊ธธ์ด ์ ํจ์ฑ๊ฒ์ฌ
+ if (signUpData.displayName.length > 20) {
+ toast.error('๋๋ค์์ 20์ ์ดํ๋ก ์์ฑํด์ฃผ์ธ์.', {
+ id: 'signUp',
+ });
+ return;
+ }
+
+ // ๋น๋ฐ๋ฒํธ ํ์ธ
+ if (signUpData.password !== signUpData.passwordRepeat) {
+ toast.error('๋น๋ฐ๋ฒํธ๊ฐ ์ผ์นํ์ง ์์ต๋๋ค.', {
+ id: 'signUp',
+ });
+ return;
+ }
+
+ // ํต์ ์์
+ setIsSending(true);
+ toast.loading('ํ์๊ฐ์
์์ฒญ ์ค...', { id: 'signUp' });
+ const res = await signUp(signUpData);
+ // ํ์๊ฐ์
์ ์ฑ๊ณตํ๋ ๊ฒฝ์ฐ
+ if (res.statusCode === 200) {
+ const user = res.data as UserResponseValue;
+ setIsSending(false);
+ toast.success(`${user.user.displayName}๋ ์ฆ๊ฑฐ์ด ์ผํ ๋์ธ์!`, {
+ id: 'signUp',
+ });
+ // ์๋ก ๊ฐ์
ํ๋ ์ฌ๋์ด ๊ด๋ฆฌ์์ผ๋ฆฌ ์์
+ localStorage.setItem('user', JSON.stringify({ ...user, isAdmin: false }));
+ setUser({ ...user, isAdmin: false });
+ navigate('/', { replace: true });
+ return;
+ }
+ // ํ์๊ฐ์
์คํจ
+ toast.error(res.message, {
+ id: 'signUp',
+ });
+ setIsSending(false);
+ };
+
+ return (
+
+ );
+}
diff --git a/src/routes/admin/AddProduct.tsx b/src/routes/admin/AddProduct.tsx
new file mode 100644
index 00000000..6ce4856f
--- /dev/null
+++ b/src/routes/admin/AddProduct.tsx
@@ -0,0 +1,190 @@
+import { useState } from 'react';
+import { addProduct } from '@/api/adminApi';
+import Input from '@/components/ui/Input';
+import Button from '@/components/ui/Button';
+import LoadingSpinner from '@/components/ui/LoadingSpinner';
+import ImageUpload from '@/components/ui/ImageUpload';
+import Select from '@/components/ui/Select';
+import { SELECT_BRAND, SELECT_CATEGORY } from '@/constants/constants';
+import SectionTitle from '@/components/ui/SectionTitle';
+import toast from 'react-hot-toast';
+import { useNavigate } from 'react-router-dom';
+
+export default function AddProduct() {
+ const navigate = useNavigate();
+
+ // ์ํ์ input๊ฐ state, price์ discountRate์ ์๋ ํ์
์ number์ด๋ ์ผ๋จ string์ผ๋ก ๋ฐ๊ณ ํต์ ์ ๋ณด๋ผ ๋ number๋ก ๋ฐ๊ฟ์ค ์์
+ const [productInputData, setProductInputData] = useState({
+ title: '',
+ price: '',
+ description: '',
+ tags: ['', ''],
+ thumbnailBase64: '',
+ photoBase64: '',
+ discountRate: '',
+ isSoldOut: false,
+ });
+
+ const [isSending, setIsSending] = useState(false);
+
+ const handleChange = (
+ // event ์ค input ์์๋ฟ๋ง ์๋๋ผ select ์์๋ ์์ผ๋ฏ๋ก ๋ค์๊ณผ ๊ฐ์ด generic์ผ๋ก ์ง์
+ event: React.ChangeEvent
+ ) => {
+ const { name, value, type } = event.target;
+
+ // ์ด๋ฏธ์ง ํ์ผ
+ if (type === 'file') {
+ const files = (event.target as HTMLInputElement).files as FileList;
+ const reader = new FileReader();
+ reader.readAsDataURL(files[0]);
+ reader.onloadend = () => {
+ setProductInputData((prevData) => ({
+ ...prevData,
+ [name]: reader.result as string,
+ }));
+ };
+ // select๋ก tags์ element๋ฅผ ์ง์ ํ๋ ๋ก์ง
+ // tags = ["์นดํ
๊ณ ๋ฆฌ(์ถ๊ตฌํ, ์กฑ๊ตฌํ...)", "๋ธ๋๋(๋์ดํค, ์๋๋ค์ค...)"]
+ } else if (name === 'category') {
+ setProductInputData((prevData) => ({
+ ...prevData,
+ tags: [value, prevData.tags?.[1] || ''],
+ }));
+ } else if (name === 'brand') {
+ setProductInputData((prevData) => ({
+ ...prevData,
+ tags: [prevData.tags?.[0] || '', value],
+ }));
+ } else {
+ setProductInputData((prevData) => ({
+ ...prevData,
+ [name]: value,
+ }));
+ }
+ };
+
+ const handleSubmit = async (event: React.FormEvent) => {
+ event.preventDefault();
+
+ // ์ํ์ด๋ฆ or ์ํ๊ฐ๊ฒฉ or ์ํ์ค๋ช
์ ์
๋ ฅํ์ง ์์ ๊ฒฝ์ฐ
+ if (
+ productInputData.title.trim() === '' ||
+ productInputData.price.trim() === '' ||
+ productInputData.description.trim() === '' ||
+ productInputData.tags[0] === '' ||
+ productInputData.tags[0] === 'category' ||
+ productInputData.tags[1] === '' ||
+ productInputData.tags[1] === 'brand'
+ ) {
+ toast.error(
+ '์นดํ
๊ณ ๋ฆฌ, ๋ธ๋๋, ์ํ์ด๋ฆ, ๊ฐ๊ฒฉ, ์ํ์ค๋ช
์ ๋ชจ๋ ์
๋ ฅํด์ฃผ์ธ์.',
+ { id: 'addProduct' }
+ );
+ return;
+ }
+
+ // ํ ์ธ์จ 0 ~ 99 ๊ฐ ์๋๊ฒฝ์ฐ
+ if (productInputData.discountRate) {
+ if (
+ !Number(productInputData.discountRate) ||
+ Number(productInputData.discountRate) <= 0 ||
+ Number(productInputData.discountRate) >= 100
+ ) {
+ toast.error('ํ ์ธ์จ์ 0 ~ 99๋ฅผ ์
๋ ฅํด์ฃผ์ธ์.', { id: 'addProduct' });
+ return;
+ }
+ }
+
+ setIsSending(true);
+ toast.loading('์ํ ๋ฑ๋ก ์ค ์
๋๋ค.', { id: 'addProduct' });
+ const res = await addProduct({
+ ...productInputData,
+ discountRate: Number(productInputData.discountRate),
+ price: Number(productInputData.price),
+ });
+
+ // ์ํ๋ฑ๋ก์ด ์ฑ๊ณตํ ๊ฒฝ์ฐ
+ if (res.statusCode === 200) {
+ toast.success(res.message, { id: 'addProduct' });
+ setIsSending(false);
+ navigate(`/products/${res.data?.tags[0]}/${res.data?.id}`);
+ return;
+ }
+ // ์ํ๋ฑ๋ก์ด ์คํจํ ๊ฒฝ์ฐ
+ toast.error(res.message, { id: 'addProduct' });
+ setIsSending(false);
+ };
+
+ return (
+
+ );
+}
diff --git a/src/routes/admin/Admin.tsx b/src/routes/admin/Admin.tsx
new file mode 100644
index 00000000..eb570539
--- /dev/null
+++ b/src/routes/admin/Admin.tsx
@@ -0,0 +1,26 @@
+/* eslint-disable react-hooks/exhaustive-deps */
+import SubNavbar from '@/components/SubNavbar';
+import { SUB_MENUS_ADMIN } from '@/constants/constants';
+import { userStore } from '@/store';
+import { useEffect } from 'react';
+import { toast } from 'react-hot-toast';
+import { Outlet } from 'react-router-dom';
+
+export default function Admin() {
+ const { authMe } = userStore();
+ useEffect(() => {
+ async function auth() {
+ const errorMessage = await authMe();
+ if (errorMessage) {
+ toast.error(errorMessage, { id: 'authMe' });
+ }
+ }
+ auth();
+ }, []);
+ return (
+ <>
+
+
+ >
+ );
+}
diff --git a/src/routes/admin/AdminClients.tsx b/src/routes/admin/AdminClients.tsx
new file mode 100644
index 00000000..ea40f19f
--- /dev/null
+++ b/src/routes/admin/AdminClients.tsx
@@ -0,0 +1,98 @@
+import { useEffect, useMemo, useState } from 'react';
+import { getAllTransactions, getClients } from '@/api/adminApi';
+import SingleUser from '@/components/SingleUser';
+import { ADMINS } from '@/constants/constants';
+import toast from 'react-hot-toast';
+import SectionTitle from '@/components/ui/SectionTitle';
+import CrazyLoading from '@/components/ui/CrazyLoading';
+
+export default function AdminClients() {
+ const [clients, setClients] = useState([]);
+ const [isLoading, setIsLoading] = useState(false);
+
+ useEffect(() => {
+ setIsLoading(true);
+ async function fetchData() {
+ const promiseClients = getClients();
+ const promiseTansactions = getAllTransactions();
+ // ํต์ ์ ๋๊ฐ ๋๋ฆฌ๊ธฐ ๋๋ฌธ์ ๋ก๋ฉ์๊ฐ์ด ๊ธป๋๋ค.
+ const [res1, res2] = await Promise.all([
+ promiseClients,
+ promiseTansactions,
+ ]);
+ if (res1.statusCode === 200 && res2.statusCode === 200) {
+ const spentMoneyIncludedClients = (res1.data as Client[]).map(
+ (client) => {
+ // ๊ฐ ๊ณ ๊ฐ๋ง๋ค ์๋น๊ธ์ก์ ๊ตฌํ๋ ๋ก์ง
+ const spentMoney = (res2.data as TransactionDetail[])
+ // ๊ณ ๊ฐ์ด๋ฉ์ผ๊ณผ ๊ฑฐ๋์ ๋ณด ์ด๋ฉ์ผ์ด ์ผ์นํ๋ฉด์ ์๋ฃ๋ ๊ฑฐ๋ ํํฐ๋ง
+ .filter(
+ (transaction) =>
+ transaction.user.email === client.email && transaction.done
+ )
+ // ๊ฑฐ๋ ๊ธ์ก์ ๋ค ๋ํจ
+ .reduce((acc, curr) => acc + curr.product.price, 0);
+
+ return {
+ ...client,
+ spentMoney,
+ };
+ }
+ );
+ setClients(spentMoneyIncludedClients);
+ setIsLoading(false);
+ return;
+ }
+ toast.error(res1.message, { id: 'getClients' });
+ setIsLoading(false);
+ }
+ fetchData();
+ }, []);
+
+ const adminCount = useMemo(
+ () => clients.filter((user) => ADMINS.includes(user.email)).length,
+ [clients]
+ );
+
+ return (
+ <>
+ {isLoading ? (
+
+ ) : (
+
+
+
+
+
+
+
+
+
+ ํ๋กํ์ฌ์ง |
+ ์ด๋ฉ์ผ |
+ ๋๋ค์ |
+
+ ๋ฑ๊ธ(๐ฐVIP : 30๋ง์,
+ ๐ฐVVIP๐ฐ : 50๋ง์)
+ |
+
+
+
+ {clients.map((user) => {
+ return (
+
+ );
+ })}
+
+
+
+ )}
+ >
+ );
+}
diff --git a/src/routes/admin/AdminProducts.tsx b/src/routes/admin/AdminProducts.tsx
new file mode 100644
index 00000000..d1ca049e
--- /dev/null
+++ b/src/routes/admin/AdminProducts.tsx
@@ -0,0 +1,138 @@
+import { useEffect, useState } from 'react';
+import { deleteProduct, getProducts } from '@/api/adminApi.ts';
+import { useNavigate } from 'react-router-dom';
+import Button from '@/components/ui/Button.tsx';
+import SectionTitle from '@/components/ui/SectionTitle';
+import { DICTIONARY_SHOES } from '@/constants/constants';
+import toast from 'react-hot-toast';
+import CrazyLoading from '@/components/ui/CrazyLoading';
+
+export default function AdminProduct() {
+ const [products, setProducts] = useState();
+ const [isLoading, setIsLoading] = useState(false);
+ const navigate = useNavigate();
+
+ useEffect(() => {
+ setIsLoading(true);
+ const fetchData = async () => {
+ const res = await getProducts();
+ if (res.statusCode === 200) {
+ setProducts(res.data as Product[]);
+ setIsLoading(false);
+ return;
+ }
+ toast.error(res.message, { id: 'getProducts' });
+ setIsLoading(false);
+ };
+ fetchData();
+ }, []);
+
+ const toDetailPage = (category: string, productId: string) => {
+ navigate(`/products/${category}/${productId}`);
+ };
+
+ const toEditPage = (
+ event: React.MouseEvent,
+ productId: string,
+ productTitle: string
+ ) => {
+ // ๋ฒํผ์ ๋๋ ์ ๋ ์์ธ ํ์ด์ง๋ก ๊ฐ์ง ์๊ธฐ ์ํด
+ event.stopPropagation();
+ // ์์ธ ํ์ด์ง๋ก state๋ฅผ ์ ๋ฌํ๋ ๋ฐฉ๋ฒ์ ๋๊ฐ์ง๊ฐ ์์ต๋๋ค.
+ // 1. "/admin/editproduct/:productId"์ ๊ฐ์ด url๋ก ๋ณด๋ด๋ ๋ฐฉ๋ฒ
+ // 2. history api์ state๋ฅผ ์ด์ฉํ๋ ๋ฐฉ๋ฒ, ์ด ๋ฐฉ๋ฒ์ ์ฌ์ฉํ๊ฒ ์ต๋๋ค.
+ navigate('/admin/editproduct', { state: { productId, productTitle } });
+ };
+
+ const handleDelete = async (
+ event: React.MouseEvent,
+ productId: string,
+ productTitle: string
+ ) => {
+ event.stopPropagation();
+ if (confirm(`${productTitle}๋ฅผ ์ญ์ ํ์๊ฒ ์ต๋๊น?`)) {
+ toast.loading(`${productTitle} ์ญ์ ์ค...`, {
+ id: 'deleteProduct',
+ });
+ const res = await deleteProduct(productId);
+ if (res.statusCode === 200) {
+ toast.success(`${productTitle}๋ฅผ ์ญ์ ํ์์ต๋๋ค.`, {
+ id: 'deleteProduct',
+ });
+ setProducts(products?.filter((product) => product.id !== productId));
+ return;
+ }
+ toast.error(res.message, { id: 'deleteProduct' });
+ }
+ };
+
+ return (
+ <>
+ {isLoading ? (
+
+ ) : (
+
+
+
+
+
+ ์ฌ์ง |
+ ์ํ๋ช
|
+ ์ํ๊ฐ๊ฒฉ(์) |
+ ์นดํ
๊ณ ๋ฆฌ |
+ ๋ธ๋๋ |
+ ์ฌ๊ณ |
+ ํ ์ธ์จ |
+ |
+
+
+
+ {products?.map((product) => {
+ return (
+ toDetailPage(product.tags[0], product.id)}
+ className="cursor-pointer hover:opacity-70"
+ >
+
+
+ |
+
+
+ {product.title}
+
+ |
+ {product.price.toLocaleString('ko-KR')} |
+ {DICTIONARY_SHOES[product.tags[0]]} |
+ {product.tags[1].toUpperCase()} |
+ {product.isSoldOut ? 'โ' : '๐'} |
+ {product.discountRate}% |
+
+ |
+
+ );
+ })}
+
+
+
+ )}
+ >
+ );
+}
diff --git a/src/routes/admin/AllTransactions.tsx b/src/routes/admin/AllTransactions.tsx
new file mode 100644
index 00000000..f79aa453
--- /dev/null
+++ b/src/routes/admin/AllTransactions.tsx
@@ -0,0 +1,89 @@
+import { useEffect, useMemo, useState } from 'react';
+import { getAllTransactions } from '@/api/adminApi';
+import toast from 'react-hot-toast';
+import CrazyLoading from '@/components/ui/CrazyLoading';
+import { convertToHumanReadable } from '@/lib/time';
+import SectionTitle from '@/components/ui/SectionTitle';
+
+export default function TransactionsPage() {
+ const [transactions, setTransactions] = useState([]);
+ const [searchTerm, setSearchTerm] = useState('');
+ const [isLoading, setIsLoading] = useState(false);
+
+ useEffect(() => {
+ const fetchData = async () => {
+ setIsLoading(true);
+ const res = await getAllTransactions();
+ if (res.statusCode === 200) {
+ setTransactions(res.data as TransactionDetail[]);
+ setIsLoading(false);
+ return;
+ }
+ toast.error(res.message, { id: 'getTransactions' });
+ setIsLoading(false);
+ };
+ fetchData();
+ }, []);
+
+ const filteredTransactions = useMemo(
+ () =>
+ transactions.filter(
+ (transaction) =>
+ transaction.user.displayName.includes(searchTerm) ||
+ transaction.product.title.includes(searchTerm)
+ ),
+ [searchTerm, transactions]
+ );
+
+ return (
+ <>
+ {isLoading ? (
+
+ ) : (
+
+ )}
+ >
+ );
+}
diff --git a/src/routes/admin/EditProduct.tsx b/src/routes/admin/EditProduct.tsx
new file mode 100644
index 00000000..242c25a5
--- /dev/null
+++ b/src/routes/admin/EditProduct.tsx
@@ -0,0 +1,254 @@
+import { useEffect, useState } from 'react';
+import { getProductDetail, updateProduct } from '@/api/adminApi';
+import Input from '@/components/ui/Input';
+import Button from '@/components/ui/Button';
+import LoadingSpinner from '@/components/ui/LoadingSpinner';
+import Select from '@/components/ui/Select';
+import { SELECT_BRAND, SELECT_CATEGORY } from '@/constants/constants';
+import { useLocation, useNavigate } from 'react-router-dom';
+import { toast } from 'react-hot-toast';
+import CrazyLoading from '@/components/ui/CrazyLoading';
+import SectionTitle from '@/components/ui/SectionTitle';
+import ImageUpload from '@/components/ui/ImageUpload';
+
+export default function EditProduct() {
+ const navigate = useNavigate();
+ // navigate๋ก๋ถํฐ ๋ฐ์ state์ ๋ณด๋ค
+ const {
+ state: { productId, productTitle },
+ } = useLocation();
+
+ // ์๋ ์ผ๋จ์ ๋ชจ๋ string์ผ๋ก ์ด๊ธฐ๊ฐ ์ธํ
+ const [detailProduct, setDetailProduct] = useState({
+ title: '',
+ price: '',
+ description: '',
+ tags: ['', ''],
+ thumbnailBase64: '',
+ photoBase64: '',
+ discountRate: '',
+ isSoldOut: '',
+ });
+ const [isLoading, setIsLoading] = useState(false);
+ const [isSending, setIsSending] = useState(false);
+ const [isImageUpdate, setIsImageUpdate] = useState(false);
+
+ useEffect(() => {
+ setIsLoading(true);
+ const fetchProducts = async () => {
+ const res = await getProductDetail(productId);
+ if (res.statusCode === 200) {
+ const data = res.data as ProductDetail;
+ setDetailProduct({
+ // string์ด ์๋ ํญ๋ชฉ์ string์ผ๋ก ๋ณํํ ์ธํ
ํด์ค
+ title: data.title,
+ price: data.price.toString(),
+ description: data.description,
+ tags: data.tags,
+ thumbnailBase64: data.thumbnail,
+ photoBase64: data.photo,
+ discountRate: data.discountRate.toString(),
+ isSoldOut: data.isSoldOut.toString(),
+ });
+ setIsLoading(false);
+ return;
+ }
+ toast.error(res.message, { id: 'getProductDetail' });
+ setIsLoading(false);
+ };
+ fetchProducts();
+ }, [productId]);
+
+ const handleChange = (
+ event: React.ChangeEvent
+ ) => {
+ const { name, value, type } = event.target;
+ setIsImageUpdate(false);
+ if (type === 'file') {
+ // ์ด๋ฏธ์ง๋ฅผ ์
๋ก๋ ์ฌ๋ถ๋ฅผ state๋ก ๊ด๋ฆฌ
+ setIsImageUpdate(true);
+ const files = (event.target as HTMLInputElement).files as FileList;
+ const reader = new FileReader();
+ reader.readAsDataURL(files[0]);
+ reader.onloadend = () => {
+ setDetailProduct((prevData) => {
+ return {
+ ...prevData,
+ [name]: reader.result as string,
+ };
+ });
+ };
+ } else if (name === 'category') {
+ setDetailProduct((prevData) => {
+ return {
+ ...prevData,
+ tags: [value, prevData?.tags?.[1] || ''],
+ };
+ });
+ } else if (name === 'brand') {
+ setDetailProduct((prevData) => {
+ return {
+ ...prevData,
+ tags: [prevData?.tags?.[0] || '', value],
+ };
+ });
+ } else {
+ setDetailProduct((prevdata) => {
+ return {
+ ...prevdata,
+ [name]: value,
+ };
+ });
+ }
+ };
+
+ const handleSubmit = async (event: React.FormEvent) => {
+ event.preventDefault();
+
+ // ์ํ์ด๋ฆ or ์ํ๊ฐ๊ฒฉ or ์ํ์ค๋ช
์ ์
๋ ฅํ์ง ์์ ๊ฒฝ์ฐ
+ if (
+ detailProduct?.title.trim() === '' ||
+ detailProduct?.price.trim() === '' ||
+ detailProduct?.description.trim() === ''
+ ) {
+ toast.error('์ํ์ด๋ฆ, ๊ฐ๊ฒฉ, ์ํ์ค๋ช
์ ๋ชจ๋ ์
๋ ฅํด์ฃผ์ธ์.', {
+ id: 'updateProduct',
+ });
+ return;
+ }
+
+ // ํ ์ธ์จ 0 ~ 99 ๊ฐ ์๋๊ฒฝ์ฐ
+ if (
+ Number(detailProduct.discountRate) < 0 ||
+ Number(detailProduct.discountRate) >= 100
+ ) {
+ toast.error('ํ ์ธ์จ์ 0 ~ 99๋ฅผ ์
๋ ฅํด์ฃผ์ธ์.', { id: 'updateProduct' });
+ return;
+ }
+ setIsSending(true);
+ const res = await updateProduct(
+ productId,
+ // ์ด๋ฏธ์ง๋ฅผ ์
๋ก๋ ํ ๊ฒฝ์ฐ์๋ง 'thumbnailBase64', 'photoBase64' ํค๊ฐ์ ์ถ๊ฐํด์ ๋ณด๋
+ // ๊ทธ๋ฐ๋ฐ ๋๊ฐ์ ์ด๋ฏธ์ง ์ค์ ํ๋๋ง ์
๋ก๋๋ฅผ ํ ๊ฒฝ์ฐ ๋๋จธ์ง ํ๋์ ๊ฐ์ด base64๊ฐ ์๋๊ธฐ ๋๋ฌธ์ ์๋ฌ๊ฐ ๋ฐ์ํจ.
+ // ๋ฐ๋ผ์ ์์ ํ ๊ฑฐ๋ผ๋ฉด ๋๊ฐ ๋ค ์
๋ก๋ํด์ผํจ.
+ isImageUpdate
+ ? {
+ title: detailProduct.title,
+ price: Number(detailProduct.price),
+ description: detailProduct.description,
+ tags: detailProduct.tags,
+ discountRate: Number(detailProduct?.discountRate),
+ isSoldOut: detailProduct.isSoldOut === 'true',
+ thumbnailBase64: detailProduct?.thumbnailBase64,
+ photoBase64: detailProduct?.photoBase64,
+ }
+ : {
+ title: detailProduct.title,
+ price: Number(detailProduct.price),
+ description: detailProduct.description,
+ tags: detailProduct.tags,
+ discountRate: Number(detailProduct?.discountRate),
+ isSoldOut: detailProduct.isSoldOut === 'true',
+ }
+ );
+ if (res.statusCode === 200) {
+ toast.success(res.message, { id: 'updateProduct' });
+ setIsSending(false);
+ navigate(`/products/${detailProduct.tags[0]}/${productId}`);
+ return;
+ }
+ toast.error(res.message, { id: 'updateProduct' });
+ setIsSending(false);
+ };
+
+ return (
+ <>
+ {isLoading ? (
+
+ ) : (
+
+ )}
+ >
+ );
+}
diff --git a/src/routes/myAccount/ChangeName.tsx b/src/routes/myAccount/ChangeName.tsx
new file mode 100644
index 00000000..47ee8fcb
--- /dev/null
+++ b/src/routes/myAccount/ChangeName.tsx
@@ -0,0 +1,84 @@
+/* eslint-disable react-hooks/exhaustive-deps */
+import { useState } from 'react';
+import { userStore } from '@/store';
+import { editUser } from '@/api/authApi';
+import { useNavigate } from 'react-router-dom';
+import Input from '@/components/ui/Input';
+import Button from '@/components/ui/Button';
+import LoadingSpinner from '@/components/ui/LoadingSpinner';
+import toast from 'react-hot-toast';
+import SectionTitle from '@/components/ui/SectionTitle';
+
+export default function ChangeName() {
+ const [isSending, setIsSending] = useState(false);
+ const navigate = useNavigate();
+ const { authMe, userInfo } = userStore();
+ const [editData, setEditData] = useState({
+ displayName: '',
+ });
+
+ const handleChange = (e: React.ChangeEvent) => {
+ const { name, value } = e.target;
+ setEditData({
+ ...editData,
+ [name]: value,
+ });
+ };
+
+ const handleSubmit = async (e: React.FormEvent) => {
+ e.preventDefault();
+ if (editData.displayName.trim() === '') {
+ toast.error('๋ณ๊ฒฝ ํ ๋๋ค์๋ฅผ ์
๋ ฅํด์ฃผ์ธ์.', { id: 'changeName' });
+ return;
+ }
+ if (editData.displayName.trim() === userInfo?.user.displayName) {
+ toast.error('์๋ ๋๋ค์๊ณผ ๋์ผํฉ๋๋ค.', { id: 'changeName' });
+ return;
+ }
+ if (editData.displayName.length > 20) {
+ toast.error('๋๋ค์์ 20์ ์ดํ๋ก ์์ฑํด์ฃผ์ธ์', { id: 'changeName' });
+ return;
+ }
+
+ setIsSending(true);
+ toast.loading('๋๋ค์ ๋ณ๊ฒฝ ์ค', { id: 'changeName' });
+ const res = await editUser(userInfo?.accessToken as string, editData);
+ if (res.statusCode === 200) {
+ const updatedUser = res.data as UpdatedUserResponseValue;
+ toast.success(`${updatedUser.displayName}(์ผ)๋ก ๋ณ๊ฒฝํ์์ต๋๋ค.`, {
+ id: 'changeName',
+ });
+ navigate('/myaccount/info');
+ setIsSending(false);
+ authMe();
+ return;
+ }
+ toast.error(res.message, { id: 'changeName' });
+ setIsSending(false);
+ };
+
+ return (
+
+ );
+}
diff --git a/src/routes/myAccount/ChangePassword.tsx b/src/routes/myAccount/ChangePassword.tsx
new file mode 100644
index 00000000..c2a99724
--- /dev/null
+++ b/src/routes/myAccount/ChangePassword.tsx
@@ -0,0 +1,132 @@
+import { useState } from 'react';
+import { userStore } from '@/store';
+import { editUser } from '@/api/authApi';
+import Input from '@/components/ui/Input';
+import Button from '@/components/ui/Button';
+import LoadingSpinner from '@/components/ui/LoadingSpinner';
+import toast from 'react-hot-toast';
+import SectionTitle from '@/components/ui/SectionTitle';
+import { useNavigate } from 'react-router-dom';
+
+export default function ChangePassword() {
+ const navigate = useNavigate();
+ const [isSending, setIsSending] = useState(false);
+ const { userInfo } = userStore();
+ const [editData, setEditData] = useState({
+ oldPassword: '',
+ newPassword: '',
+ checkPassword: '',
+ });
+
+ // ์๋ฒ์ ์ ์ก์ํ์ ๋ฐ๋ผ ๋ฒํผ์ ์ํ๋ฅผ ๋ฐ๊ฟ์ฃผ๊ธฐ ์ํด์ ์คํ
์ดํธ ์ง์
+ // ์๋ฌ๋ฉ์ธ์ง ํ์์์
+ const [timeoutId, setTimeoutId] = useState(null);
+
+ const handleChange = (e: React.ChangeEvent) => {
+ const { name, value } = e.target;
+ setEditData({
+ ...editData,
+ [name]: value,
+ });
+ };
+
+ const handleSubmit = async (e: React.FormEvent) => {
+ e.preventDefault();
+
+ // ์ด์ ํ์์์์ด ์์ง ์๋์ค์ด ์ด๊ธฐํ
+ if (timeoutId) {
+ clearTimeout(timeoutId);
+ setTimeoutId(null);
+ }
+
+ // ๋ณ๊ฒฝ์ ๋น๋ฒ, ๋ณ๊ฒฝ ํ ๋น๋ฒ ์
๋ ฅ ์ํ์ ๋
+ if (
+ editData.newPassword.trim() === '' ||
+ editData.oldPassword.trim() === ''
+ ) {
+ toast.error('๋น๋ฐ๋ฒํธ๋ฅผ ์
๋ ฅํด์ฃผ์ธ์.', { id: 'changePassword' });
+ return;
+ }
+ // ๋ณ๊ฒฝ ๋น๋ฒ ํ์ธ
+ if (editData.checkPassword !== editData.newPassword) {
+ toast.error('๋ณ๊ฒฝ ํ ๋น๋ฐ๋ฒํธ๊ฐ ์ผ์นํ์ง ์์ต๋๋ค.', {
+ id: 'changePassword',
+ });
+ return;
+ }
+ // ๋ณ๊ฒฝ ๋น๋ฒ ๊ธธ์ด ์
+ if (editData.newPassword.length <= 7) {
+ toast.error('๋น๋ฐ๋ฒํธ๋ฅผ 8์๋ฆฌ ์ด์ ์
๋ ฅํด์ฃผ์ธ์.', {
+ id: 'changePassword',
+ });
+ return;
+ }
+
+ setIsSending(true);
+ toast.loading('๋น๋ฐ๋ฒํธ ์์ ์ค', {
+ id: 'changePassword',
+ });
+ const res = await editUser(userInfo?.accessToken as string, {
+ newPassword: editData.newPassword,
+ oldPassword: editData.oldPassword,
+ });
+
+ if (res.statusCode === 200) {
+ const data = res.data as UpdatedUserResponseValue;
+ toast.success(`${data.displayName}๋์ ๋น๋ฐ๋ฒํธ๊ฐ ๋ณ๊ฒฝ๋์์ต๋๋ค.`, {
+ id: 'changePassword',
+ });
+ setEditData({
+ oldPassword: '',
+ newPassword: '',
+ checkPassword: '',
+ });
+ setIsSending(false);
+ navigate('/myaccount/info');
+ return;
+ }
+ toast.error(res.message, {
+ id: 'changePassword',
+ });
+ setIsSending(false);
+ };
+
+ return (
+
+ );
+}
diff --git a/src/routes/myAccount/Info.tsx b/src/routes/myAccount/Info.tsx
new file mode 100644
index 00000000..e7b3242b
--- /dev/null
+++ b/src/routes/myAccount/Info.tsx
@@ -0,0 +1,94 @@
+import { useState } from 'react';
+import ImageUpload from '@/components/ui/ImageUpload';
+import ProfileImage from '@/components/ui/ProfileImage';
+import { userStore } from '@/store';
+import Button from '@/components/ui/Button';
+import { editUser } from '@/api/authApi';
+import LoadingSpinner from '@/components/ui/LoadingSpinner';
+import toast from 'react-hot-toast';
+import { AiOutlineEdit } from 'react-icons/ai';
+import { useNavigate } from 'react-router-dom';
+import SectionTitle from '@/components/ui/SectionTitle';
+
+export default function Info() {
+ const navigate = useNavigate();
+ const { authMe } = userStore();
+ const { userInfo } = userStore();
+ const [profileImage, setProfileImage] = useState(
+ userInfo?.user.profileImg as string
+ );
+ const [isSending, setIsSending] = useState(false);
+
+ const handleChange = (event: React.ChangeEvent) => {
+ const files = event.target.files as FileList;
+ const reader = new FileReader();
+ reader.readAsDataURL(files[0]);
+ reader.onloadend = () => {
+ setProfileImage(reader.result as string);
+ };
+ };
+
+ const handleSubmit = async (
+ event: React.MouseEvent
+ ) => {
+ event.preventDefault();
+
+ if (profileImage === '') {
+ toast.error('๋ณ๊ฒฝํ ์ด๋ฏธ์ง๋ฅผ ์ ํํด์ฃผ์ธ์.', { id: 'profileImage' });
+ return;
+ }
+
+ // ์ฌ์ง์ ์ ํํ์ง ์์์ ๊ฒฝ์ฐ ๋ฌธ์ ๋ฐ์ํจ..!!
+ setIsSending(true);
+ toast.loading('ํ๋กํ ์ฌ์ง ๋ณ๊ฒฝ ์ค', { id: 'profileImage' });
+ const res = await editUser(userInfo?.accessToken as string, {
+ profileImgBase64: profileImage as string,
+ });
+ if (res.statusCode === 200) {
+ const updatedUser = res.data as UpdatedUserResponseValue;
+ toast.success(`${updatedUser.displayName}๋! ์๋ก์ด ์ฌ์ง ๋ฉ์ ธ์!๐๐`, {
+ id: 'profileImage',
+ });
+ setIsSending(false);
+ // navbar์ ์๋ ํ๋กํ ์ฌ์ง๋ ์๋ก์ด ์ฌ์ง์ผ๋ก ๋ฐ๊ฟ์ฃผ๊ธฐ ์ํด
+ setProfileImage(updatedUser.profileImg as string);
+ await authMe();
+ return;
+ }
+ const errorMessage = res.message;
+ toast.error(errorMessage, { id: 'profileImage' });
+ setIsSending(false);
+ };
+
+ return (
+
+
+
+
+
+
+
+ {userInfo?.user.displayName}
+
+
{
+ navigate('/myaccount/changename');
+ }}
+ />
+
+
+
+
: 'ํ๋กํ์ฌ์ง ๋ณ๊ฒฝ'
+ }
+ disabled={isSending}
+ onClick={handleSubmit}
+ />
+
+
+
+ );
+}
diff --git a/src/routes/myAccount/Login.tsx b/src/routes/myAccount/Login.tsx
new file mode 100644
index 00000000..83d53131
--- /dev/null
+++ b/src/routes/myAccount/Login.tsx
@@ -0,0 +1,111 @@
+/* eslint-disable react-hooks/exhaustive-deps */
+import { useState } from 'react';
+import { useNavigate } from 'react-router-dom';
+import { userStore } from '../../store';
+import { signIn } from '../../api/authApi';
+import { ADMINS, EMAIL_REGEX } from '../../constants/constants';
+import Input from '../../components/ui/Input';
+import Button from '../../components/ui/Button';
+import LoadingSpinner from '../../components/ui/LoadingSpinner';
+import SectionTitle from '@/components/ui/SectionTitle';
+import toast from 'react-hot-toast';
+
+export default function Login() {
+ // ์ ์ญ ๋ก์ปฌ ์ ์ ๋ฅผ ์ธํ
ํด์ฃผ๋ ํจ์
+ const { setUser } = userStore();
+
+ //๋ก๊ทธ์ธ ํ ์ง์ ์ ํ์ด์ง๋ก ์ด๋ํ๊ธฐ ์ํด
+ const navigate = useNavigate();
+
+ const [isSending, setIsSending] = useState(false);
+ const [loginData, setLoginData] = useState({ email: '', password: '' });
+
+ const handleChange = (event: React.ChangeEvent) => {
+ const { name, value } = event.target;
+ setLoginData({
+ ...loginData,
+ [name]: value,
+ });
+ };
+
+ const handleLogin = async (event: React.FormEvent) => {
+ // form์ด๋ฒคํธ์ ๊ธฐ๋ณธ ์๋ก๊ณ ์นจ์ ๋ง์
+ event.preventDefault();
+
+ // ์ด๋ฉ์ผ๊ณผ ๋น๋ฐ๋ฒํธ๋ฅผ ์
๋ ฅํ์ง ์์๊ฒฝ์ฐ
+ if (loginData.email.trim() === '' || loginData.password.trim() === '') {
+ toast.error('์ด๋ฉ์ผ ๋๋ ๋น๋ฐ๋ฒํธ๋ฅผ ์
๋ ฅํด์ฃผ์ธ์.', { id: 'login' });
+ return;
+ }
+
+ // ์ด๋ฉ์ผ์ ์ ํจ์ฑ ๊ฒ์ฌ
+ if (!EMAIL_REGEX.test(loginData.email)) {
+ toast.error('์ฌ๋ฐ๋ฅธ ์ด๋ฉ์ผ์ ์
๋ ฅํด์ฃผ์ธ์.', { id: 'login' });
+ return;
+ }
+
+ // ํต์ ์์
+ setIsSending(true);
+ toast.loading('๋ก๊ทธ์ธ ์ค', { id: 'login' });
+ const res = await signIn(loginData);
+
+ // ๋ก๊ทธ์ธ ์ฑ๊ณต
+ if (res.statusCode === 200) {
+ const user = res.data as UserResponseValue;
+ // ์ด๋๋ฏผ ์ฌ๋ถ ํ์ธ(๋ณด์์ ๋งค์ฐ ์์ข์)
+ const isAdmin = ADMINS.includes(user.user.email);
+ // // ๋ก์ปฌ ์ ์ฅ์์ user์ ๋ณด์ isAdmin์ ๋ฌธ์์ดํ์์ผ์ ์ ์ฅ
+ localStorage.setItem('user', JSON.stringify({ ...user, isAdmin }));
+ // ๋ก์ปฌ user์ ์ํ๋ ์ ์ฅ
+ setUser({ ...user, isAdmin });
+ setIsSending(false);
+ navigate(-1);
+ toast.success(isAdmin ? '์ฃผ์ธ๋ ์ค์
จ์ต๋๋ค!๐ธ๐ธ' : res.message, {
+ id: 'login',
+ });
+ return;
+ }
+
+ // ๋ก๊ทธ์ธ ์คํจ
+ const errorMessage = res.message;
+ toast.error(errorMessage, { id: 'login' });
+ setIsSending(false);
+ };
+
+ return (
+
+ );
+}
diff --git a/src/routes/myAccount/LogoutNeededRoute.tsx b/src/routes/myAccount/LogoutNeededRoute.tsx
new file mode 100644
index 00000000..6b2b685b
--- /dev/null
+++ b/src/routes/myAccount/LogoutNeededRoute.tsx
@@ -0,0 +1,15 @@
+import { Navigate } from 'react-router-dom';
+import { userStore } from '@/store';
+
+type LogoutNeededRouteProps = {
+ element: React.ReactNode;
+};
+
+export default function LogoutNeededRoute({ element }: LogoutNeededRouteProps) {
+ const { userInfo } = userStore();
+
+ if (userInfo) {
+ return ;
+ }
+ return <>{element}>;
+}
diff --git a/src/routes/myAccount/MyAccount.tsx b/src/routes/myAccount/MyAccount.tsx
new file mode 100644
index 00000000..c33626e9
--- /dev/null
+++ b/src/routes/myAccount/MyAccount.tsx
@@ -0,0 +1,27 @@
+/* eslint-disable react-hooks/exhaustive-deps */
+import { Outlet } from 'react-router-dom';
+import SubNavbar from '@/components/SubNavbar';
+import { SUB_MENUS_MYACCOUNT } from '@/constants/constants';
+import { userStore } from '@/store';
+import { useEffect } from 'react';
+import toast from 'react-hot-toast';
+
+export default function MyAccount() {
+ const { authMe } = userStore();
+ useEffect(() => {
+ async function auth() {
+ const errorMessage = await authMe();
+ if (errorMessage) {
+ toast.error(errorMessage, { id: 'authMe' });
+ }
+ }
+ auth();
+ }, []);
+
+ return (
+ <>
+
+
+ >
+ );
+}
diff --git a/src/routes/myAccount/OrderDetail.tsx b/src/routes/myAccount/OrderDetail.tsx
new file mode 100644
index 00000000..2e9cdb88
--- /dev/null
+++ b/src/routes/myAccount/OrderDetail.tsx
@@ -0,0 +1,114 @@
+/* eslint-disable react-hooks/exhaustive-deps */
+import { useEffect, useState } from 'react';
+import { useNavigate, useParams } from 'react-router-dom';
+import { getOrderDetail } from '@/api/transactionApi';
+import { userStore } from '@/store';
+import { convertToHumanReadable } from '@/lib/time';
+import CrazyLoading from '@/components/ui/CrazyLoading';
+import SectionTitle from '@/components/ui/SectionTitle';
+import toast from 'react-hot-toast';
+import { DICTIONARY_SHOES } from '@/constants/constants';
+import Button from '@/components/ui/Button';
+
+export default function OrderDetail() {
+ const navigate = useNavigate();
+ const [isLoading, setIsLoading] = useState(false);
+ const { detailId } = useParams();
+ const [detail, setDetail] = useState();
+ const { userInfo } = userStore();
+
+ console.log(detail);
+ useEffect(() => {
+ const fetchData = async () => {
+ setIsLoading(true);
+ const res = await getOrderDetail(
+ userInfo?.accessToken as string,
+ detailId as string
+ );
+ if (res.statusCode === 200) {
+ setDetail(res.data as TransactionDetail);
+ setIsLoading(false);
+ return;
+ }
+ toast.error(res.message, { id: 'getOrderDetail' });
+ navigate('/');
+ setIsLoading(false);
+ };
+ fetchData();
+ }, [detailId, userInfo?.accessToken]);
+
+ return (
+ <>
+ {isLoading ? (
+
+ ) : (
+
+
+
+
+
+ navigate(
+ `/products/${detail?.product.tags[0]}/${detail?.product.productId}`
+ )
+ }
+ />
+
+
+
+
+
+ ์ํ |
+ {detail?.account.bankName} |
+
+
+ ๊ณ์ข ๋ฒํธ |
+ {detail?.account.accountNumber} |
+
+
+ ์ํ ์ด๋ฏธ์ง |
+
+
+ |
+
+
+ ์ํ ์ด๋ฆ |
+ {detail?.product.title} |
+
+
+ ์ํ ๊ฐ๊ฒฉ(์) |
+ {detail?.product.price.toLocaleString('ko-KR')} |
+
+
+
+ ์นดํ
๊ณ ๋ฆฌ |
+ {DICTIONARY_SHOES[detail?.product.tags[0] as string]} |
+
+
+ ๋ธ๋๋ |
+ {detail?.product.tags[1].toUpperCase()} |
+
+
+ ํ ์ธ์จ |
+ {detail?.product.discountRate}% |
+
+
+ ๊ตฌ๋งค ์๊ฐ |
+ {convertToHumanReadable(detail?.timePaid || '')} |
+
+
+ ๊ตฌ๋งค ์๋ฃ ์ฌ๋ถ |
+ {detail?.done ? '์๋ฃ๋จ' : '์๋ฃ๋์ง ์์'} |
+
+
+
+
+ )}
+ >
+ );
+}
diff --git a/src/routes/myAccount/OrderList.tsx b/src/routes/myAccount/OrderList.tsx
new file mode 100644
index 00000000..4d42bca7
--- /dev/null
+++ b/src/routes/myAccount/OrderList.tsx
@@ -0,0 +1,162 @@
+import { confirmOrder, getOrderList, cancelOrder } from '@/api/transactionApi';
+import Button from '@/components/ui/Button';
+import CrazyLoading from '@/components/ui/CrazyLoading';
+import SectionTitle from '@/components/ui/SectionTitle';
+import { convertToHumanReadable, convertToMilliseconds } from '@/lib/time';
+import { userStore } from '@/store';
+import { useEffect, useState } from 'react';
+import { toast } from 'react-hot-toast';
+import { useNavigate } from 'react-router-dom';
+
+export default function OrderList() {
+ const { userInfo } = userStore();
+ const [orders, setOrders] = useState([]);
+ const [isLoading, setIsLoading] = useState(false);
+ const [isOrdered, setIsOrdered] = useState(false);
+ const navigate = useNavigate();
+
+ useEffect(() => {
+ async function fetchData() {
+ setIsLoading(true);
+ const res = await getOrderList(userInfo?.accessToken as string);
+ if (res.statusCode === 200) {
+ setOrders(
+ (res.data as TransactionDetail[])
+ .filter((order) => !order.isCanceled)
+ .sort(
+ (a, b) =>
+ convertToMilliseconds(b.timePaid) -
+ convertToMilliseconds(a.timePaid)
+ )
+ );
+ setIsLoading(false);
+ return;
+ }
+ toast.error(res.message, { id: 'fetchOrderList' });
+ setIsLoading(false);
+ }
+ fetchData();
+ }, [userInfo?.accessToken, isOrdered]);
+
+ const handleConfirmOrder = async (
+ event: React.MouseEvent,
+ orderId: string,
+ productTitle: string
+ ) => {
+ event.stopPropagation();
+ setIsOrdered(false);
+ if (confirm(`${productTitle} ๊ตฌ๋งค๋ฅผ ํ์ ํ์๊ฒ ์ต๋๊น?`)) {
+ toast.loading('๊ตฌ๋งคํ์ ์์ฒญ ์ค...', { id: 'confirmOrder' });
+ const res = await confirmOrder(userInfo?.accessToken as string, orderId);
+ if (res.statusCode === 200) {
+ toast.success(`${productTitle} ๊ตฌ๋งค๋ฅผ ํ์ ํ์์ต๋๋ค.`, {
+ id: 'confirmOrder',
+ });
+ setIsOrdered(true);
+ return;
+ }
+ toast.error(res.message, { id: 'confirmOrder' });
+ }
+ };
+
+ const toOrderDetail = (orderId: string) => {
+ navigate(`/myaccount/order/${orderId}`);
+ };
+
+ const handleCancel = async (
+ event: React.MouseEvent,
+ detailId: string,
+ productTitle: string
+ ) => {
+ event.stopPropagation();
+ if (confirm(`${productTitle} ๊ตฌ๋งค๋ฅผ ์ทจ์ํ์๊ฒ ์ต๋๊น?`)) {
+ toast.loading('๊ตฌ๋งค ์ทจ์ ์์ฒญ ์ค', { id: 'cancelOrder' });
+ const res = await cancelOrder(detailId, userInfo?.accessToken as string);
+
+ if (res.statusCode === 200) {
+ const updatedOrders = orders.filter(
+ (order) => order.detailId !== detailId
+ );
+ setOrders(updatedOrders);
+ toast.success(`${productTitle} ๊ตฌ๋งค๋ฅผ ์ทจ์ํ์์ต๋๋ค.`, {
+ id: 'cancelOrder',
+ });
+ return;
+ }
+ toast.error(res.message, { id: 'cancelOrder' });
+ }
+ };
+
+ return (
+ <>
+ {isLoading ? (
+
+ ) : (
+
+
+
+
+
+ ์ํ์ด๋ฏธ์ง |
+ ์ํ๋ช
|
+ ์ํ๊ฐ๊ฒฉ(์) |
+ ์ฃผ๋ฌธ์๊ฐ |
+ ๊ตฌ๋งคํ์ |
+ |
+
+
+
+ {orders?.map((order) => (
+ toOrderDetail(order.detailId)}
+ className="cursor-pointer hover:opacity-80"
+ >
+
+
+ |
+ {order.product.title} |
+ {order.product.price.toLocaleString('ko-KR')} |
+ {convertToHumanReadable(order.timePaid)} |
+ {order.done ? '๐' : 'โ'} |
+
+
+ handleConfirmOrder(
+ event,
+ order.detailId,
+ order.product.title
+ )
+ }
+ secondary
+ />
+ {order.done ? (
+ <>>
+ ) : (
+
+ handleCancel(
+ event,
+ order.detailId,
+ order.product.title
+ )
+ }
+ />
+ )}
+ |
+
+ ))}
+
+
+
+ )}
+ >
+ );
+}
diff --git a/src/routes/myAccount/SignUp.tsx b/src/routes/myAccount/SignUp.tsx
new file mode 100644
index 00000000..7b7b499f
--- /dev/null
+++ b/src/routes/myAccount/SignUp.tsx
@@ -0,0 +1,171 @@
+import { useState } from 'react';
+import { useNavigate } from 'react-router-dom';
+import { userStore } from '@/store';
+import { signUp } from '@/api/authApi';
+import { EMAIL_REGEX } from '@/constants/constants';
+import Button from '@/components/ui/Button';
+import Input from '@/components/ui/Input';
+import LoadingSpinner from '@/components/ui/LoadingSpinner';
+import ImageUpload from '@/components/ui/ImageUpload';
+import SectionTitle from '@/components/ui/SectionTitle';
+import toast from 'react-hot-toast';
+
+export default function SignUp() {
+ const navigate = useNavigate();
+ const { setUser } = userStore();
+
+ const [signUpData, setSignData] = useState({
+ email: '',
+ password: '',
+ passwordRepeat: '',
+ displayName: '',
+ profileImgBase64: '',
+ });
+
+ const [isSending, setIsSending] = useState(false);
+
+ const handleChange = (event: React.ChangeEvent) => {
+ const { name, value } = event.target;
+ // ์ด๋ฏธ์ง ํ์ผ ๋ค๋ฃจ๋ ๋ก์ง
+ if (name === 'profileImgBase64') {
+ const files = event.target.files as FileList;
+ const reader = new FileReader();
+ reader.readAsDataURL(files[0]);
+ reader.onloadend = () => {
+ setSignData({ ...signUpData, [name]: reader.result as string });
+ };
+ }
+ setSignData((prevData) => ({
+ ...prevData,
+ [name]: value,
+ }));
+ };
+
+ const handleSubmit = async (event: React.FormEvent) => {
+ event.preventDefault();
+
+ // ์ด๋ฉ์ผ or ๋น๋ฐ๋ฒํธ or ์ด๋ฆ์ ์
๋ ฅํ์ง ์์๊ฒฝ์ฐ
+ if (
+ signUpData.email.trim() === '' ||
+ signUpData.password.trim() === '' ||
+ signUpData.displayName.trim() === ''
+ ) {
+ toast.error('์ด๋ฉ์ผ, ๋น๋ฐ๋ฒํธ, ๋๋ค์์ ๋ชจ๋ ์
๋ ฅํด์ฃผ์ธ์.', {
+ id: 'signUp',
+ });
+ return;
+ }
+
+ // ์ด๋ฉ์ผ์ ์ ํจ์ฑ ๊ฒ์ฌ
+ if (!EMAIL_REGEX.test(signUpData.email)) {
+ toast.error('์ฌ๋ฐ๋ฅธ ์ด๋ฉ์ผ์ ์
๋ ฅํด์ฃผ์ธ์.', {
+ id: 'signUp',
+ });
+ return;
+ }
+
+ // ๋น๋ฒ 8์๋ฆฌ ์ ํจ์ฑ๊ฒ์ฌ
+ if (signUpData.password.length < 7) {
+ toast.error('๋น๋ฐ๋ฒํธ๋ฅผ 8์๋ฆฌ ์ด์ ์
๋ ฅํด์ฃผ์ธ์.', {
+ id: 'signUp',
+ });
+ return;
+ }
+
+ // ์ด๋ฆ ๊ธธ์ด ์ ํจ์ฑ๊ฒ์ฌ
+ if (signUpData.displayName.length > 20) {
+ toast.error('๋๋ค์์ 20์ ์ดํ๋ก ์์ฑํด์ฃผ์ธ์.', {
+ id: 'signUp',
+ });
+ return;
+ }
+
+ // ๋น๋ฐ๋ฒํธ ํ์ธ
+ if (signUpData.password !== signUpData.passwordRepeat) {
+ toast.error('๋น๋ฐ๋ฒํธ๊ฐ ์ผ์นํ์ง ์์ต๋๋ค.', {
+ id: 'signUp',
+ });
+ return;
+ }
+
+ // ํต์ ์์
+ setIsSending(true);
+ toast.loading('ํ์๊ฐ์
์์ฒญ ์ค...', { id: 'signUp' });
+ const res = await signUp(signUpData);
+ // ํ์๊ฐ์
์ ์ฑ๊ณตํ๋ ๊ฒฝ์ฐ
+ if (res.statusCode === 200) {
+ const user = res.data as UserResponseValue;
+ setIsSending(false);
+ toast.success(`${user.user.displayName}๋ ์ฆ๊ฑฐ์ด ์ผํ ๋์ธ์!`, {
+ id: 'signUp',
+ });
+ // ์๋ก ๊ฐ์
ํ๋ ์ฌ๋์ด ๊ด๋ฆฌ์์ผ๋ฆฌ ์์
+ localStorage.setItem('user', JSON.stringify({ ...user, isAdmin: false }));
+ setUser({ ...user, isAdmin: false });
+ navigate('/', { replace: true });
+ return;
+ }
+ // ํ์๊ฐ์
์คํจ
+ toast.error(res.message, {
+ id: 'signUp',
+ });
+ setIsSending(false);
+ };
+
+ return (
+
+ );
+}
diff --git a/src/routes/myAccount/bank/BankAccounts.tsx b/src/routes/myAccount/bank/BankAccounts.tsx
new file mode 100644
index 00000000..58ce41b9
--- /dev/null
+++ b/src/routes/myAccount/bank/BankAccounts.tsx
@@ -0,0 +1,120 @@
+/* eslint-disable react-hooks/exhaustive-deps */
+import { useState, useEffect } from 'react';
+import { getAccountListAndBalance, deleteAccount } from '@/api/bankApi';
+import Button from '@/components/ui/Button';
+import { useNavigate } from 'react-router-dom';
+import LoadingSpinner from '@/components/ui/LoadingSpinner';
+import { userStore } from '@/store';
+import toast from 'react-hot-toast';
+import CrazyLoading from '@/components/ui/CrazyLoading';
+import SectionTitle from '@/components/ui/SectionTitle';
+
+export default function BankAccounts() {
+ const navigate = useNavigate();
+ const [totalBalance, setTotalBalance] = useState(0);
+ const [accounts, setAccounts] = useState();
+ const [isLoading, setIsLoading] = useState(false);
+ const [isDeleting, setIsDeleting] = useState(false);
+ const { userInfo } = userStore();
+
+ useEffect(() => {
+ setIsLoading(true);
+ async function fetchAccountList() {
+ const res = await getAccountListAndBalance(
+ userInfo?.accessToken as string
+ );
+ if (res.statusCode === 200) {
+ if (res.data?.accounts.length === 0) {
+ setIsLoading(false);
+ toast.error('๋จผ์ ๊ณ์ข๋ฅผ ๋ฑ๋กํด์ฃผ์ธ์', { id: 'getAccounts' });
+ navigate('/myaccount/connectAccount');
+ return;
+ }
+ setTotalBalance((res.data as AccountsAndBalance).totalBalance);
+ setAccounts((res.data as AccountsAndBalance).accounts);
+ setIsLoading(false);
+ return;
+ }
+ toast.error(res.message, { id: 'getAccounts' });
+ setIsLoading(false);
+ }
+ fetchAccountList();
+ }, [userInfo?.accessToken]);
+
+ const handleDeleteAccount = async (
+ accountId: string,
+ accountName: string
+ ) => {
+ if (confirm(`${accountName} ๊ณ์ข๋ฅผ ํด์งํ์๊ฒ ์ต๋๊น?`)) {
+ setIsDeleting(true);
+ setAccounts((prevAccounts) =>
+ prevAccounts?.map((account) =>
+ account.id === accountId ? { ...account, delete: true } : account
+ )
+ );
+ const res = await deleteAccount(
+ { accountId, signature: true },
+ userInfo?.accessToken as string
+ );
+ if (res.statusCode === 200) {
+ toast.success(`${accountName} ๊ณ์ข๋ฅผ ํด์งํ์์ต๋๋ค.`, {
+ id: 'deleteAccount',
+ });
+ setAccounts((prev) => prev?.filter((bank) => bank.id !== accountId));
+ setIsDeleting(false);
+ return;
+ }
+ toast.error(res.message, { id: 'deleteAccount' });
+ setIsDeleting(false);
+ }
+ };
+
+ return (
+ <>
+ {isLoading ? (
+
+ ) : (
+
+
+
+
+
+ ์ํ๋ช
|
+ ๊ณ์ข๋ฒํธ |
+ ์์ก(์) |
+ ํด์ง |
+
+
+
+ {accounts?.map((account) => (
+
+ {account.bankName} |
+ {account.accountNumber} |
+ {account.balance.toLocaleString('ko-KR')} |
+
+
+ ) : (
+ 'ํด์ง'
+ )
+ }
+ onClick={() =>
+ handleDeleteAccount(account.id, account.bankName)
+ }
+ disabled={isDeleting}
+ />
+ |
+
+ ))}
+
+
+
+ ์์ก : {totalBalance.toLocaleString('kr-KO')}์
+
+
+ )}
+ >
+ );
+}
diff --git a/src/routes/myAccount/bank/ConnectBankAccount.tsx b/src/routes/myAccount/bank/ConnectBankAccount.tsx
new file mode 100644
index 00000000..0fc6f196
--- /dev/null
+++ b/src/routes/myAccount/bank/ConnectBankAccount.tsx
@@ -0,0 +1,157 @@
+import { useState, useEffect, useMemo } from 'react';
+import { connectAccount, getBankList } from '@/api/bankApi';
+import Select from '@/components/ui/Select';
+import { userStore } from '@/store';
+import Input from '@/components/ui/Input';
+import { BANKS } from '@/constants/constants';
+import Button from '@/components/ui/Button';
+import { useNavigate } from 'react-router-dom';
+import LoadingSpinner from '@/components/ui/LoadingSpinner';
+import { toast } from 'react-hot-toast';
+import SectionTitle from '@/components/ui/SectionTitle';
+
+export default function ConnectBankAccount() {
+ const navigate = useNavigate();
+ const [isSending, setIsSending] = useState(false);
+ const { userInfo } = userStore();
+ const [banks, setBanks] = useState([]);
+
+ useEffect(() => {
+ async function fetchData() {
+ const res = await getBankList(userInfo?.accessToken as string);
+ if (res.statusCode === 200) {
+ setBanks(res.data as Bank[]);
+ return;
+ }
+ toast.error(res.message, { id: 'getBankList' });
+ }
+ fetchData();
+ }, [userInfo?.accessToken]);
+
+ // ๊ฐ์ ธ์จ ์ํ๋ค ์ค ์ฌ์ฉ ๊ฐ๋ฅํ ๊ฒ๋ง option์ผ๋ก ์ฌ์ฉ
+ const bankOptions = useMemo(
+ () => [
+ { name: '์ํ์ ํ*', value: '' },
+ ...banks
+ .filter((bank) => !bank.disabled)
+ .map((bank) => ({
+ name: bank.name,
+ value: bank.code,
+ })),
+ ],
+ [banks]
+ );
+
+ // ๊ณ์ข๋ฑ๋ก์ ํ์ํ data ์คํ
์ดํธ
+ const [bankInputData, setBankInputData] = useState({
+ accountNumber: '',
+ bankCode: '',
+ phoneNumber: '',
+ signature: false,
+ });
+
+ const handleChange = (
+ event: React.ChangeEvent
+ ) => {
+ const { value, name } = event.target;
+ if (event.target.type === 'checkbox') {
+ setBankInputData((prev) => ({
+ ...prev,
+ [name]: (event.target as HTMLInputElement).checked,
+ }));
+ } else {
+ setBankInputData((prev) => ({ ...prev, [name]: value }));
+ }
+ };
+
+ // ์ํ์ ํ์ digits์ ํฉ์ ๊ตฌํ๋ ๋ก์ง
+ const selectedBankDigits = useMemo(
+ () =>
+ BANKS.find((bank) => bank.code === bankInputData.bankCode)?.digits.reduce(
+ (acc, curr) => acc + curr
+ ),
+ [bankInputData.bankCode]
+ );
+
+ // ์ ์กํจ์
+ async function handleSubmit(event: React.FormEvent) {
+ event.preventDefault();
+ if (
+ bankInputData.bankCode.trim() === '' ||
+ bankInputData.accountNumber.trim() === '' ||
+ bankInputData.phoneNumber.trim() === ''
+ ) {
+ toast.error('์ํ, ๊ณ์ข๋ฒํธ, ํด๋ํฐ๋ฒํธ๋ฅผ ์
๋ ฅํด์ฃผ์ธ์.');
+ return;
+ }
+ if (!bankInputData.signature) {
+ toast.error('๊ฐํธ๊ฒฐ์ ๋ฑ๋ก์ ๋์ํด์ฃผ์ธ์.');
+ return;
+ }
+
+ setIsSending(true);
+ toast.loading('๊ณ์ข๋ฅผ ์ถ๊ฐํ๊ณ ์์ต๋๋ค.', { id: 'connectAccount' });
+ const res = await connectAccount(
+ bankInputData,
+ userInfo?.accessToken as string
+ );
+ if (res.statusCode === 200) {
+ toast.success(res.message, { id: 'connectAccount' });
+ setIsSending(false);
+ navigate('/myaccount/accountList');
+ return;
+ }
+ toast.error(res.message, { id: 'connectAccount' });
+ setIsSending(false);
+ }
+
+ return (
+
+ );
+}
diff --git a/src/store.ts b/src/store.ts
new file mode 100644
index 00000000..166b425b
--- /dev/null
+++ b/src/store.ts
@@ -0,0 +1,69 @@
+import { create } from 'zustand';
+import { authenticate } from '@/api/authApi';
+import { ADMINS } from '@/constants/constants';
+
+// user๊ด๋ จ ์ ์ญstate(store)์ ๋ฌด์์ด ๋ค์ด๊ฐ๋์ง ํ์
์ง์
+interface UserState {
+ userInfo: LocalUser | null;
+ setUser: (user: LocalUser | null) => void;
+ authMe: () => Promise;
+}
+
+export const userStore = create((set) => ({
+ //์ ์ ธ์ ๋ณด(useState์ฒ๋ผ ์ด๊ธฐ๊ฐ์ ์ง์ ํด์ค)
+ // ๋ก์ปฌ์ ์ฅ์์ 'user'๊ฐ์ด ์์ผ๋ฉด usrInfo์ ํด๋น๊ฐ์ JSON.parseํ ๊ฐ์ฒด๋ฅผ ํ ๋น, ์์ผ๋ฉด null
+ userInfo: localStorage.getItem('user')
+ ? JSON.parse(localStorage.getItem('user') as string)
+ : null,
+
+ // ์ฌ์ฉ์ ์ธํ
+ setUser: (user: LocalUser | null) =>
+ set({
+ userInfo: user,
+ }),
+
+ // ์ธ์ฆ
+ authMe: async () => {
+ // ๋ก์ปฌ์ ์ฅ์์ 'user'๊ฐ ์๋ค๋ฉด json.parse์์ผ ๊ฐ์ฒด๋ก ๋ง๋ค๊ณ useInfo์ ์ ์ฅ / ์๋ค๋ฉด useInfo์ null
+ const userInfo: LocalUser | null = localStorage.getItem('user')
+ ? JSON.parse(localStorage.getItem('user') as string)
+ : null;
+
+ // ๋ก์ปฌ์ ์ฅ์์ ์ ์ ธ๊ฐ ์๋ ๊ฒฝ์ฐ
+ if (!userInfo) {
+ // ์ ์ ธ ์ด๊ธฐํ
+ set({
+ userInfo: null,
+ });
+ return '๋ก๊ทธ์ธ์ ํด์ฃผ์ธ์.';
+ }
+ // ๋ก์ปฌ์ ์ฅ์์ user๊ฐ ์๋ ๊ฒฝ์ฐ
+ const res = await authenticate(userInfo.accessToken);
+ // ์ธ์ฆ์ ์ฑ๊ณตํ๋ ๊ฒฝ์ฐ
+ if (res.statusCode === 200) {
+ const user = res.data as AuthenticateResponseValue;
+ const isAdmin = ADMINS.includes(user.email);
+ // ํด๋น์ ์ ๋ฅผ ํด๋ผ์ด์ธํธ ์ ์ญ ์ ์ ์ํ์ ์ธํ
+ set({
+ userInfo: {
+ user: user,
+ accessToken: userInfo.accessToken,
+ isAdmin,
+ },
+ });
+ // ๋ก์ปฌ ์ ์ฅ์์๋ ์ธํ
+ localStorage.setItem(
+ 'user',
+ JSON.stringify({ user, accessToken: userInfo.accessToken, isAdmin })
+ );
+
+ return;
+ }
+ // ํ ํฐ์ ์์ผ๋ ์ธ์ฆ์ ์คํจํ ๊ฒฝ์ฐ (expired or ํ ํฐ ๊ฐ ์ธ์์ ์กฐ์)
+ set({
+ userInfo: null,
+ });
+ localStorage.removeItem('user');
+ return '๋ก๊ทธ์ธ ํ์ ์ง 24์๊ฐ์ด ์ง๋์
จ์ด์! ๋ค์ ๋ก๊ทธ์ธํด์ฃผ์ธ์.';
+ },
+}));
diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts
new file mode 100644
index 00000000..11f02fe2
--- /dev/null
+++ b/src/vite-env.d.ts
@@ -0,0 +1 @@
+///
diff --git a/tailwind.config.js b/tailwind.config.js
new file mode 100644
index 00000000..967ca12b
--- /dev/null
+++ b/tailwind.config.js
@@ -0,0 +1,14 @@
+import daisyui from 'daisyui';
+
+/** @type {import('tailwindcss').Config} */
+export default {
+ content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
+ theme: {
+ extend: {
+ colors: {
+ accent: '#e41717',
+ },
+ },
+ },
+ plugins: [daisyui],
+};
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 00000000..6a965703
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,28 @@
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "useDefineForClassFields": true,
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
+ "module": "ESNext",
+ "skipLibCheck": true,
+ "moduleResolution": "node",
+ "baseUrl": ".",
+ "paths": {
+ "@/*": ["src/*"]
+ },
+ "allowSyntheticDefaultImports": true,
+ /* Bundler mode */
+ "allowImportingTsExtensions": true,
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "noEmit": true,
+ "jsx": "react-jsx",
+ /* Linting */
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "include": ["src", "**/*.ts", "**/*.tsx"],
+ "references": [{ "path": "./tsconfig.node.json" }]
+}
diff --git a/tsconfig.node.json b/tsconfig.node.json
new file mode 100644
index 00000000..42872c59
--- /dev/null
+++ b/tsconfig.node.json
@@ -0,0 +1,10 @@
+{
+ "compilerOptions": {
+ "composite": true,
+ "skipLibCheck": true,
+ "module": "ESNext",
+ "moduleResolution": "bundler",
+ "allowSyntheticDefaultImports": true
+ },
+ "include": ["vite.config.ts"]
+}
diff --git a/vite.config.ts b/vite.config.ts
new file mode 100644
index 00000000..445e88c4
--- /dev/null
+++ b/vite.config.ts
@@ -0,0 +1,13 @@
+import { defineConfig } from 'vite';
+import react from '@vitejs/plugin-react-swc';
+import path from 'path';
+
+// https://vitejs.dev/config/
+export default defineConfig({
+ plugins: [react()],
+ resolve: {
+ alias: {
+ '@': path.resolve(__dirname, './src'),
+ },
+ },
+});