diff --git a/.eslintrc.json b/.eslintrc.json
new file mode 100644
index 00000000..95edec7b
--- /dev/null
+++ b/.eslintrc.json
@@ -0,0 +1,11 @@
+{
+ "extends": [
+ "eslint:recommended",
+ "plugin:react/recommended",
+ "plugin:prettier/recommended"
+ ],
+ "plugins": [
+ "react",
+ "prettier"
+ ]
+}
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..47591372
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,28 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+.env
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
+
+# Local Netlify folder
+.netlify
\ No newline at end of file
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 00000000..33a8b8de
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,9 @@
+{
+ "semi": true,
+ "singleQuote": false,
+ "endOfLine": "lf",
+ "singleAttributePerLine": true,
+ "bracketSameLine": true,
+ "trailingComma": "none",
+ "arrowParens": "avoid"
+}
\ No newline at end of file
diff --git a/README.md b/README.md
index c81804bf..61414e05 100644
--- a/README.md
+++ b/README.md
@@ -1,1319 +1,195 @@
-# π€ κ±°λ API νμ©, ν νλ‘μ νΈ
+# π μ§ κ°κ΅¬μΆμ΄ (SweetHome)
-μ£Όμ΄μ§ APIλ₯Ό λΆμν΄ μ΄λ€ νλ‘μ νΈλ₯Ό μ§ν/μμ±ν κ²μΈμ§ ν λ¨μλ‘ μμ λ‘κ² κ²°μ νκ³ λ§λ€μ΄λ³΄μΈμ.
-TypeScriptλ₯Ό νμλ‘ μ¬μ©ν΄μΌ ν©λλ€.
-κ³Όμ μν λ° λ¦¬λ·° κΈ°κ°μ λ³λ 곡μ§λ₯Ό μ°Έκ³ νμΈμ!
+
React, TypeScript, Rest APIλ₯Ό νμ©ν λΌμ΄ν μ€νμΌ ν λ°μ½Β·μΈν
λ¦¬μ΄ μΌνλͺ° νλ‘μ νΈμ
λλ€.
+μ±λ³κ³Ό μ°λ Ήμ μκ΄μμ΄ λͺ¨λκ° κ΄μ¬μ κ°μ§κ³ μ΄μ©ν μ μλ μΈν
λ¦¬μ΄ κ΄λ ¨ μ£Όμ λ‘ μ μ νμμΌλ©°,
+βμ§(Home)β + βκ°κ΅¬(Furniture)β + βκ°κ³ μΆλ€.(Want To Go)β μ ν©μ±μ΄λ‘ μΈμ μ΄λμλ μ§μ κ°κ³ μΆκ² λ§λλ μ νμ ν맀νλ€λ μλ―Έμ μΌνλͺ°μ
λλ€.
-## κ³Όμ μν λ° μ μΆ λ°©λ²
+
-```
-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
-}
-```
+> **ν¨μ€νΈμΊ νΌμ€ νλ‘ νΈμλ κ°λ° λΆνΈμΊ ν 5κΈ°**
+> **κ°λ° κΈ°κ°** : 2023. 05. 30 ~ 2023. 07. 01
+> **λ°°ν¬ μ£Όμ** : [DEMO](https://fe5-team9.github.io/sweethome)
-```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...(μλ΅)"
-}
-```
+| **[κΉμ€ν¬](https://github.com/dev-junehee)** | **[μ‘νλΉ](https://github.com/hbsongk)** | **[μ‘°μμ](https://github.com/ChoEun-Sang)** | **[λ°κ·Όμ°](https://github.com/SpeedGear)** | **[λ°±λμ](https://github.com/debeck6)** |
+| :--------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------: |
+| | | | | |
+|νμκ°μ
About νμ΄μ§
μν νμ΄μ§
μ₯λ°κ΅¬λ νμ΄μ§
κ²°μ νμ΄μ§
κ΄λ¦¬μ νμ΄μ§
Footer|λ‘κ·ΈμΈ/λ‘κ·Έμμ
κ²μ κΈ°λ₯
λ©μΈ νμ΄μ§
μν νμ΄μ§
μ₯λ°κ΅¬λ νμ΄μ§
κ²°μ νμ΄μ§
Header|νμκ°μ
λ‘κ·ΈμΈ μΈμ¦
λ§μ΄νμ΄μ§
μν νμ΄μ§
μ₯λ°κ΅¬λ νμ΄μ§
κ²°μ νμ΄μ§
κ΄λ¦¬μ νμ΄μ§|λμμΈ μ°Έμ¬|λμμΈ μ°Έμ¬|
-### λ‘κ·ΈμΈ
+
-- λ°κΈλ `accessToken`μ 24μκ° ν λ§λ£λ©λλ€.(λ§λ£ ν λ€μ λ‘κ·ΈμΈ νμ)
+## μ¬μ©κΈ°μ λ° κ°λ°νκ²½
-```curl
-curl https://asia-northeast3-heropy-api.cloudfunctions.net/api/auth/login
- \ -X 'POST'
-```
-
-μμ² λ°μ΄ν° νμ
λ° μμ:
-
-```ts
-interface RequestBody {
- email: string // μ¬μ©μ μμ΄λ (νμ!)
- password: string // μ¬μ©μ λΉλ°λ²νΈ (νμ!)
-}
-```
+### Development
-```json
-{
- "email": "thesecon@gmail.com",
- "password": "********"
-}
-```
+
+
+
+
+
+
+
+
+
-μλ΅ λ°μ΄ν° νμ
λ° μμ:
+### Config
-```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...(μλ΅)"
-}
-```
+### Deployment
+
+
-### μΈμ¦ νμΈ
+### Environment
+
+
+
+
+
+
+
+### Cowork Tools
+
+
+
+
+
+
+
+
+
+
+### μ 체 νλ©΄ ꡬμ±
+| **λ©μΈ νμ΄μ§** | **About νμ΄μ§** |
+| :--------------------------------------------: | :--------------------------------------------: |
+| | |
+
+| **μν λͺ©λ‘ νμ΄μ§** | **μν μμΈ νμ΄μ§** |
+| :--------------------------------------------: | :--------------------------------------------: |
+| | |
+
+| **μ₯λ°κ΅¬λ νμ΄μ§** | **κ²°μ νμ΄μ§** |
+| :--------------------------------------------: | :--------------------------------------------: |
+| |
+
+| **λ§μ΄ νμ΄μ§ (μ£Όλ¬Έ λ΄μ κ΄λ¦¬)** | **λ§μ΄ νμ΄μ§ (μ£Όλ¬Έ λ΄μ μμΈ)** |
+| :--------------------------------------------: | :--------------------------------------------: |
+| |
-```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 '
-```
+## νλ‘μ νΈ μμΈ κΈ°λ₯
-μμ² λ°μ΄ν° νμ
λ° μμ:
+### Layout
+- React-Router-Domμ outlet μ€μ²© λΌμ°ν
μ νμ©ν λ μ΄μμ ꡬμ±
+- Reduxλ₯Ό μ¬μ©ν μ μ μν κ΄λ¦¬
+- μ¬μ¬μ©μ λμ΄κΈ° μν μΈλΆ μ»΄ν¬λνΈ κ΅¬μ±
+- λ λμ UXλ₯Ό μν λ‘λ© μ€νΌλ μΆκ°
+### Head
+- μΉ΄ν
κ³ λ¦¬ (Navbar) : useNavigate, NavLinkλ₯Ό νμ©ν νμ΄μ§ λΌμ°ν° κ΄λ¦¬
+- μ ν κ²μ κΈ°λ₯ : useState, useNavigate, ChangeEventλ₯Ό νμ©ν κ²μ κΈ°λ₯ ꡬν
-- μμ
+### λ©μΈ νμ΄μ§ (Home)
+- μ΄λ―Έμ§ μ¬λΌμ΄λ : React-sliderλ₯Ό νμ©ν λ©μΈ νμ΄μ§ μ΄λ―Έμ§ μ¬λΌμ΄λ ꡬν
+
+### μν νμ΄μ§ (Shop)
+- μν λͺ©λ‘ νμ΄μ§ : productItem μ»΄ν¬λνΈλ‘ μ¬μ¬μ©μ±μ λμ΄κ³ MouseEventμ useStateλ₯Ό νμ©ν μΉ΄ν
κ³ λ¦¬ νν° κ΅¬ν
+- μν μμΈ νμ΄μ§ : useParamsλ₯Ό νμ©ν μν μμΈ μ 보 μ‘°ν(ID), Reduxλ₯Ό νμ©ν μ₯λ°κ΅¬λ κΈ°λ₯ ꡬν
+- μ₯λ°κ΅¬λ λ΄κΈ° κΈ°λ₯ : Redux, useDispatch, useSelector, useNavigate, useParamsλ₯Ό νμ©ν μ₯λ°κ΅¬λ μν κ΄λ¦¬ ꡬν
+- κ²°μ νμ΄μ§ : useNavigate, Reduxλ₯Ό νμ©ν νμ΄μ§ λΌμ°ν
, λ°μ΄ν° μ λ¬ κ΅¬ν
+
+### μ₯λ°κ΅¬λ νμ΄μ§ (Cart)
+- μ₯λ°κ΅¬λ λͺ©λ‘ μ‘°ν : Redux, useSelector, useNavigateλ₯Ό νμ©ν μ₯λ°κ΅¬λ μν κ΄λ¦¬ ꡬν
+- μ 체/μ ν μν ꡬ맀 : Reduxλ₯Ό νμ©νμ¬ μν μ ν μ 무μ λ°λ₯Έ μ‘°κ±΄λΆ λ λλ§ κ΅¬ν
+
+### κ²°μ νμ΄μ§ (Buy)
+- κ²°μ κΈ°λ₯ : Reduxλ₯Ό νμ©ν κ²°μ μμΈ μ 보 μΆλ ₯ λ° μ¬μ©μ κ³μ’ μ 무μ λ°λ₯Έ μ‘°κ±΄λΆ λ λλ§ κ΅¬ν
-μλ΅ λ°μ΄ν° νμ
λ° μμ:
+### λ§μ΄νμ΄μ§ (Mypage)
+- μ£Όλ¬Έ λ΄μ μ‘°ν
+ - μν ꡬ맀 μ·¨μ : State λ³νμ λ°λ₯Έ μ‘°κ±΄λΆ λ λλ§ κ΅¬ν
+ - μν ꡬ맀 νμ : State λ³νμ λ°λ₯Έ μ‘°κ±΄λΆ λ λλ§ κ΅¬ν
+ - μμΈ μ 보 μ‘°ν : μ£Όλ¬Έ μκ°(μ΅μ μ)μ λ°λ₯Έ μν ꡬ맀 λ΄μ μ λ ¬ ꡬν
+- κ³μ’ κ΄λ¦¬
+ - μ 체 κ³μ’ μ‘°ν
+ - κ³μ’ λ±λ‘ : Modalμ ν΅ν κ³μ’ λ±λ‘, μν μ νμ μν μ½λ μλ μ
λ ₯ ꡬν, μ리μμ λ°λ₯Έ μ¬λ¬ κ°μ input μν κ΄λ¦¬
+ - κ³μ’ μμ : μ»΄ν¬λνΈλ₯Ό νμ©ν λ±λ‘ κ³μ’ 리μ€νΈ μΆλ ₯, λ±λ‘ κ³μ’ μ¬λΆμ λ°λΌ μ‘°κ±΄λΆ λ λλ§ κ΅¬ν
+- κ°μΈ μ 보 μμ : λΉλ°λ²νΈ μ¬νμΈ κΈ°λ₯ ꡬν, React-Hook-formμ ν΅ν μ½λ λ¨μν λ° μ ν¨μ± κ²μ¬ ꡬν
+
+### κ΄λ¦¬μ νμ΄μ§ (Admin)
+- μ 체 μ¬μ©μ λͺ©λ‘ μ‘°ν
+- μν κ΄λ¦¬
+ - μ 체 μν λͺ©λ‘ μ‘°ν
+ - μν λ±λ‘ : Select μ»΄ν¬λνΈλ₯Ό μ΄μ©ν μν νκ·Έ λ±λ‘ ꡬν
+ - μν μμ : React-icons νμ©ν μμ λ²νΌ μμ±
+ - μν μ 보 μμ : React-icons, Modal μ»΄ν¬λνΈλ₯Ό ν΅ν μν μ 보 μμ λ° κΈ°μ‘΄ μ 보 νμΈ κΈ°λ₯ ꡬν
+- μ£Όλ¬Έ λ΄μ κ΄λ¦¬
+ - μ 체 κ±°λ λ΄μ μ‘°ν
+ - κ±°λ μ·¨μ : State λ³νμ λ°λ₯Έ μ‘°κ±΄λΆ λ λλ§ κ΅¬ν
+ - κ±°λ νμ : State λ³νμ λ°λ₯Έ μ‘°κ±΄λΆ λ λλ§ κ΅¬ν
+
+### μΈμ¦ & μΈκ°
+- νμκ°μ
: React-Hook-Formμ μ΄μ©ν λΉμ μ΄ μ»΄ν¬λνΈ κ΄λ¦¬ λ° μ ν¨μ± κ²μ¬ ꡬν
+- λ‘κ·ΈμΈ : useStateλ₯Ό ν΅ν΄ λ‘κ·ΈμΈ κΈ°λ₯ ꡬν
+- λ‘κ·ΈμΈ μΈμ¦ : App.tsxμμ useEffectλ₯Ό μ΄μ©ν λͺ¨λ νμ νμ΄μ§ λ‘κ·ΈμΈ μΈμ¦ ꡬν
+- λ‘κ·Έμμ : Reduxλ₯Ό μ¬μ©ν΄ Header λ‘κ·Έμμ UI ꡬν
-```ts
-type ResponseValue = true // λ‘κ·Έμμ μ²λ¦¬ μν
-```
+
+
+## νλ‘μ νΈ ν
μ€νΈ
-### μ¬μ©μ μ 보 μμ
+### clone project
-```curl
-curl https://asia-northeast3-heropy-api.cloudfunctions.net/api/auth/user
- \ -X 'PUT'
- \ -H 'Authorization: Bearer '
+```bash
+$ git clone git@github.com:FE5-TEAM9/sweethome.git
```
-μμ² λ°μ΄ν° νμ
λ° μμ:
-
-```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μ
λλ€.
-
-```curl
-curl https://asia-northeast3-heropy-api.cloudfunctions.net/api/auth/users
- \ -X 'GET'
- \ -H 'masterKey: true'
-```
-
-μμ² λ°μ΄ν° νμ
λ° μμ:
-
-- μμ
-
-μλ΅ λ°μ΄ν° νμ
λ° μμ:
-
-```ts
-type ResponseValue = User[]
-
-interface User {
- email: string // μ¬μ©μ μμ΄λ
- displayName: string // μ¬μ©μ νμ μ΄λ¦
- profileImg: string // μ¬μ©μ νλ‘ν μ΄λ―Έμ§ URL
-}
-```
-
-```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"
- }
-]
-```
-
-
-
-## κ³μ’
-
-'κ³μ’' κ΄λ ¨ 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 '
-```
-
-μμ² λ°μ΄ν° νμ
λ° μμ:
-
-- μμ
-
-μλ΅ λ°μ΄ν° νμ
λ° μμ:
-
-```ts
-type ResponseValue = Bank[] // μ ν κ°λ₯ν μν μ 보 λͺ©λ‘
-
-interface Bank { // μ ν κ°λ₯ν μν μ 보
- name: string // μν μ΄λ¦
- code: string // μν μ½λ
- digits: number[] // μν κ³μ’ μλ¦Ώμ
- disabled: boolean // μ¬μ©μκ° μΆκ°ν κ³μ’ μ¬λΆ
-}
-```
-
-```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
- }
-]
-```
+### go to project
-### κ³μ’ λͺ©λ‘ λ° μμ‘ μ‘°ν
+```bash
+$ cd sweethome
+```
-- κ³μ’λ²νΈλ μΌλΆλ§ λ
ΈμΆλ©λλ€. E.g. `"123-XXXX-XXXX-XX"`
-- μμ‘μ λ¨μλ 'μν(οΏ¦)'μ
λλ€.
+### install npm
-```curl
-curl https://asia-northeast3-heropy-api.cloudfunctions.net/api/account
- \ -X 'GET'
- \ -H 'Authorization: Bearer '
+```bash
+$ npm install
```
-μμ² λ°μ΄ν° νμ
λ° μμ:
-
-- μμ
-
-μλ΅ λ°μ΄ν° νμ
λ° μμ:
-
-```ts
-interface ResponseValue {
- totalBalance: number // μ¬μ©μ κ³μ’ μμ‘ μ΄ν©
- accounts: Bank[] // μ¬μ©μ κ³μ’ μ 보 λͺ©λ‘
-}
-
-interface Bank { // μ¬μ©μ κ³μ’ μ 보
- id: string // κ³μ’ ID
- bankName: string // μν μ΄λ¦
- bankCode: string // μν μ½λ
- accountNumber: string // κ³μ’ λ²νΈ
- balance: number // κ³μ’ μμ‘
-}
-```
-
-```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
- }
- ]
-}
-```
-
-### κ³μ’ μ°κ²°
-
-- μ°κ²°λ κ³μ’ μμ‘μλ μλμΌλ‘ κΈ°λ³Έ '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
- }
- }
-]
-```
-
-### κ±°λ(ν맀) λ΄μ μλ£/μ·¨μ λ° ν΄μ
-
-- κ΄λ¦¬μ μ μ© 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
- }
- }
- ]
-}
-```
-
-### μ ν κ²μ
-
-- μ¬μ©μ μ μ© APIμ
λλ€.
-- μ ν μ΄λ¦κ³Ό νκ·Έλ₯Ό λμμ κ²μν μ μκ³ , 'And'(κ²μν μ΄λ¦κ³Ό νκ·Έ λͺ¨λ ν¬ν¨λ μ ν) 쑰건μΌλ‘ κ²°κ³Όλ₯Ό λ°νν©λλ€.
-- μ ν μ΄λ¦κ³Ό νκ·Έ λͺ¨λ ν¬ν¨νμ§ μμΌλ©΄, λͺ¨λ μ νμ κ²°κ³Όλ₯Ό λ°νν©λλ€.
-- μ νμ κΈ°λ³Έ μ λ³΄λ§ λ°νν©λλ€.
-- 맀μ§λ μ νμ κ²μλμ§ μμ΅λλ€.
-
-```curl
-curl https://asia-northeast3-heropy-api.cloudfunctions.net/api/products/search
- \ -X 'POST'
-```
-
-μμ² λ°μ΄ν° νμ
λ° μμ:
-
-```ts
-interface RequestBody {
- searchText?: string // κ²μν μ ν μ΄λ¦
- searchTags?: string[] // κ²μν μ ν νκ·Έ
-}
-```
-
-```json
-{
- "searchText": "μΌμ±μ μ",
- "searchTags": ["κ°μ "]
-}
-```
-
-μλ΅ λ°μ΄ν° νμ
λ° μμ:
-
-```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 // μμ½ λ§λ£ μ¬λΆ
-}
-```
+### start project
-```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
-}
+```bash
+$ npm run dev
```
diff --git a/index.html b/index.html
new file mode 100644
index 00000000..f4e546ea
--- /dev/null
+++ b/index.html
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ μ§ κ°κ΅¬μΆμ΄(SweetHome)
+
+
+
+
+
+
diff --git a/netlify.toml b/netlify.toml
new file mode 100644
index 00000000..ff1c0508
--- /dev/null
+++ b/netlify.toml
@@ -0,0 +1,4 @@
+[[redirects]]
+ from = "/*"
+ to = "/index.html"
+ status = 200
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 00000000..4d0ff359
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,3756 @@
+{
+ "name": "sweethome",
+ "version": "0.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "sweethome",
+ "version": "0.0.0",
+ "dependencies": {
+ "@types/react-router-dom": "^5.3.3",
+ "esbuild": "^0.18.1",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0",
+ "react-hook-form": "^7.45.0",
+ "react-icons": "^4.9.0",
+ "react-redux": "^8.1.0",
+ "react-router-dom": "^6.12.1",
+ "react-table": "^7.8.0",
+ "redux": "^4.2.1",
+ "redux-persist": "^6.0.0",
+ "swiper": "^9.4.1",
+ "vite-plugin-remove-console": "^2.1.1"
+ },
+ "devDependencies": {
+ "@types/node": "^20.2.5",
+ "@types/react": "^18.2.12",
+ "@types/react-dom": "^18.0.11",
+ "@typescript-eslint/eslint-plugin": "^5.59.0",
+ "@typescript-eslint/parser": "^5.59.0",
+ "@vitejs/plugin-react": "^4.0.0",
+ "eslint": "^8.42.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",
+ "prettier": "^2.8.8",
+ "sass": "^1.62.1",
+ "typescript": "^5.0.2",
+ "vite": "^4.3.9"
+ }
+ },
+ "node_modules/@ampproject/remapping": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz",
+ "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.0",
+ "@jridgewell/trace-mapping": "^0.3.9"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/code-frame": {
+ "version": "7.21.4",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz",
+ "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==",
+ "dev": true,
+ "dependencies": {
+ "@babel/highlight": "^7.18.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/compat-data": {
+ "version": "7.22.3",
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.3.tgz",
+ "integrity": "sha512-aNtko9OPOwVESUFp3MZfD8Uzxl7JzSeJpd7npIoxCasU37PFbAQRpKglkaKwlHOyeJdrREpo8TW8ldrkYWwvIQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/core": {
+ "version": "7.22.1",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.1.tgz",
+ "integrity": "sha512-Hkqu7J4ynysSXxmAahpN1jjRwVJ+NdpraFLIWflgjpVob3KNyK3/tIUc7Q7szed8WMp0JNa7Qtd1E9Oo22F9gA==",
+ "dev": true,
+ "dependencies": {
+ "@ampproject/remapping": "^2.2.0",
+ "@babel/code-frame": "^7.21.4",
+ "@babel/generator": "^7.22.0",
+ "@babel/helper-compilation-targets": "^7.22.1",
+ "@babel/helper-module-transforms": "^7.22.1",
+ "@babel/helpers": "^7.22.0",
+ "@babel/parser": "^7.22.0",
+ "@babel/template": "^7.21.9",
+ "@babel/traverse": "^7.22.1",
+ "@babel/types": "^7.22.0",
+ "convert-source-map": "^1.7.0",
+ "debug": "^4.1.0",
+ "gensync": "^1.0.0-beta.2",
+ "json5": "^2.2.2",
+ "semver": "^6.3.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/babel"
+ }
+ },
+ "node_modules/@babel/core/node_modules/semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/@babel/generator": {
+ "version": "7.22.3",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.3.tgz",
+ "integrity": "sha512-C17MW4wlk//ES/CJDL51kPNwl+qiBQyN7b9SKyVp11BLGFeSPoVaHrv+MNt8jwQFhQWowW88z1eeBx3pFz9v8A==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.22.3",
+ "@jridgewell/gen-mapping": "^0.3.2",
+ "@jridgewell/trace-mapping": "^0.3.17",
+ "jsesc": "^2.5.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets": {
+ "version": "7.22.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.1.tgz",
+ "integrity": "sha512-Rqx13UM3yVB5q0D/KwQ8+SPfX/+Rnsy1Lw1k/UwOC4KC6qrzIQoY3lYnBu5EHKBlEHHcj0M0W8ltPSkD8rqfsQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/compat-data": "^7.22.0",
+ "@babel/helper-validator-option": "^7.21.0",
+ "browserslist": "^4.21.3",
+ "lru-cache": "^5.1.1",
+ "semver": "^6.3.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets/node_modules/semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/@babel/helper-environment-visitor": {
+ "version": "7.22.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.1.tgz",
+ "integrity": "sha512-Z2tgopurB/kTbidvzeBrc2To3PUP/9i5MUe+fU6QJCQDyPwSH2oRapkLw3KGECDYSjhQZCNxEvNvZlLw8JjGwA==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-function-name": {
+ "version": "7.21.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz",
+ "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/template": "^7.20.7",
+ "@babel/types": "^7.21.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-hoist-variables": {
+ "version": "7.18.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz",
+ "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.18.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-imports": {
+ "version": "7.21.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz",
+ "integrity": "sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.21.4"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-transforms": {
+ "version": "7.22.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.1.tgz",
+ "integrity": "sha512-dxAe9E7ySDGbQdCVOY/4+UcD8M9ZFqZcZhSPsPacvCG4M+9lwtDDQfI2EoaSvmf7W/8yCBkGU0m7Pvt1ru3UZw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-environment-visitor": "^7.22.1",
+ "@babel/helper-module-imports": "^7.21.4",
+ "@babel/helper-simple-access": "^7.21.5",
+ "@babel/helper-split-export-declaration": "^7.18.6",
+ "@babel/helper-validator-identifier": "^7.19.1",
+ "@babel/template": "^7.21.9",
+ "@babel/traverse": "^7.22.1",
+ "@babel/types": "^7.22.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-plugin-utils": {
+ "version": "7.21.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.21.5.tgz",
+ "integrity": "sha512-0WDaIlXKOX/3KfBK/dwP1oQGiPh6rjMkT7HIRv7i5RR2VUMwrx5ZL0dwBkKx7+SW1zwNdgjHd34IMk5ZjTeHVg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-simple-access": {
+ "version": "7.21.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.21.5.tgz",
+ "integrity": "sha512-ENPDAMC1wAjR0uaCUwliBdiSl1KBJAVnMTzXqi64c2MG8MPR6ii4qf7bSXDqSFbr4W6W028/rf5ivoHop5/mkg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.21.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-split-export-declaration": {
+ "version": "7.18.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz",
+ "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.18.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-string-parser": {
+ "version": "7.21.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.21.5.tgz",
+ "integrity": "sha512-5pTUx3hAJaZIdW99sJ6ZUUgWq/Y+Hja7TowEnLNMm1VivRgZQL3vpBY3qUACVsvw+yQU6+YgfBVmcbLaZtrA1w==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.19.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
+ "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-option": {
+ "version": "7.21.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz",
+ "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helpers": {
+ "version": "7.22.3",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.3.tgz",
+ "integrity": "sha512-jBJ7jWblbgr7r6wYZHMdIqKc73ycaTcCaWRq4/2LpuPHcx7xMlZvpGQkOYc9HeSjn6rcx15CPlgVcBtZ4WZJ2w==",
+ "dev": true,
+ "dependencies": {
+ "@babel/template": "^7.21.9",
+ "@babel/traverse": "^7.22.1",
+ "@babel/types": "^7.22.3"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/highlight": {
+ "version": "7.18.6",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
+ "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.18.6",
+ "chalk": "^2.0.0",
+ "js-tokens": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.22.4",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.4.tgz",
+ "integrity": "sha512-VLLsx06XkEYqBtE5YGPwfSGwfrjnyPP5oiGty3S8pQLFDFLaS8VwWSIxkTXpcvr5zeYLE6+MBNl2npl/YnfofA==",
+ "dev": true,
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx-self": {
+ "version": "7.21.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.21.0.tgz",
+ "integrity": "sha512-f/Eq+79JEu+KUANFks9UZCcvydOOGMgF7jBrcwjHa5jTZD8JivnhCJYvmlhR/WTXBWonDExPoW0eO/CR4QJirA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.20.2"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx-source": {
+ "version": "7.19.6",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.19.6.tgz",
+ "integrity": "sha512-RpAi004QyMNisst/pvSanoRdJ4q+jMCWyk9zdw/CyLB9j8RXEahodR6l2GyttDRyEVWZtbN+TpLiHJ3t34LbsQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.19.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/runtime": {
+ "version": "7.22.3",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.3.tgz",
+ "integrity": "sha512-XsDuspWKLUsxwCp6r7EhsExHtYfbe5oAGQ19kqngTdCPUoPQzOPdUbD/pB9PJiwb2ptYKQDjSJT3R6dC+EPqfQ==",
+ "dependencies": {
+ "regenerator-runtime": "^0.13.11"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/template": {
+ "version": "7.21.9",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.21.9.tgz",
+ "integrity": "sha512-MK0X5k8NKOuWRamiEfc3KEJiHMTkGZNUjzMipqCGDDc6ijRl/B7RGSKVGncu4Ro/HdyzzY6cmoXuKI2Gffk7vQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.21.4",
+ "@babel/parser": "^7.21.9",
+ "@babel/types": "^7.21.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/traverse": {
+ "version": "7.22.4",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.4.tgz",
+ "integrity": "sha512-Tn1pDsjIcI+JcLKq1AVlZEr4226gpuAQTsLMorsYg9tuS/kG7nuwwJ4AB8jfQuEgb/COBwR/DqJxmoiYFu5/rQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.21.4",
+ "@babel/generator": "^7.22.3",
+ "@babel/helper-environment-visitor": "^7.22.1",
+ "@babel/helper-function-name": "^7.21.0",
+ "@babel/helper-hoist-variables": "^7.18.6",
+ "@babel/helper-split-export-declaration": "^7.18.6",
+ "@babel/parser": "^7.22.4",
+ "@babel/types": "^7.22.4",
+ "debug": "^4.1.0",
+ "globals": "^11.1.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/types": {
+ "version": "7.22.4",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.4.tgz",
+ "integrity": "sha512-Tx9x3UBHTTsMSW85WB2kphxYQVvrZ/t1FxD88IpSgIjiUJlCm9z+xWIDwyo1vffTwSqteqyznB8ZE9vYYk16zA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-string-parser": "^7.21.5",
+ "@babel/helper-validator-identifier": "^7.19.1",
+ "to-fast-properties": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.18.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.1.tgz",
+ "integrity": "sha512-8+QS98jqdreHLvCojIke8NjcuelB+Osysazr15EhkUIuG0Ov5WK26XgPYWViCTjHnKQxbpS86/JryBOkEpyrBA==",
+ "cpu": [
+ "arm"
+ ],
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.18.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.1.tgz",
+ "integrity": "sha512-l5V0IWGTYfQMzl4ulgIHKMZPwabIS4a39ZvtkPwL6LYiX3UtL76sylA6eFKufJCB43mwEYqbXoBSMn++NpxILw==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.18.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.1.tgz",
+ "integrity": "sha512-1y8/bRek6EYxQeGTUfwL2mmj6NAeXZ3h5YSc4W2Y/kduI1B8VhT4x5X0VxrcGkIKef4N5qCdziRxvei/YUfESg==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.18.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.1.tgz",
+ "integrity": "sha512-FFT/on9qQTOntdloQvgfwFkRhNI5l/TCNXZS1CpH6JQd0boR637aThi9g9FYs4o31Ao72/jPZFDiRln5Cu6R2A==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.18.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.1.tgz",
+ "integrity": "sha512-p/ZIUt+NlW8qRNVTXoKJgRuc49teazvmXBquoGOm5D6IAimTfWJVJrEivqpoMKyDS/0/PxDMRM2lrkxlSa7XeQ==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.18.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.1.tgz",
+ "integrity": "sha512-eYUDR3thO96ULRf4rJcG9TJ/sQc6Z/YNe16mC/KvVeAOtzmeTXiPMETEv/iMqTCxZhYkHyQG/mYbAxPBWC2mcg==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.18.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.1.tgz",
+ "integrity": "sha512-w03zjxyg51qktv0JKsV+AbY3uSb1Awifs8IkKQSUXdP3sdPxxmPzZLrlJ1+LjKZRiSa4yP/Haayi/hriNVoIdQ==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.18.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.1.tgz",
+ "integrity": "sha512-d6FXeb8F/cuXtSZuVHQN0Rz3gs3g2Xy/M4KJJRzbKsBx3pwCQuRdSrYxcr7g0PFN8geIOspiLQnUzwONyMA3Bw==",
+ "cpu": [
+ "arm"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.18.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.1.tgz",
+ "integrity": "sha512-dHlvkKAVlYNt5LPg1GUha99QiaEGKEC21zpHVAxs7hhW6EkR8nN3iWmyndGXxVJm4K7e4lKAzl8ekPqSr5gAXQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.18.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.1.tgz",
+ "integrity": "sha512-QHS4duBPuAsLZP82sNeoqTXAJ1mNU4QcfmYtBN/jNvQJXb6n0im8F4ljFSAQbivt1jl1OnKL8HhlLUeKY75nLg==",
+ "cpu": [
+ "ia32"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.18.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.1.tgz",
+ "integrity": "sha512-g4YSiF/qBvXvJhSowxaR7Ei/79otL48Qfjviuo+FpXREykA9nSe407T5ZvezFXryFgdf44Fe8lWpjvtQ+n42cQ==",
+ "cpu": [
+ "loong64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.18.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.1.tgz",
+ "integrity": "sha512-/G1fzmaR5u2S9wgQhiQEhWRct0+GMpuNjhll59uv5Tjojlma9MUPinVnvpw9Re+Idb6gxe6kmzUxFP2YkC/svg==",
+ "cpu": [
+ "mips64el"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.18.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.1.tgz",
+ "integrity": "sha512-NkDjIvleUc3lSV1VI3QE9Oh5mz3nY11H5TCbi4DJ8X09FGwHN5pDVXdAsQYPGjlt/frXZzq6x7vMmTOb5VyBog==",
+ "cpu": [
+ "ppc64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.18.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.1.tgz",
+ "integrity": "sha512-IhN7Nz+HyDRnMQOLcCl6m5BgQMITMhS9O1hOqgAUIy6FI0m/0zTSkZHtvMmSIpOy1uleaGqfNDA9SM3nBeTATQ==",
+ "cpu": [
+ "riscv64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.18.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.1.tgz",
+ "integrity": "sha512-u9iRg0eUUIyBbg5hANvRBYRaAnhVemAA2+pi3IgrzQTMeR/uPHQtJI3XInNZkNR6ACA4Fdl8N941p81XygeqWQ==",
+ "cpu": [
+ "s390x"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.18.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.1.tgz",
+ "integrity": "sha512-0QeWU0a0+RmxPCDt+plXS7/hVMJtfde/LaSzs6X3UTr4FYA0hYpnwDzGXxumcPLzt5c8ctugPuKat0tmRb7noQ==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.18.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.1.tgz",
+ "integrity": "sha512-eFL7sxibN8wKuwrRf3HRkcjELALlfl/TavJ8P4J+BJfnkXOITF7zx4tTmGkzK8OwAR9snT2kEfp1Ictc80atGw==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.18.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.1.tgz",
+ "integrity": "sha512-riCQUnngF2xYUzr0XDdrGEEz0nqnocch0No7SBIQM22wTRi5gt5WqTQexGd/2u2Z19d0rVYQbKBelaJ1dwe9bg==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.18.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.1.tgz",
+ "integrity": "sha512-6lTop2k+GMkWlrwMy2+55xIBXKfXOi6uzWYypXZZP8HxXG3Mb5N4O71z2KzisVNJtYK2VlQRNbmGtUzIQIhHAw==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.18.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.1.tgz",
+ "integrity": "sha512-d6wt4g9GluZp7xCmgpm7gY6wy0mjcBHbKeeK9MYrlWNFJd8KBcD2uCil8kFuaH3Dt6AUz62D0wIoDETFsZ01Tg==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.18.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.1.tgz",
+ "integrity": "sha512-z51DOtcwECu4WlqJUhu39AVnnpaVmTvXei0EQxc99QK7ZJyn4tj0EelYkMBZckpqzqB/GyGSLwEclKtRJ0l2uw==",
+ "cpu": [
+ "ia32"
+ ],
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.18.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.1.tgz",
+ "integrity": "sha512-6tdeuCLT+l9QuCFaYsNtULO6xH2fgJObvICMCsOZvkqIey6FUXVVju5aO+OZjxswy7WgKadhI1k/nq2wQSmB+Q==",
+ "cpu": [
+ "x64"
+ ],
+ "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/eslintrc/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/@eslint/js": {
+ "version": "8.42.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.42.0.tgz",
+ "integrity": "sha512-6SWlXpWU5AvId8Ac7zjzmIOqMOba/JWY8XZ4A7q7Gn1Vlfg/SFFIlrtHXt9nPn4op9ZPAkl91Jao+QQv3r/ukw==",
+ "dev": true,
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ }
+ },
+ "node_modules/@humanwhocodes/config-array": {
+ "version": "0.11.10",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz",
+ "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==",
+ "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.3",
+ "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.6.3.tgz",
+ "integrity": "sha512-EXJysQ7J3veRECd0kZFQwYYd5sJMcq2O/m60zu1W2l3oVQ9xtub8jTOtYRE0+M2iomyG/W3Ps7+vp2kna0C27Q==",
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/@types/history": {
+ "version": "4.7.11",
+ "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz",
+ "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA=="
+ },
+ "node_modules/@types/hoist-non-react-statics": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
+ "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==",
+ "dependencies": {
+ "@types/react": "*",
+ "hoist-non-react-statics": "^3.3.0"
+ }
+ },
+ "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=="
+ },
+ "node_modules/@types/react": {
+ "version": "18.2.12",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.12.tgz",
+ "integrity": "sha512-ndmBMLCgn38v3SntMeoJaIrO6tGHYKMEBohCUmw8HoLLQdRMOIGXfeYaBTLe2lsFaSB3MOK1VXscYFnmLtTSmw==",
+ "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==",
+ "devOptional": true,
+ "dependencies": {
+ "@types/react": "*"
+ }
+ },
+ "node_modules/@types/react-router": {
+ "version": "5.1.20",
+ "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz",
+ "integrity": "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==",
+ "dependencies": {
+ "@types/history": "^4.7.11",
+ "@types/react": "*"
+ }
+ },
+ "node_modules/@types/react-router-dom": {
+ "version": "5.3.3",
+ "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz",
+ "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==",
+ "dependencies": {
+ "@types/history": "^4.7.11",
+ "@types/react": "*",
+ "@types/react-router": "*"
+ }
+ },
+ "node_modules/@types/scheduler": {
+ "version": "0.16.3",
+ "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz",
+ "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ=="
+ },
+ "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/@types/use-sync-external-store": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz",
+ "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA=="
+ },
+ "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": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.0.0.tgz",
+ "integrity": "sha512-HX0XzMjL3hhOYm+0s95pb0Z7F8O81G7joUHgfDd/9J/ZZf5k4xX6QAMFkKsHFxaHlf6X7GD7+XuaZ66ULiJuhQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/core": "^7.21.4",
+ "@babel/plugin-transform-react-jsx-self": "^7.21.0",
+ "@babel/plugin-transform-react-jsx-source": "^7.19.6",
+ "react-refresh": "^0.14.0"
+ },
+ "engines": {
+ "node": "^14.18.0 || >=16.0.0"
+ },
+ "peerDependencies": {
+ "vite": "^4.2.0"
+ }
+ },
+ "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/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": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "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/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/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/caniuse-lite": {
+ "version": "1.0.30001494",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001494.tgz",
+ "integrity": "sha512-sY2B5Qyl46ZzfYDegrl8GBCzdawSLT4ThM9b9F+aDYUrAG2zCOyMbd2Tq34mS1g4ZKBfjRlzOohQMxx28x6wJg==",
+ "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": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "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": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "1.1.3"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+ "dev": true
+ },
+ "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/convert-source-map": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
+ "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
+ "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/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/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/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/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.419",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.419.tgz",
+ "integrity": "sha512-jdie3RiEgygvDTyS2sgjq71B36q2cDSBfPlwzUyuOrfYTNoYWyBxxjGJV/HAu3A2hB0Y+HesvCVkVAFoCKwCSw==",
+ "dev": true
+ },
+ "node_modules/esbuild": {
+ "version": "0.18.1",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.1.tgz",
+ "integrity": "sha512-ZUvsIx2wPjpj86b805UwbGJu47Kxgr2UTio9rGhWpBr1oOVk88exzoieOgTweX0UcVCwSAk3z2WvNALpTcpQZw==",
+ "hasInstallScript": true,
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "optionalDependencies": {
+ "@esbuild/android-arm": "0.18.1",
+ "@esbuild/android-arm64": "0.18.1",
+ "@esbuild/android-x64": "0.18.1",
+ "@esbuild/darwin-arm64": "0.18.1",
+ "@esbuild/darwin-x64": "0.18.1",
+ "@esbuild/freebsd-arm64": "0.18.1",
+ "@esbuild/freebsd-x64": "0.18.1",
+ "@esbuild/linux-arm": "0.18.1",
+ "@esbuild/linux-arm64": "0.18.1",
+ "@esbuild/linux-ia32": "0.18.1",
+ "@esbuild/linux-loong64": "0.18.1",
+ "@esbuild/linux-mips64el": "0.18.1",
+ "@esbuild/linux-ppc64": "0.18.1",
+ "@esbuild/linux-riscv64": "0.18.1",
+ "@esbuild/linux-s390x": "0.18.1",
+ "@esbuild/linux-x64": "0.18.1",
+ "@esbuild/netbsd-x64": "0.18.1",
+ "@esbuild/openbsd-x64": "0.18.1",
+ "@esbuild/sunos-x64": "0.18.1",
+ "@esbuild/win32-arm64": "0.18.1",
+ "@esbuild/win32-ia32": "0.18.1",
+ "@esbuild/win32-x64": "0.18.1"
+ }
+ },
+ "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": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/eslint": {
+ "version": "8.42.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.42.0.tgz",
+ "integrity": "sha512-ulg9Ms6E1WPf67PHaEY4/6E2tEn5/f7FXGzr3t9cBMugOmf1INYvuUwwh1aXQN4MfJ6a5K2iNwP3w4AColvI9A==",
+ "dev": true,
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.2.0",
+ "@eslint-community/regexpp": "^4.4.0",
+ "@eslint/eslintrc": "^2.0.3",
+ "@eslint/js": "8.42.0",
+ "@humanwhocodes/config-array": "^0.11.10",
+ "@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/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/eslint/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/eslint/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/eslint/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/eslint/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/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/eslint/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/eslint/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/eslint/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/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/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/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/gensync": {
+ "version": "1.0.0-beta.2",
+ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "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": "11.12.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
+ "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "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/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-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/hoist-non-react-statics": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
+ "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
+ "dependencies": {
+ "react-is": "^16.7.0"
+ }
+ },
+ "node_modules/hoist-non-react-statics/node_modules/react-is": {
+ "version": "16.13.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
+ },
+ "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/immutable": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.0.tgz",
+ "integrity": "sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg==",
+ "dev": true
+ },
+ "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-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/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/jsesc": {
+ "version": "2.5.2",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
+ "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
+ "dev": true,
+ "bin": {
+ "jsesc": "bin/jsesc"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "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/json5": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "dev": true,
+ "bin": {
+ "json5": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "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/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": "5.1.1",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+ "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+ "dev": true,
+ "dependencies": {
+ "yallist": "^3.0.2"
+ }
+ },
+ "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/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/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/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-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/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/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/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-hook-form": {
+ "version": "7.45.0",
+ "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.45.0.tgz",
+ "integrity": "sha512-AbHeZ4ad+0dEIknSW9dBgIwcvRDfZ1O97sgj75WaMdOX0eg8TBiUf9wxzVkIjZbk76BBIE9lmFOzyD4PN80ZQg==",
+ "engines": {
+ "node": ">=12.22.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/react-hook-form"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17 || ^18"
+ }
+ },
+ "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-is": {
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
+ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
+ },
+ "node_modules/react-redux": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.1.0.tgz",
+ "integrity": "sha512-CtHZzAOxi7GQvTph4dVLWwZHAWUjV2kMEQtk50OrN8z3gKxpWg3Tz7JfDw32N3Rpd7fh02z73cF6yZkK467gbQ==",
+ "dependencies": {
+ "@babel/runtime": "^7.12.1",
+ "@types/hoist-non-react-statics": "^3.3.1",
+ "@types/use-sync-external-store": "^0.0.3",
+ "hoist-non-react-statics": "^3.3.2",
+ "react-is": "^18.0.0",
+ "use-sync-external-store": "^1.0.0"
+ },
+ "peerDependencies": {
+ "@reduxjs/toolkit": "^1 || ^2.0.0-beta.0",
+ "@types/react": "^16.8 || ^17.0 || ^18.0",
+ "@types/react-dom": "^16.8 || ^17.0 || ^18.0",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0",
+ "react-native": ">=0.59",
+ "redux": "^4 || ^5.0.0-beta.0"
+ },
+ "peerDependenciesMeta": {
+ "@reduxjs/toolkit": {
+ "optional": true
+ },
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ },
+ "react-dom": {
+ "optional": true
+ },
+ "react-native": {
+ "optional": true
+ },
+ "redux": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-refresh": {
+ "version": "0.14.0",
+ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz",
+ "integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/react-router": {
+ "version": "6.12.1",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.12.1.tgz",
+ "integrity": "sha512-evd/GrKJOeOypD0JB9e1r7pQh2gWCsTbUfq059Wm1AFT/K2MNZuDo19lFtAgIhlBrp0MmpgpqtvZC7LPAs7vSw==",
+ "dependencies": {
+ "@remix-run/router": "1.6.3"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "peerDependencies": {
+ "react": ">=16.8"
+ }
+ },
+ "node_modules/react-router-dom": {
+ "version": "6.12.1",
+ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.12.1.tgz",
+ "integrity": "sha512-POIZN9UDKWwEDga054LvYr2KnK8V+0HR4Ny4Bwv8V7/FZCPxJgsCjYxXGxqxzHs7VBxMKZfgvtKhafuJkJSPGA==",
+ "dependencies": {
+ "@remix-run/router": "1.6.3",
+ "react-router": "6.12.1"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "peerDependencies": {
+ "react": ">=16.8",
+ "react-dom": ">=16.8"
+ }
+ },
+ "node_modules/react-table": {
+ "version": "7.8.0",
+ "resolved": "https://registry.npmjs.org/react-table/-/react-table-7.8.0.tgz",
+ "integrity": "sha512-hNaz4ygkZO4bESeFfnfOft73iBUj8K5oKi1EcSHPAibEydfsX2MyU6Z8KCr3mv3C9Kqqh71U+DhZkFvibbnPbA==",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/tannerlinsley"
+ },
+ "peerDependencies": {
+ "react": "^16.8.3 || ^17.0.0-0 || ^18.0.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/redux": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz",
+ "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==",
+ "dependencies": {
+ "@babel/runtime": "^7.9.2"
+ }
+ },
+ "node_modules/redux-persist": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/redux-persist/-/redux-persist-6.0.0.tgz",
+ "integrity": "sha512-71LLMbUq2r02ng2We9S215LtPu3fY0KgaGE0k8WRgl6RkqxtGfl7HUozz1Dftwsb0D/5mZ8dwAaPbtnzfvbEwQ==",
+ "peerDependencies": {
+ "redux": ">4.0.0"
+ }
+ },
+ "node_modules/regenerator-runtime": {
+ "version": "0.13.11",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
+ "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
+ },
+ "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.1",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.23.1.tgz",
+ "integrity": "sha512-ybRdFVHOoljGEFILHLd2g/qateqUdjE6YS41WXq4p3C/WwD3xtWxV4FYWETA1u9TeXQc5K8L8zHE5d/scOvrOQ==",
+ "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/sass": {
+ "version": "1.62.1",
+ "resolved": "https://registry.npmjs.org/sass/-/sass-1.62.1.tgz",
+ "integrity": "sha512-NHpxIzN29MXvWiuswfc1W3I0N8SXBd8UR26WntmDlRYf0bSADnwnOjsyMZ3lMezSlArD33Vs3YFhp7dWvL770A==",
+ "dev": true,
+ "dependencies": {
+ "chokidar": ">=3.0.0 <4.0.0",
+ "immutable": "^4.0.0",
+ "source-map-js": ">=0.6.2 <2.0.0"
+ },
+ "bin": {
+ "sass": "sass.js"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "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/semver/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/semver/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/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/ssr-window": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/ssr-window/-/ssr-window-4.0.2.tgz",
+ "integrity": "sha512-ISv/Ch+ig7SOtw7G2+qkwfVASzazUnvlDTwypdLoPoySv+6MqlOV10VwPSE6EWkGjhW50lUmghPmpYZXMu/+AQ=="
+ },
+ "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/supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/swiper": {
+ "version": "9.4.1",
+ "resolved": "https://registry.npmjs.org/swiper/-/swiper-9.4.1.tgz",
+ "integrity": "sha512-1nT2T8EzUpZ0FagEqaN/YAhRj33F2x/lN6cyB0/xoYJDMf8KwTFT3hMOeoB8Tg4o3+P/CKqskP+WX0Df046fqA==",
+ "funding": [
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/swiperjs"
+ },
+ {
+ "type": "open_collective",
+ "url": "http://opencollective.com/swiper"
+ }
+ ],
+ "dependencies": {
+ "ssr-window": "^4.0.2"
+ },
+ "engines": {
+ "node": ">= 4.7.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/to-fast-properties": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
+ "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "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/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.1.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.3.tgz",
+ "integrity": "sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==",
+ "dev": true,
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "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/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/vite-plugin-remove-console": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/vite-plugin-remove-console/-/vite-plugin-remove-console-2.1.1.tgz",
+ "integrity": "sha512-AQOsKl9+1YO82otwSchf+P8SRo4RhMvPjOvjm9DXOnkff0SBwBPAzazEn06IUjhsm/zX4miMgicCQH1hPdktrw=="
+ },
+ "node_modules/vite/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/vite/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/vite/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/vite/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/vite/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/vite/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/vite/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/vite/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/vite/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/vite/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/vite/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/vite/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/vite/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/vite/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/vite/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/vite/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/vite/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/vite/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/vite/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/vite/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/vite/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/vite/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/vite/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/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": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+ "dev": true
+ },
+ "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"
+ }
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 00000000..ebd10fbb
--- /dev/null
+++ b/package.json
@@ -0,0 +1,45 @@
+{
+ "name": "sweethome",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "scripts": {
+ "start": "npm run build && node main.tsx",
+ "dev": "vite",
+ "build": "tsc && vite build",
+ "lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
+ "preview": "vite preview"
+ },
+ "dependencies": {
+ "@types/react-router-dom": "^5.3.3",
+ "esbuild": "^0.18.1",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0",
+ "react-hook-form": "^7.45.0",
+ "react-icons": "^4.9.0",
+ "react-redux": "^8.1.0",
+ "react-router-dom": "^6.12.1",
+ "react-table": "^7.8.0",
+ "redux": "^4.2.1",
+ "redux-persist": "^6.0.0",
+ "swiper": "^9.4.1",
+ "vite-plugin-remove-console": "^2.1.1"
+ },
+ "devDependencies": {
+ "@types/node": "^20.2.5",
+ "@types/react": "^18.2.12",
+ "@types/react-dom": "^18.0.11",
+ "@typescript-eslint/eslint-plugin": "^5.59.0",
+ "@typescript-eslint/parser": "^5.59.0",
+ "@vitejs/plugin-react": "^4.0.0",
+ "eslint": "^8.42.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",
+ "prettier": "^2.8.8",
+ "sass": "^1.62.1",
+ "typescript": "^5.0.2",
+ "vite": "^4.3.9"
+ }
+}
diff --git a/public/.DS_Store b/public/.DS_Store
new file mode 100644
index 00000000..ff082eed
Binary files /dev/null and b/public/.DS_Store differ
diff --git a/public/assets/.DS_Store b/public/assets/.DS_Store
new file mode 100644
index 00000000..286d035d
Binary files /dev/null and b/public/assets/.DS_Store differ
diff --git a/public/assets/Home/main1.jpeg b/public/assets/Home/main1.jpeg
new file mode 100644
index 00000000..d3769882
Binary files /dev/null and b/public/assets/Home/main1.jpeg differ
diff --git a/public/assets/Home/main2.jpeg b/public/assets/Home/main2.jpeg
new file mode 100644
index 00000000..39b7ab00
Binary files /dev/null and b/public/assets/Home/main2.jpeg differ
diff --git a/public/assets/Home/main3.jpeg b/public/assets/Home/main3.jpeg
new file mode 100644
index 00000000..42ade555
Binary files /dev/null and b/public/assets/Home/main3.jpeg differ
diff --git a/public/assets/README/01_main.png b/public/assets/README/01_main.png
new file mode 100644
index 00000000..c6ed1970
Binary files /dev/null and b/public/assets/README/01_main.png differ
diff --git a/public/assets/README/02_about.png b/public/assets/README/02_about.png
new file mode 100644
index 00000000..39a632b8
Binary files /dev/null and b/public/assets/README/02_about.png differ
diff --git a/public/assets/README/03_shop.png b/public/assets/README/03_shop.png
new file mode 100644
index 00000000..95c2c1d8
Binary files /dev/null and b/public/assets/README/03_shop.png differ
diff --git a/public/assets/README/04_shopdetail.png b/public/assets/README/04_shopdetail.png
new file mode 100644
index 00000000..67aac1ac
Binary files /dev/null and b/public/assets/README/04_shopdetail.png differ
diff --git a/public/assets/README/05_cart.png b/public/assets/README/05_cart.png
new file mode 100644
index 00000000..54c8495c
Binary files /dev/null and b/public/assets/README/05_cart.png differ
diff --git a/public/assets/README/06_buy.png b/public/assets/README/06_buy.png
new file mode 100644
index 00000000..5087e95f
Binary files /dev/null and b/public/assets/README/06_buy.png differ
diff --git a/public/assets/README/07_mypage_order.png b/public/assets/README/07_mypage_order.png
new file mode 100644
index 00000000..2f569ab0
Binary files /dev/null and b/public/assets/README/07_mypage_order.png differ
diff --git a/public/assets/README/08_mypage_orderdetail.png b/public/assets/README/08_mypage_orderdetail.png
new file mode 100644
index 00000000..cc6c800c
Binary files /dev/null and b/public/assets/README/08_mypage_orderdetail.png differ
diff --git a/public/assets/README/09_mypage_account.png b/public/assets/README/09_mypage_account.png
new file mode 100644
index 00000000..458e3e27
Binary files /dev/null and b/public/assets/README/09_mypage_account.png differ
diff --git a/public/assets/README/0_loading.png b/public/assets/README/0_loading.png
new file mode 100644
index 00000000..58f42fb2
Binary files /dev/null and b/public/assets/README/0_loading.png differ
diff --git a/public/assets/README/0_login.png b/public/assets/README/0_login.png
new file mode 100644
index 00000000..e3c1cd3c
Binary files /dev/null and b/public/assets/README/0_login.png differ
diff --git a/public/assets/README/0_search.png b/public/assets/README/0_search.png
new file mode 100644
index 00000000..82e75f45
Binary files /dev/null and b/public/assets/README/0_search.png differ
diff --git a/public/assets/README/0_signup.png b/public/assets/README/0_signup.png
new file mode 100644
index 00000000..166ab079
Binary files /dev/null and b/public/assets/README/0_signup.png differ
diff --git a/public/assets/README/10_mypage_account_modal.png b/public/assets/README/10_mypage_account_modal.png
new file mode 100644
index 00000000..834a03b5
Binary files /dev/null and b/public/assets/README/10_mypage_account_modal.png differ
diff --git a/public/assets/README/11_mypage_accountlist.png b/public/assets/README/11_mypage_accountlist.png
new file mode 100644
index 00000000..bc09ee68
Binary files /dev/null and b/public/assets/README/11_mypage_accountlist.png differ
diff --git a/public/assets/README/12_mypage_info.png b/public/assets/README/12_mypage_info.png
new file mode 100644
index 00000000..90de1b34
Binary files /dev/null and b/public/assets/README/12_mypage_info.png differ
diff --git a/public/assets/README/13_mypage_infochange.png b/public/assets/README/13_mypage_infochange.png
new file mode 100644
index 00000000..f45b90b4
Binary files /dev/null and b/public/assets/README/13_mypage_infochange.png differ
diff --git a/public/assets/README/14_admin_user.png b/public/assets/README/14_admin_user.png
new file mode 100644
index 00000000..e940bbc4
Binary files /dev/null and b/public/assets/README/14_admin_user.png differ
diff --git a/public/assets/README/15_admin_product.png b/public/assets/README/15_admin_product.png
new file mode 100644
index 00000000..404471ab
Binary files /dev/null and b/public/assets/README/15_admin_product.png differ
diff --git a/public/assets/README/16_admin_orderlist.png b/public/assets/README/16_admin_orderlist.png
new file mode 100644
index 00000000..66d4a905
Binary files /dev/null and b/public/assets/README/16_admin_orderlist.png differ
diff --git a/public/assets/about/about.jpeg b/public/assets/about/about.jpeg
new file mode 100644
index 00000000..75e4c3d9
Binary files /dev/null and b/public/assets/about/about.jpeg differ
diff --git a/public/assets/bank/bank004.svg b/public/assets/bank/bank004.svg
new file mode 100644
index 00000000..bc771df0
--- /dev/null
+++ b/public/assets/bank/bank004.svg
@@ -0,0 +1,3 @@
+
diff --git a/public/assets/bank/bank011.svg b/public/assets/bank/bank011.svg
new file mode 100644
index 00000000..468fe384
--- /dev/null
+++ b/public/assets/bank/bank011.svg
@@ -0,0 +1,11 @@
+
diff --git a/public/assets/bank/bank020.svg b/public/assets/bank/bank020.svg
new file mode 100644
index 00000000..ce2e479e
--- /dev/null
+++ b/public/assets/bank/bank020.svg
@@ -0,0 +1,80 @@
+
diff --git a/public/assets/bank/bank081.svg b/public/assets/bank/bank081.svg
new file mode 100644
index 00000000..31680943
--- /dev/null
+++ b/public/assets/bank/bank081.svg
@@ -0,0 +1,12 @@
+
diff --git a/public/assets/bank/bank088.svg b/public/assets/bank/bank088.svg
new file mode 100644
index 00000000..073094d3
--- /dev/null
+++ b/public/assets/bank/bank088.svg
@@ -0,0 +1,23 @@
+
diff --git a/public/assets/bank/bank089.svg b/public/assets/bank/bank089.svg
new file mode 100644
index 00000000..fa045f4f
--- /dev/null
+++ b/public/assets/bank/bank089.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/assets/bank/bank090.svg b/public/assets/bank/bank090.svg
new file mode 100644
index 00000000..4526c79c
--- /dev/null
+++ b/public/assets/bank/bank090.svg
@@ -0,0 +1,11 @@
+
diff --git a/public/assets/products/kitchen1-detail.jpeg b/public/assets/products/kitchen1-detail.jpeg
new file mode 100644
index 00000000..febc85f4
Binary files /dev/null and b/public/assets/products/kitchen1-detail.jpeg differ
diff --git a/public/assets/products/kitchen1.jpg b/public/assets/products/kitchen1.jpg
new file mode 100644
index 00000000..dfdb83e7
Binary files /dev/null and b/public/assets/products/kitchen1.jpg differ
diff --git a/public/favicon.png b/public/favicon.png
new file mode 100644
index 00000000..9b824b54
Binary files /dev/null and b/public/favicon.png differ
diff --git a/src/.DS_Store b/src/.DS_Store
new file mode 100644
index 00000000..9d327c6b
Binary files /dev/null and b/src/.DS_Store differ
diff --git a/src/App.scss b/src/App.scss
new file mode 100644
index 00000000..67232021
--- /dev/null
+++ b/src/App.scss
@@ -0,0 +1,4 @@
+.allSections {
+ min-height: calc(100vh - (100px + 150px));
+ width: 100%;
+}
\ No newline at end of file
diff --git a/src/App.tsx b/src/App.tsx
new file mode 100644
index 00000000..a1c3b6c8
--- /dev/null
+++ b/src/App.tsx
@@ -0,0 +1,37 @@
+import { useCallback, useEffect } from 'react';
+import { Outlet, useLocation } from 'react-router-dom';
+import { useDispatch } from "react-redux";
+import { authenticate } from '~/api/requests';
+import TheHeader from '~/components/common/TheHeader';
+import TheFooter from '~/components/common/TheFooter';
+import '~/App.scss';
+
+const App = () => {
+ const location = useLocation();
+ const dispatch = useDispatch()
+
+ useEffect(()=> {
+ authenticateHandler();
+ }, [location])
+
+ const authenticateHandler = useCallback(async () => {
+ try {
+ const res = await authenticate()
+ dispatch({ type: "RETURN_USER", payload: res })
+ } catch (err) {
+ console.log("λ‘κ·ΈμΈ μΈμ¦ μ€ν¨νμμ΅λλ€.")
+ }
+ }, [location])
+
+ return (
+ <>
+
+
+
+
+
+ >
+ )
+};
+
+export default App;
\ No newline at end of file
diff --git a/src/api/requests.ts b/src/api/requests.ts
new file mode 100644
index 00000000..8707c656
--- /dev/null
+++ b/src/api/requests.ts
@@ -0,0 +1,436 @@
+// Common Header
+const headers = {
+ "content-type": "application/json",
+ apikey: import.meta.env.VITE_API_KEY,
+ username: import.meta.env.VITE_USER_NAME,
+};
+
+// Common Interface
+interface User {
+ email: string;
+ password: string;
+}
+
+// Transactions Interface
+interface TransactionsBody {
+ detailId: string;
+}
+
+// Sign-Up νμκ°μ
+interface SignUpBody extends User {
+ displayName: string;
+}
+
+const signUp = async (body: SignUpBody) => {
+ const res = await fetch(`${import.meta.env.VITE_API_BASE}/auth/signup`, {
+ method: "POST",
+ headers,
+ body: JSON.stringify(body),
+ });
+ if (res.status === 200) {
+ const data = await res.json();
+ return data;
+ } else return false;
+};
+
+// Log-In λ‘κ·ΈμΈ
+const logIn = async (body: User) => {
+ const res = await fetch(`${import.meta.env.VITE_API_BASE}/auth/login`, {
+ method: "POST",
+ headers,
+ body: JSON.stringify(body),
+ });
+
+ if (res.status === 200) {
+ const json = await res.json();
+ localStorage.setItem("token", json.accessToken);
+ return json;
+ } else return false;
+};
+
+// Log-Out λ‘κ·Έμμ
+const logOut = async () => {
+ const res = await fetch(`${import.meta.env.VITE_API_BASE}/auth/logout`, {
+ method: "POST",
+ headers: {
+ ...headers,
+ Authorization: `Bearer ${localStorage.getItem("token")}`,
+ },
+ });
+ if (res.status === 200) {
+ await res.json();
+ window.localStorage.clear();
+ } else return false;
+};
+
+// λ‘κ·ΈμΈ μΈμ¦
+const authenticate = async () => {
+ const res = await fetch(`${import.meta.env.VITE_API_BASE}/auth/me`, {
+ method: "POST",
+ headers: {
+ ...headers,
+ Authorization: `Bearer ${localStorage.getItem("token")}`,
+ },
+ });
+ if (res.status === 200) {
+ const json = await res.json();
+ return json;
+ } else return false;
+};
+
+// Users μ¬μ©μ λͺ©λ‘
+const users = async () => {
+ const res = await fetch(`${import.meta.env.VITE_API_BASE}/auth/users`, {
+ method: "GET",
+ headers: {
+ ...headers,
+ masterKey: "true",
+ },
+ });
+ const data = await res.json();
+ return data;
+};
+
+// Add-Product μνλ±λ‘
+interface AddProductBody {
+ title: string;
+ price: number;
+ description: string;
+ tags?: string;
+ thumbnailBase64?: string;
+ photoBase64?: string;
+ discountRate?: number;
+}
+
+const addProduct = async (body: AddProductBody) => {
+ const res = await fetch(`${import.meta.env.VITE_API_BASE}/products`, {
+ method: "POST",
+ headers: {
+ "content-type": "application/json",
+ apikey: "KDT5_nREmPe9B",
+ username: "KDT5_Team9",
+ masterKey: "true",
+ },
+ body: JSON.stringify(body),
+ });
+ if (res.status === 200) {
+ const data = await res.json();
+ return data;
+ } else return false;
+};
+
+// Get-All-Products μ 체 μν μ‘°ν
+const getAllProducts = async () => {
+ const res = await fetch(`${import.meta.env.VITE_API_BASE}/products`, {
+ method: "GET",
+ headers: {
+ ...headers,
+ masterKey: "true",
+ },
+ });
+ const data = await res.json();
+ return data.map((data: any) => ({ ...data, isChecked: false }));
+};
+
+// Get-Product λ¨μΌ μν μ‘°ν
+const getProduct = async (id: string) => {
+ const res = await fetch(`${import.meta.env.VITE_API_BASE}/products/${id}`, {
+ method: "GET",
+ headers,
+ });
+ const data = await res.json();
+ return data;
+};
+
+// Edit-Product μν μμ
+interface EditProductBody {
+ title?: string;
+ price?: number;
+ description?: string;
+ tags?: string[];
+ thumbnailBase64?: string;
+ photoBase64?: string;
+ isSoldOut?: boolean;
+ discountRate?: number;
+}
+
+const editProduct = async (body: EditProductBody, id: string) => {
+ const res = await fetch(`${import.meta.env.VITE_API_BASE}/products/${id}`, {
+ method: "PUT",
+ headers: {
+ ...headers,
+ masterKey: "true",
+ },
+ body: JSON.stringify(body),
+ });
+ const data = await res.json();
+ return data;
+};
+
+// Delete-Product μν μμ
+const deleteProduct = async (id: string) => {
+ const res = await fetch(
+ `https://asia-northeast3-heropy-api.cloudfunctions.net/api/products/${id}`,
+ {
+ method: "DELETE",
+ headers: {
+ ...headers,
+ masterKey: "true",
+ },
+ }
+ );
+ if (res.status === 200) {
+ const data = await res.json();
+ return data;
+ } else return false;
+};
+
+// κ°μΈ μ 보 μμ
+interface EditInfoBody {
+ displayName?: string;
+ profileImgBase64?: string;
+ oldPassword?: string;
+ newPassword?: string;
+}
+
+const editInfo = async (body: EditInfoBody) => {
+ const res = await fetch(`${import.meta.env.VITE_API_BASE}/auth/user`, {
+ method: "PUT",
+ headers: {
+ ...headers,
+ Authorization: `Bearer ${localStorage.getItem("token")}`,
+ },
+ body: JSON.stringify(body),
+ });
+ if (res.status === 200) {
+ const data = await res.json();
+ return data;
+ } else return false;
+};
+
+// μ ν κ°λ₯ν μν λͺ©λ‘ μ‘°ν
+const getBankList = async () => {
+ const res = await fetch(`${import.meta.env.VITE_API_BASE}/account/banks`, {
+ method: "GET",
+ headers: {
+ ...headers,
+ Authorization: `Bearer ${localStorage.getItem("token")}`,
+ },
+ });
+ const data = await res.json();
+ return data;
+};
+
+// κ³μ’ λͺ©λ‘ λ° μμ‘ μ‘°ν
+const getAccountList = async () => {
+ const res = await fetch(`${import.meta.env.VITE_API_BASE}/account`, {
+ method: "GET",
+ headers: {
+ ...headers,
+ Authorization: `Bearer ${localStorage.getItem("token")}`,
+ },
+ });
+ const data = await res.json();
+ return data;
+};
+
+// κ³μ’ μ°κ²°
+interface linkAccountBody {
+ bankCode: string;
+ accountNumber: string;
+ phoneNumber: string;
+ signature: boolean;
+}
+
+const linkAccount = async (body: linkAccountBody) => {
+ const res = await fetch(`${import.meta.env.VITE_API_BASE}/account`, {
+ method: "POST",
+ headers: {
+ ...headers,
+ Authorization: `Bearer ${localStorage.getItem("token")}`,
+ },
+ body: JSON.stringify(body),
+ });
+ if (res.status === 200) {
+ const data = await res.json();
+ return data;
+ } else return false;
+};
+
+// κ³μ’ ν΄μ§
+interface DeleteAccountBody {
+ accountId: string;
+ signature: boolean;
+}
+
+const deleteAccount = async (body: DeleteAccountBody) => {
+ await fetch(`${import.meta.env.VITE_API_BASE}/account`, {
+ method: "DELETE",
+ headers: {
+ ...headers,
+ Authorization: `Bearer ${localStorage.getItem("token")}`,
+ },
+ body: JSON.stringify(body),
+ });
+};
+
+// μν κ±°λ μ μ² (ꡬ맀)
+
+interface BuyProductBody {
+ productId: string; // κ±°λν μ ν ID (νμ!)
+ accountId: string; // κ²°μ ν μ¬μ©μ κ³μ’ ID (νμ!)
+ reservation?: {
+ // μμ½ μ 보(μμ½ μμ€ν
μ μ¬μ©νλ κ²½μ°λ§ νμ)
+ start: string; // μμ½ μμ μκ°(ISO)
+ end: string; // μμ½ μ’
λ£ μκ°(ISO)
+ };
+}
+const buyProduct = async (body: BuyProductBody) => {
+ try {
+ const res = await fetch(`${import.meta.env.VITE_API_BASE}/products/buy`, {
+ method: "POST",
+ headers: {
+ ...headers,
+ Authorization: `Bearer ${localStorage.getItem("token")}`,
+ },
+ body: JSON.stringify(body),
+ });
+ if (res.status === 200) {
+ const data = await res.json();
+ return data;
+ } else return res.status;
+ } catch (error) {
+ alert("κ²°μ μ€ν¨νμμ΅λλ€.")
+ }
+};
+
+// μν κ±°λ μ·¨μ
+const cancelTransaction = async (body: TransactionsBody) => {
+ const res = await fetch(`${import.meta.env.VITE_API_BASE}/products/cancel`, {
+ method: "POST",
+ headers: {
+ ...headers,
+ Authorization: `Bearer ${localStorage.getItem("token")}`,
+ },
+ body: JSON.stringify(body),
+ });
+ if (res.status === 200) {
+ const data = await res.json();
+ return data;
+ } else return false;
+};
+
+// μν κ±°λ νμ
+const confirmedTransaction = async (body: TransactionsBody) => {
+ const res = await fetch(`${import.meta.env.VITE_API_BASE}/products/ok`, {
+ method: "POST",
+ headers: {
+ ...headers,
+ Authorization: `Bearer ${localStorage.getItem("token")}`,
+ },
+ body: JSON.stringify(body),
+ });
+
+ if (res.status === 200) {
+ const data = await res.json();
+ return data;
+ } else return false;
+};
+
+// μ 체 κ±°λ λ΄μ (μ¬μ©μ)
+const getAllTransactions = async () => {
+ const res = await fetch(
+ `${import.meta.env.VITE_API_BASE}/products/transactions/details`,
+ {
+ method: "GET",
+ headers: {
+ ...headers,
+ Authorization: `Bearer ${localStorage.getItem("token")}`,
+ },
+ }
+ );
+ if (res.status === 200) {
+ const data = await res.json();
+ return data;
+ } else return false;
+};
+
+// λ¨μΌ κ±°λ λ΄μ (μ¬μ©μ)
+const getTransaction = async (body: TransactionsBody) => {
+ const res = await fetch(
+ `${import.meta.env.VITE_API_BASE}/products/transactions/detail`,
+ {
+ method: "POST",
+ headers: {
+ ...headers,
+ Authorization: `Bearer ${localStorage.getItem("token")}`,
+ },
+ body: JSON.stringify(body),
+ }
+ );
+ const data = await res.json();
+ return data;
+};
+
+// μ 체 κ±°λ λ΄μ (κ΄λ¦¬μ)
+const adminAllTransactions = async () => {
+ const res = await fetch(
+ `${import.meta.env.VITE_API_BASE}/products/transactions/all`,
+ {
+ method: "GET",
+ headers: {
+ ...headers,
+ masterKey: "true",
+ },
+ }
+ );
+ const data = await res.json();
+ return data;
+};
+
+// κ±°λ λ΄μ κ΄λ¦¬ - μλ£, μ·¨μ, ν΄μ (κ΄λ¦¬μ)
+interface adminTransactionsBody {
+ isCanceled?: boolean;
+ done?: boolean;
+}
+
+const adminTransactions = async (id: string, body: adminTransactionsBody) => {
+ const res = await fetch(
+ `${import.meta.env.VITE_API_BASE}/products/transactions/${id}`,
+ {
+ method: "PUT",
+ headers: {
+ ...headers,
+ masterKey: "true",
+ },
+ body: JSON.stringify(body),
+ }
+ );
+ const data = await res.json();
+ return data;
+};
+
+export {
+ signUp,
+ logIn,
+ logOut,
+ authenticate,
+ users,
+ addProduct,
+ getAllProducts,
+ getProduct,
+ editProduct,
+ deleteProduct,
+ editInfo,
+ getBankList,
+ getAccountList,
+ linkAccount,
+ deleteAccount,
+ buyProduct,
+ cancelTransaction,
+ confirmedTransaction,
+ getAllTransactions,
+ getTransaction,
+ adminAllTransactions,
+ adminTransactions,
+};
diff --git a/src/components/.DS_Store b/src/components/.DS_Store
new file mode 100644
index 00000000..daf165e2
Binary files /dev/null and b/src/components/.DS_Store differ
diff --git a/src/components/Cart/CartList.tsx b/src/components/Cart/CartList.tsx
new file mode 100644
index 00000000..612b0989
--- /dev/null
+++ b/src/components/Cart/CartList.tsx
@@ -0,0 +1,105 @@
+import { useEffect } from "react";
+import { Link } from "react-router-dom";
+import { useSelector, useDispatch } from "react-redux";
+import { TfiClose } from "react-icons/tfi";
+import { convertPrice, priceBeforeDiscount } from "~/utils/convert";
+import styles from "~/styles/Cart/CartList.module.scss";
+
+const CartList = () => {
+ const cart = useSelector((state: any) => state.cart);
+ const selectedCart = useSelector((state: any) => state.selectedCart);
+ const myCart = [...cart];
+ const mySelectedCart = [...selectedCart];
+ const dispatch = useDispatch();
+
+ // μ₯λ°κ΅¬λ μμ
+ const deleteCartItemHandler = (i: number, item: any) => {
+ myCart.splice(i, 1);
+
+ dispatch({ type: "RETURN_CART", items: myCart });
+ dispatch({
+ type: "DELETE_SELECTED_CART",
+ items: mySelectedCart.filter(obj => obj.id !== item.id)
+ });
+ return cart;
+ };
+
+ const checkedCartItemHandler = (
+ e: React.ChangeEvent,
+ item: any
+ ) => {
+ e.target.checked
+ ? dispatch({ type: "CHECKED_SELECTED_CART", items: item })
+ : dispatch({
+ type: "DELETE_SELECTED_CART",
+ items: mySelectedCart.filter(obj => obj.id !== item.id)
+ });
+ };
+
+ useEffect(() => {
+ dispatch({ type: "REFRESH" });
+ }, []);
+
+ return (
+
+
+ {myCart.map((item, i: number) => (
+ -
+ checkedCartItemHandler(e, item)}
+ />
+
+
+
+
+
+
+
+ {item.title}
+
+
+ {item.quantity}κ°
+
+
+
+ {item.discountRate !== 0
+ ? `${convertPrice(item.price)}μ`
+ : `${convertPrice(
+ priceBeforeDiscount(item.price, item.discountRate)
+ )}μ`}
+
+
+ {item.discountRate !== 0
+ ? `${convertPrice(
+ priceBeforeDiscount(item.price, item.discountRate)
+ )}μ`
+ : ""}
+
+
+
+ {item.discountRate !== 0
+ ? convertPrice(item.price * item.quantity)
+ : convertPrice(
+ priceBeforeDiscount(item.price, item.discount) * item.quantity)
+ }μ
+
+
+ deleteCartItemHandler(i, item)} />
+
+
+ ))}
+
+
+ );
+};
+
+export default CartList;
diff --git a/src/components/MyPage/MyBankAccount/Account.tsx b/src/components/MyPage/MyBankAccount/Account.tsx
new file mode 100644
index 00000000..8f26786d
--- /dev/null
+++ b/src/components/MyPage/MyBankAccount/Account.tsx
@@ -0,0 +1,52 @@
+import { SlClose } from 'react-icons/sl';
+import { deleteAccount } from '~/api/requests';
+import { convertPrice } from '~/utils/convert';
+import styles from '~/styles/Mypage/Account.module.scss';
+
+interface AccountProps {
+ item: Bank;
+ watch: boolean;
+ setWatch: React.Dispatch>;
+}
+interface Bank {
+ id: string
+ bankName: string
+ bankCode: string
+ accountNumber: string
+ balance: number
+}
+
+const Account = ({
+ item, watch, setWatch
+}: AccountProps) => {
+
+ // κ³μ’ ν΄μ§
+ const deleteAcountHandler = async (id: string) => {
+ const body ={
+ accountId: id,
+ signature: true
+ }
+ try {
+ await deleteAccount(body);
+ alert("ν΄λΉ κ³μ’κ° μμ λμμ΅λλ€.")
+ setWatch(!watch)
+ } catch (error) {
+ alert('κ³μ’ ν΄μ§ μ€ν¨νμμ΅λλ€.')
+ }
+ }
+
+ return (
+
+
+
+
{item.bankName}
+
{item.accountNumber}
+
{`μμ‘: ${convertPrice(item.balance)}μ`}
+
+
deleteAcountHandler(item.id)} />
+
+
+ )
+}
+
+export default Account;
\ No newline at end of file
diff --git a/src/components/MyPage/MyBankAccount/AccountModal.tsx b/src/components/MyPage/MyBankAccount/AccountModal.tsx
new file mode 100644
index 00000000..f0fb6a08
--- /dev/null
+++ b/src/components/MyPage/MyBankAccount/AccountModal.tsx
@@ -0,0 +1,171 @@
+import { useState } from 'react';
+import { linkAccount } from '~/api/requests';
+import Loading from '~/components/common/Loading';
+import styles from '~/styles/Mypage/AccountModal.module.scss';
+
+interface AccountModalProps {
+ bankList: Bank[];
+ watch: boolean;
+ setWatch: React.Dispatch>
+ showModal: boolean;
+ setShowModal: React.Dispatch>
+
+}
+
+interface Bank { // μ ν κ°λ₯ν μν μ 보
+ name: string // μν μ΄λ¦
+ code: string // μν μ½λ
+ digits: number[] // μν κ³μ’ μλ¦Ώμ
+ disabled: boolean // μ¬μ©μκ° μΆκ°ν κ³μ’ μ¬λΆ
+}
+
+interface InputState {
+ input0: string;
+ input1: string;
+ input2: string;
+ input3: string;
+ phone0: string;
+ phone1: string;
+ phone2: string;
+}
+
+const AccountModal = ({
+ bankList,
+ watch,
+ setWatch,
+ showModal,
+ setShowModal
+}: AccountModalProps) => {
+ const [bankCode, setBankCode] = useState('')
+ const [isAgree, setIsAgree] = useState(false)
+ const [bankIDX, setBankIDX] = useState(0)
+ const [isLoading, setIsLoading] = useState(false)
+ const [accountInput, setAccountInput] = useState({
+ input0: '',
+ input1: '',
+ input2: '',
+ input3: '',
+ phone0: '',
+ phone1: '',
+ phone2: ''
+ })
+
+ // Input onChange Handler
+ const accountOnChangeHandler = (e: React.ChangeEvent) => {
+ const { value, name } = e.target;
+ setAccountInput({
+ ...accountInput,
+ [name]: value
+ })
+}
+
+ // κ³μ’ λ±λ‘
+ const enrollAccount = async (e: React.MouseEvent) => {
+ e.preventDefault();
+ setIsLoading(true);
+ const body = {
+ bankCode,
+ accountNumber: accountInput.input0 + accountInput.input1 + accountInput.input2+ accountInput.input3,
+ phoneNumber: accountInput.phone0+ accountInput.phone1 + accountInput.phone2,
+ signature: isAgree,
+ }
+ const res = await linkAccount(body);
+ if (res) {
+ console.log('κ³μ’ μ°κ²° μ 보', res);
+ alert('κ³μ’κ° μ°κ²°λμμ΅λλ€.');
+ setShowModal(!showModal);
+ setWatch(!watch)
+ } else alert('κ³μ’ μ 보λ₯Ό λ€μ νμΈν΄ μ£ΌμΈμ.')
+ setIsLoading(false);
+ }
+
+ return (
+ <>
+ {isLoading ? : null}
+
+ >
+
+ )
+}
+
+export default AccountModal
diff --git a/src/components/Shop/ProductItem.tsx b/src/components/Shop/ProductItem.tsx
new file mode 100644
index 00000000..0fc8be0f
--- /dev/null
+++ b/src/components/Shop/ProductItem.tsx
@@ -0,0 +1,35 @@
+import { Link } from "react-router-dom";
+import { priceBeforeDiscount, convertPrice } from "~/utils/convert";
+import styles from "~/styles/Shop/ProductItem.module.scss";
+
+
+const ProductItem = ({ product }: any) => {
+ return (
+
+
+
+
+
+
+ {product.title}
+
+
+
+ {product.discountRate ? `${product.discountRate}%` : ""}
+
+
+ β©{convertPrice((product.price))}
+
+
+ {product.discountRate
+ ? `β©${convertPrice(priceBeforeDiscount(product.price, product.discountRate))}`
+ : ""
+ }
+
+
+
+
+ );
+};
+
+export default ProductItem;
diff --git a/src/components/common/Loading.tsx b/src/components/common/Loading.tsx
new file mode 100644
index 00000000..264e214a
--- /dev/null
+++ b/src/components/common/Loading.tsx
@@ -0,0 +1,21 @@
+import { GiHouse } from 'react-icons/gi';
+import { LuCar } from 'react-icons/lu';
+import styles from '~/styles/Loading.module.scss';
+
+const Loading = () => {
+ return (
+
+
+ )
+}
+
+export default Loading;
\ No newline at end of file
diff --git a/src/components/common/Select.tsx b/src/components/common/Select.tsx
new file mode 100644
index 00000000..aa361337
--- /dev/null
+++ b/src/components/common/Select.tsx
@@ -0,0 +1,29 @@
+interface SelectProps {
+ name: string;
+ options: { name: string, value: string }[];
+ onChange: (event: React.ChangeEvent) => void;
+ value: any;
+}
+
+const Select = ({
+ options,
+ onChange,
+ value,
+ name
+}: SelectProps) => {
+ return (
+
+ )
+}
+
+export default Select;
\ No newline at end of file
diff --git a/src/components/common/SubNav.tsx b/src/components/common/SubNav.tsx
new file mode 100644
index 00000000..246df62c
--- /dev/null
+++ b/src/components/common/SubNav.tsx
@@ -0,0 +1,33 @@
+import styles from "~/styles/SubNav.module.scss";
+
+interface SubNavProps {
+ subNav: string[]
+ setCategory: React.Dispatch>
+}
+
+const SubNav = ({ subNav, setCategory }: SubNavProps) => {
+
+ return (
+ <>
+
+
+ {subNav.map((category: string) => (
+
{
+ setCategory(category)}
+ }
+ >
+
+ {category}
+
+
+ ))}
+
+
+ >
+ );
+};
+
+
+export default SubNav;
diff --git a/src/components/common/TheFooter.tsx b/src/components/common/TheFooter.tsx
new file mode 100644
index 00000000..a2cf5023
--- /dev/null
+++ b/src/components/common/TheFooter.tsx
@@ -0,0 +1,54 @@
+import styles from '~/styles/TheFooter.module.scss';
+
+const TheFooter = () => {
+ return (
+ <>
+
+ >
+ )
+}
+
+export default TheFooter;
\ No newline at end of file
diff --git a/src/components/common/TheHeader.tsx b/src/components/common/TheHeader.tsx
new file mode 100644
index 00000000..76020217
--- /dev/null
+++ b/src/components/common/TheHeader.tsx
@@ -0,0 +1,103 @@
+import { useState } from "react";
+import { useSelector, useDispatch } from "react-redux";
+import { NavLink, useNavigate } from "react-router-dom";
+import { AiOutlineSearch } from "react-icons/ai";
+import { FaShoppingBag, FaUserAlt } from "react-icons/fa";
+import { logOut } from "~/api/requests";
+import TheSearchBar from "~/components/common/TheSearchBar";
+import styles from "~/styles/TheHeader.module.scss";
+
+const TheHeader = () => {
+ const [search, setSearch] = useState("");
+ const [searchIsClicked, setSearchIsClicked] = useState(false);
+
+ const logout = useSelector((state: any) => state.logout);
+ const dispatch = useDispatch();
+ const navigate = useNavigate();
+
+ // λ‘κ·Έμμ
+ const logOutHandler = async (e: React.MouseEvent) => {
+ e.preventDefault();
+ dispatch({ type: "LOGOUT", state: false });
+ dispatch({ type: "RETURN", account: {} });
+ try {
+ await logOut();
+ alert("λ‘κ·Έμμ μλ£λμμ΅λλ€.")
+ navigate("/sweethome")
+ } catch (error: any) {
+ alert(error.message);
+ }
+ };
+
+ return (
+
+
+
+ SWEET HOME
+
+
+
+ -
+
+ isActive ? styles.active : `menu`
+ }>
+ ABOUT
+
+
+ -
+ (isActive ? styles.active : "")}>
+ SHOP
+
+
+
+
+
+
+ {logout ? (
+
+ Logout
+
+ ) : (
+
+
+ Login
+
+
+ Sign-Up
+
+
+ )}
+
+
+
+
+
+
+
+
+
+ {searchIsClicked && (
+
) => setSearch(e.target.value)}
+ />
+ )}
+ setSearchIsClicked(!searchIsClicked)}
+ />
+
+
+
+
+
+ );
+};
+export default TheHeader;
diff --git a/src/components/common/TheModal.tsx b/src/components/common/TheModal.tsx
new file mode 100644
index 00000000..8b452922
--- /dev/null
+++ b/src/components/common/TheModal.tsx
@@ -0,0 +1,200 @@
+import { useState } from "react";
+import { TfiClose } from "react-icons/tfi";
+import { editProduct } from "~/api/requests";
+import { SELECT_TAGS } from "~/constants";
+import Loading from "~/components/common/Loading";
+import Select from "~/components/common/Select";
+import styles from "~/styles/TheModal.module.scss";
+
+interface PropsType {
+ setModalOpen: React.Dispatch>;
+ title: string;
+ allProducts: Product[];
+ setAllProducts: React.Dispatch>
+ productId: string;
+ watch: boolean;
+ setWatch: React.Dispatch>
+ productIDX: number;
+}
+
+interface Product {
+ id: string
+ title: string
+ price: number
+ description: string
+ tags: string[]
+ thumbnail: string
+ isSoldOut: boolean
+ discountRate: number
+}
+
+const TheModal = ({
+ setModalOpen,
+ title,
+ allProducts,
+ setAllProducts,
+ productId,
+ watch,
+ setWatch,
+ productIDX,
+}: PropsType) => {
+ const [isChecked, setIsChecked] = useState(false);
+ const [productThumb] = useState('');
+ const [isLoading, setIsLoading] = useState(false);
+ const [editInfo, setEditInfo] = useState({
+ title: allProducts[productIDX].title,
+ price: allProducts[productIDX].price,
+ description: allProducts[productIDX].description,
+ tags: allProducts[productIDX].tags,
+ thumbnail: productThumb,
+ discountRate: allProducts[productIDX].discountRate,
+ });
+
+ const closeModal = () => {
+ setModalOpen(false);
+ };
+
+ // μΈλ€μΌ base64 μΈμ½λ©
+ // const thumbBase64Handler = (e: React.ChangeEvent) => {
+ // const target: any = e.target as HTMLInputElement;
+ // const file = target.files[0];
+ // const reader = new FileReader();
+ // reader.readAsDataURL(file);
+
+ // return new Promise((resolve) => {
+ // reader.onload = () => {
+ // setProductThumb(reader.result as string);
+ // resolve();
+ // };
+ // });
+ // };
+
+ const onChangeHandler = (
+ e:
+ | React.ChangeEvent
+ | React.ChangeEvent
+ ) => {
+ const { value, name } = e.target;
+ setEditInfo({
+ ...editInfo,
+ [name]: value,
+ });
+ };
+
+ // μν μμ
+ const editProductHandler = async (e: React.MouseEvent, id: string) => {
+ e.preventDefault();
+ setIsLoading(true);
+ if (editInfo.title.trim() === "") {
+ alert("μνμ΄λ¦, μννκ·Έλ νμμ
λλ€.");
+ return;
+ }
+ if (editInfo.discountRate < 0 || editInfo.discountRate >= 100) {
+ alert("ν μΈμ¨μ 0 ~ 99λ₯Ό μ
λ ₯νμΈμ.");
+ return;
+ }
+
+ const body = {
+ title: editInfo.title,
+ price: editInfo.price,
+ description: editInfo.description,
+ tags: editInfo.tags,
+ thumbnail: productThumb,
+ isSoldOut: isChecked,
+ discountRate: editInfo.discountRate,
+ };
+
+ try {
+ const res = await editProduct(body, id);
+ setAllProducts([...allProducts, res]);
+ setWatch(!watch);
+ setModalOpen(false);
+ } catch (error: any) {
+ alert(error.message);
+ }
+ setIsLoading(false);
+ };
+
+ return (
+ <>
+ {isLoading ? : null}
+
+ >
+ );
+};
+
+export default TheModal;
diff --git a/src/components/common/TheSearchBar.tsx b/src/components/common/TheSearchBar.tsx
new file mode 100644
index 00000000..62a79c19
--- /dev/null
+++ b/src/components/common/TheSearchBar.tsx
@@ -0,0 +1,79 @@
+import { useEffect, useState } from "react";
+import { useNavigate } from "react-router-dom";
+import { getAllProducts } from "~/api/requests";
+import Loading from "~/components/common/Loading";
+import styles from "~/styles/TheSearchBar.module.scss";
+
+const TheSearchBar = ({ search, onChange }: any) => {
+ const [allProducts, setAllProducts] = useState([]);
+ const [isLoading, setIsLoading] = useState(false);
+
+ // μ 체 μν μ‘°ν
+ const getAllProductsHandler = async () => {
+ setIsLoading(true);
+ try {
+ const res = await getAllProducts();
+ setAllProducts(res);
+ } catch (error: any) {
+ alert(error.message);
+ }
+ setIsLoading(false);
+ };
+
+ const navigate = useNavigate();
+
+ useEffect(() => {
+ getAllProductsHandler();
+ }, []);
+
+ interface Product {
+ id: string;
+ title: string;
+ price: number;
+ description: string;
+ tags: string[];
+ thumbnail: string | null;
+ isSoldOut: boolean;
+ discountRate: number;
+ }
+
+ return (
+ <>
+ {isLoading ? : null}
+
+
+ {}
+
+ {allProducts.map((product:Product, index:number) =>
+ search === "" ? (
+
+ ) : product.title
+ .replace(" ", "")
+ .toLocaleLowerCase()
+ .includes(search?.toLocaleLowerCase().replace(" ", "")) ? (
+
{
+ navigate(`/sweethome/shop/${product.id}`, { replace: true });
+ }}>
+ {product.title}
+
+ ) : (
+
+ )
+ )}
+
+
+ >
+ );
+};
+export default TheSearchBar;
diff --git a/src/constants/index.ts b/src/constants/index.ts
new file mode 100644
index 00000000..bdb7f137
--- /dev/null
+++ b/src/constants/index.ts
@@ -0,0 +1,6 @@
+export const SELECT_TAGS = [
+ {name: 'νκ·Έλ₯Ό μ νν΄μ£ΌμΈμ.', value: ''},
+ {name: 'FURNITURE', value: 'FURNITURE'},
+ {name: 'KITCHEN', value: 'KITCHEN'},
+ {name: 'BEDROOM', value: 'BEDROOM'}
+]
\ No newline at end of file
diff --git a/src/main.tsx b/src/main.tsx
new file mode 100644
index 00000000..559e6a39
--- /dev/null
+++ b/src/main.tsx
@@ -0,0 +1,16 @@
+import ReactDOM from "react-dom/client";
+import router from "./routes/index.tsx";
+import { RouterProvider } from "react-router-dom";
+import { store } from "~/store/index.ts";
+import { Provider } from "react-redux";
+import { persistStore } from "redux-persist";
+import { PersistGate } from "redux-persist/integration/react";
+
+const persistor = persistStore(store);
+ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
+
+
+
+
+
+);
\ No newline at end of file
diff --git a/src/reducers/account.ts b/src/reducers/account.ts
new file mode 100644
index 00000000..1ddf3587
--- /dev/null
+++ b/src/reducers/account.ts
@@ -0,0 +1,10 @@
+const account = (state = {}, action: any) => {
+ switch (action.type) {
+ case "GET_ACCOUNT_LIST":
+ return action.accountList;
+ default:
+ return state;
+ }
+};
+
+export default account;
diff --git a/src/reducers/buyItem.ts b/src/reducers/buyItem.ts
new file mode 100644
index 00000000..81b772e0
--- /dev/null
+++ b/src/reducers/buyItem.ts
@@ -0,0 +1,10 @@
+const buyItem = (state = {}, action: any) => {
+ switch (action.type) {
+ case "GET_BUYITEM":
+ return action.payload
+ default:
+ return state;
+ }
+};
+
+export default buyItem
\ No newline at end of file
diff --git a/src/reducers/cart.ts b/src/reducers/cart.ts
new file mode 100644
index 00000000..1174a4b8
--- /dev/null
+++ b/src/reducers/cart.ts
@@ -0,0 +1,15 @@
+const cart = (state = [], action: any) => {
+ switch (action.type) {
+ case "RETURN_CART":
+ return action.items;
+ case "DELETE_ITEM":
+ let num = state.findIndex((obj:any)=>{
+ return obj.id === action.items
+ })
+ return state.splice(num,1)
+ default:
+ return state;
+ }
+};
+
+export default cart;
\ No newline at end of file
diff --git a/src/reducers/index.ts b/src/reducers/index.ts
new file mode 100644
index 00000000..c258646f
--- /dev/null
+++ b/src/reducers/index.ts
@@ -0,0 +1,28 @@
+import { combineReducers } from "redux";
+import { persistReducer } from "redux-persist";
+import info from "./info";
+import cart from "./cart";
+import logout from "./logout";
+import selectedCart from "./selectedCart";
+import account from "./account";
+import user from "./user"
+import buyItem from "./buyItem"
+import storage from "redux-persist/lib/storage";
+
+const persistConfig = {
+ key: "root",
+ storage,
+ whiteList: ["info", "cart", "logout", "selectedCart", "account","user","buyItem"]
+};
+
+const rootReducer = combineReducers({
+ info,
+ cart,
+ logout,
+ selectedCart,
+ account,
+ user,
+ buyItem
+});
+
+export default persistReducer(persistConfig, rootReducer);
diff --git a/src/reducers/info.ts b/src/reducers/info.ts
new file mode 100644
index 00000000..ac5a2b85
--- /dev/null
+++ b/src/reducers/info.ts
@@ -0,0 +1,10 @@
+const info = (state = 0, action: any) => {
+ switch (action.type) {
+ case "RETURN":
+ return action.account;
+ default:
+ return state;
+ }
+};
+
+export default info;
diff --git a/src/reducers/logout.ts b/src/reducers/logout.ts
new file mode 100644
index 00000000..d4a9ddfe
--- /dev/null
+++ b/src/reducers/logout.ts
@@ -0,0 +1,10 @@
+const logout = (state = true, action: any) => {
+ switch (action.type) {
+ case "LOGOUT":
+ return action.state;
+ default:
+ return state;
+ }
+};
+
+export default logout;
diff --git a/src/reducers/selectedCart.ts b/src/reducers/selectedCart.ts
new file mode 100644
index 00000000..cf97a0a7
--- /dev/null
+++ b/src/reducers/selectedCart.ts
@@ -0,0 +1,15 @@
+const selectedCart = (state = [], action: any) => {
+ switch (action.type) {
+ case "CHECKED_SELECTED_CART":
+ action.items.isChecked = true;
+ return action.items.isChecked ? [...state, action.items] : [...state];
+ case "DELETE_SELECTED_CART":
+ return action.items;
+ case "REFRESH":
+ return []
+ default:
+ return state
+ }
+};
+
+export default selectedCart;
diff --git a/src/reducers/user.ts b/src/reducers/user.ts
new file mode 100644
index 00000000..4021ab41
--- /dev/null
+++ b/src/reducers/user.ts
@@ -0,0 +1,10 @@
+const user = (state = {}, action: any) => {
+ switch (action.type) {
+ case "RETURN_USER":
+ return action.payload
+ default:
+ return state;
+ }
+};
+
+export default user;
diff --git a/src/routes/.DS_Store b/src/routes/.DS_Store
new file mode 100644
index 00000000..818b3558
Binary files /dev/null and b/src/routes/.DS_Store differ
diff --git a/src/routes/About/About.tsx b/src/routes/About/About.tsx
new file mode 100644
index 00000000..bf992b8d
--- /dev/null
+++ b/src/routes/About/About.tsx
@@ -0,0 +1,26 @@
+import about from '/public/assets/about/about.jpeg';
+import styles from '~/styles/About/About.module.scss';
+
+const About = () => {
+ return (
+
+
+
+
+
+
+
+ SWEET HOME
+
+
+ λΉμ μκ² μ§μ΄λ μ΄λ€ μλ―ΈμΈκ°μ?
+ μΈμ , μ΄λμλ μ§μ κ°κ³ μΆκ² λ§λ€ μ μλ 첫 κ±Έμ
+ μ§ κ°κ΅¬μΆμ΄μμ μμν΄ λ³΄μΈμ.
+
+
+
+
+ );
+};
+
+export default About;
\ No newline at end of file
diff --git a/src/routes/Admin/Admin.tsx b/src/routes/Admin/Admin.tsx
new file mode 100644
index 00000000..8b13f637
--- /dev/null
+++ b/src/routes/Admin/Admin.tsx
@@ -0,0 +1,50 @@
+import { useState, useEffect } from 'react'
+import { useNavigate } from 'react-router-dom'
+import { useSelector } from 'react-redux'
+import AdminUser from '~/routes/Admin/AdminUser'
+import AdminProduct from '~/routes/Admin/AdminProduct'
+import AdminOrder from '~/routes/Admin/AdminOrder'
+import SubNav from '~/components/common/SubNav'
+import styles from '~/styles/Admin/Admin.module.scss';
+
+const Admin = () => {
+ const subNav: string[] = ["μ¬μ©μ κ΄λ¦¬", "μν κ΄λ¦¬", "μ£Όλ¬Έ λ΄μ κ΄λ¦¬"];
+ const [category, setCategory] = useState("");
+
+ const navigate = useNavigate();
+
+ const user = useSelector((state: any) => state.user)
+
+ useEffect(() => {
+ if (!localStorage.getItem('token')) {
+ alert('κ΄λ¦¬μ μ μ© νμ΄μ§μ
λλ€! βοΈ');
+ navigate('/sweethome');
+ }
+ },[])
+
+ return (
+ <>
+ {localStorage.getItem('token') && user.email === `${import.meta.env.VITE_ADMIN_ACCOUNT}` ?
+
+
+
+
+
+ {
+ (category === "μ¬μ©μ κ΄λ¦¬" || category === "")
+ ?
+ : category === "μν κ΄λ¦¬"
+ ?
+ :
+ }
+
+
+
+
+ : κ΄λ¦¬μ νμ΄μ§μ
λλ€. κ΄λ¦¬μ κ³μ μΌλ‘ λ‘κ·ΈμΈ ν΄μ£ΌμΈμ.
+ }
+ >
+ )
+}
+
+export default Admin;
\ No newline at end of file
diff --git a/src/routes/Admin/AdminOrder.tsx b/src/routes/Admin/AdminOrder.tsx
new file mode 100644
index 00000000..821d2f4e
--- /dev/null
+++ b/src/routes/Admin/AdminOrder.tsx
@@ -0,0 +1,161 @@
+import { useEffect, useState } from "react";
+import { adminAllTransactions, adminTransactions } from "~/api/requests";
+import { convertDate, sortDate, convertPrice } from "~/utils/convert";
+import Loading from "~/components/common/Loading";
+import styles from "~/styles/admin/AdminOrder.module.scss";
+
+const AdminOrder = () => {
+ const [allList, setAllList] = useState([]);
+ const [isCanceled, setIsCanceled] = useState(false);
+ const [isDone, setIsDone] = useState(false);
+ const [isLoading, setIsLoading] = useState(false);
+
+ useEffect(() =>{
+ getAllTransactions();
+ },[])
+
+ // μ 체 κ±°λ λ΄μ μ‘°ν
+ const getAllTransactions = async () => {
+ setIsLoading(true);
+ try {
+ const res = await adminAllTransactions();
+ setAllList(res.sort((a: any, b: any) => sortDate(b.timePaid) - sortDate(a.timePaid)));
+ } catch (error: any) {
+ alert(error.message);
+ }
+ setIsLoading(false);
+ }
+
+ // κ±°λ μλ£ λ° μ·¨μ
+ const adminTransactionsHandler = async (e: React.MouseEvent, detailId: string) => {
+ e.preventDefault();
+ const id = e.currentTarget.id;
+ try {
+ if (id === 'canceled') {
+ await adminTransactions(detailId, { isCanceled: !isCanceled });
+ setIsCanceled(!isCanceled);
+ } else {
+ await adminTransactions(detailId, { done: !isDone });
+ setIsDone(!isDone);
+ }
+ } catch (error: any) {
+ alert(error.message);
+ }
+ }
+
+ 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
+ }
+
+ return (
+ <>
+ {isLoading ? : null}
+
+
+
+
μ 체 κ±°λ λ΄μ κ΄λ¦¬
+
+
+
+
+
NO.
+
κ±°λ λ΄μ ID
+
κ±°λμ μ 보
+
κ³μ’ μ 보
+
μ ν μ 보
+
κ±°λ μκ°
+
μ·¨μ μ¬λΆ
+
μλ£ μ¬λΆ
+
λΉκ³
+
+
+
+
+
+ {allList.map((list: TransactionDetail, i) => (
+ -
+
{i + 1}
+
+ {list.detailId.slice(0, 8)}
+
+
+
{list.user.displayName}
+
{list.user.email}
+
+
+
{list.account.bankName}
+
{list.account.accountNumber}
+
+
+
{list.product.title}
+
{convertPrice(list.product.price)}
+
{list.product.tags}
+
+
+
{convertDate(list.timePaid)}
+
+
+
{list.isCanceled ? "β
" : "β"}
+
+
+ {list.done ? "β
" : "β"}
+
+
+ {(list.isCanceled || list.done)
+ ? "π "
+ :
+ adminTransactionsHandler(e, list.detailId)}
+ />
+ }
+ {(list.done || list.isCanceled)
+ ? null
+ :
+ adminTransactionsHandler(e, list.detailId)}
+ disabled={list.done ? true : false}/>
+ }
+
+
+ ))}
+
+
+
+
+ >
+ )
+}
+
+export default AdminOrder;
\ No newline at end of file
diff --git a/src/routes/Admin/AdminProduct.tsx b/src/routes/Admin/AdminProduct.tsx
new file mode 100644
index 00000000..5ef72f2f
--- /dev/null
+++ b/src/routes/Admin/AdminProduct.tsx
@@ -0,0 +1,349 @@
+import { useState, useEffect } from "react";
+import { TiDeleteOutline } from "react-icons/ti";
+import { BsPencilSquare } from "react-icons/bs";
+import { addProduct, getAllProducts, deleteProduct } from "~/api/requests";
+import { SELECT_TAGS } from "~/constants";
+import TheModal from "~/components/common/TheModal";
+import Select from "~/components/common/Select";
+import Loading from "~/components/common/Loading";
+import styles from "~/styles/Admin/AdminProduct.module.scss";
+
+type AllProduct = Product[];
+
+interface Product {
+ id: string;
+ title: string;
+ price: number;
+ description: string;
+ tags: string[];
+ thumbnail: string;
+ isSoldOut: boolean;
+ discountRate: number;
+}
+
+interface AddProductBody {
+ title: string;
+ price: number;
+ description: string;
+ tags?: string;
+ thumbnailBase64?: string;
+ photoBase64?: string;
+ discountRate?: number;
+ isSoldOut?: boolean;
+}
+
+const AdminProduct = () => {
+ const [allProducts, setAllProducts] = useState([]);
+ const [productThumb, setProductThumb] = useState("");
+ const [productPhoto, setProductPhoto] = useState("");
+ const [productId, setProductId] = useState("");
+ const [product, setProduct] = useState({
+ title: "",
+ price: "",
+ description: "",
+ tags: "",
+ discountRate: ""
+ });
+
+ const [isLoading, setIsLoading] = useState(false);
+ const [isChecked, setIsChecked] = useState(false);
+ const [modalOpen, setModalOpen] = useState(false);
+ const [watch, setWatch] = useState(false);
+ const [productIDX, setProductIDX] = useState(0);
+
+ // μν μμ λ²νΌ ν΄λ¦ μ λͺ¨λ¬μ°½ μ€ν
+ const showModal = (id: string) => {
+ setModalOpen(true);
+ setProductId(id);
+ };
+
+ useEffect(() => {
+ getAllProductsHandler();
+ }, [watch]);
+
+ const tableHead = [
+ "NO",
+ "μννκ·Έ",
+ "μνμ΄λ¦",
+ "μνκ°κ²©",
+ "ν μΈμ¨",
+ "νμ μ¬λΆ"
+ ];
+
+ // μ 체 μν λͺ©λ‘ μ‘°ν
+ const getAllProductsHandler = async () => {
+ setIsLoading(true);
+ try {
+ const res = await getAllProducts();
+ setAllProducts(res);
+ } catch (error) {
+ alert("μν μΆλ ₯ μ€ν¨!");
+ }
+ setIsLoading(false);
+ };
+
+ // μν μμ input νΈλ€λ¬
+ const onInputChangeHandler = (
+ e:
+ | React.ChangeEvent
+ | React.ChangeEvent
+ ) => {
+ const { value, name } = e.target;
+ setProduct({
+ ...product,
+ [name]: value
+ });
+ };
+
+ // μν λ±λ‘
+ const addProductHandler = async () => {
+ const body: AddProductBody = {
+ title: product.title,
+ price: Number(product.price),
+ description: product.description,
+ tags: product.tags,
+ thumbnailBase64: productThumb,
+ photoBase64: productPhoto,
+ discountRate: Number(product.discountRate),
+ isSoldOut: isChecked
+ };
+
+ try {
+ setIsLoading(true);
+ await addProduct(body);
+ setWatch(!watch);
+ alert("μν λ±λ‘ μ±κ³΅!");
+ setProduct({
+ title: "",
+ price: "",
+ description: "",
+ tags: "",
+ discountRate: ""
+ });
+ setProductThumb("");
+ setProductPhoto("");
+ } catch (error) {
+ alert("μν λ±λ‘ μ€ν¨!");
+ }
+ setIsLoading(false);
+ };
+
+ // μΈλ€μΌ base64 μΈμ½λ©
+ const thumbBase64Handler = (e: React.ChangeEvent) => {
+ const target: any = e.target as HTMLInputElement;
+ const file = target.files[0];
+ const reader = new FileReader();
+ reader.readAsDataURL(file);
+
+ return new Promise(resolve => {
+ reader.onload = () => {
+ setProductThumb(reader.result as string);
+ resolve();
+ };
+ });
+ };
+
+ // μμΈμ¬μ§ base64 μΈμ½λ©
+ const photoBase64Handler = (e: React.ChangeEvent) => {
+ const target: any = e.target as HTMLInputElement;
+ const file = target.files[0];
+ const reader = new FileReader();
+ reader.readAsDataURL(file);
+ return new Promise(resolve => {
+ reader.onload = () => {
+ setProductPhoto(reader.result as string);
+ resolve();
+ };
+ });
+ };
+
+ // μν μμ
+ const deleteProductHandler = async (id: any) => {
+ try {
+ const res = await deleteProduct(id);
+ if (res) {
+ const updateProduct = allProducts.filter(product => product.id !== id);
+ setAllProducts(updateProduct);
+ } else {
+ alert("μν μμ μ€ν¨νμμ΅λλ€.");
+ }
+ } catch (error) {
+ alert("μν μμ μ€ν¨νμμ΅λλ€.");
+ }
+ };
+
+ return (
+ <>
+ {isLoading ? : null}
+
+
+
+
+
+
+
+
+
+
+
+ {tableHead.map(item => (
+ {item} |
+ ))}
+
+
+
+ {allProducts.map((product, i) => (
+
+ {i + 1} |
+ {product.tags} |
+ {product.title} |
+ {product.price} |
+ {product.discountRate} |
+ {product.isSoldOut ? "νμ " : ""} |
+
+ {
+ showModal(product.id);
+ setProductIDX(i);
+ }}
+ />
+ deleteProductHandler(product.id)}
+ />
+ {modalOpen && (
+
+ )}
+
+
+ ))}
+
+
+
+
+
+
+
+ >
+ );
+};
+
+export default AdminProduct;
diff --git a/src/routes/Admin/AdminUser.tsx b/src/routes/Admin/AdminUser.tsx
new file mode 100644
index 00000000..6c752947
--- /dev/null
+++ b/src/routes/Admin/AdminUser.tsx
@@ -0,0 +1,62 @@
+import { useState, useEffect } from "react";
+import { users } from "~/api/requests";
+import styles from "~/styles/Admin/AdminUser.module.scss";
+
+const AdminUser = () => {
+ interface User {
+ email: string
+ displayName: string
+ profileImg: string
+ }
+
+ const [allUsers, setAllUsers] = useState([]);
+ const tableHead = ["NO", "μ΄λ¦", "μ΄λ©μΌ"];
+
+ useEffect(() => {
+ getUsers();
+ }, []);
+
+ // μ¬μ©μ λͺ©λ‘ μ‘°ν
+ const getUsers = async () => {
+ try {
+ const res = await users();
+ setAllUsers(res);
+ } catch (error) {
+ alert("μ¬μ©μ λͺ©λ‘ μ‘°ν μ€ν¨!")
+ }
+ };
+
+ return (
+ <>
+
+
+
+
μ¬μ©μ κ΄λ¦¬
+
+
+
+
+
+ {tableHead.map(item => (
+ {item} |
+ ))}
+
+
+
+ {allUsers.map((user: User, i) => (
+
+ {i + 1} |
+ {user.displayName} |
+ {user.email} |
+
+ ))}
+
+
+
+
+
+ >
+ );
+};
+
+export default AdminUser;
diff --git a/src/routes/Buy/Buy.tsx b/src/routes/Buy/Buy.tsx
new file mode 100644
index 00000000..115a03cf
--- /dev/null
+++ b/src/routes/Buy/Buy.tsx
@@ -0,0 +1,287 @@
+import { useEffect, useState } from "react";
+import { useLocation, useNavigate } from "react-router";
+import { Link } from "react-router-dom";
+import { useSelector, useDispatch } from "react-redux";
+import { FaEquals, FaPlus } from "react-icons/fa";
+import { buyProduct, getAccountList } from "~/api/requests";
+import { convertPrice, priceBeforeDiscount } from "~/utils/convert";
+import styles from "~/styles/Buy/Buy.module.scss";
+
+interface Bank {
+ id: string;
+ bankName: string;
+ bankCode: string;
+ accountNumber: string;
+ balance: number;
+}
+
+const Buy = () => {
+ const user = useSelector((state: any) => state.user);
+ const cart = useSelector((state: any) => state.cart);
+ const dispatch = useDispatch();
+ const navigate = useNavigate();
+
+ const [accountChecked, setAccountChecked] = useState(true);
+ const [bankChecked, setBankChecked] = useState(false);
+ const [accountId, setAccountId] = useState("");
+ const [bankName, setBankName] = useState("")
+ const [accountList, setAccountList] = useState([]);
+ const [isActive, setIsActive] = useState(false);
+
+ useEffect(() => {
+ getAccountData();
+ }, []);
+
+ const getAccountData = async () => {
+ try {
+ const res = await getAccountList();
+ setAccountList(res.accounts);
+ } catch (err) {
+ alert("κ³μ’μ 보 μ€ν¨νμμ΅λλ€.");
+ }
+ };
+
+ // λΌλμ€ λ²νΌ νΈλ€λ¬
+ const radioBtnHandler = () => {
+ setAccountChecked(!accountChecked);
+ setBankChecked(!bankChecked);
+ };
+ const location = useLocation();
+ const order = [...location.state];
+
+ const totalQuantity = order.reduce((acc, cur) => (acc += cur.quantity), 0);
+ const totalPrice = order.reduce(
+ (acc, cur) => (acc += cur.price * cur.quantity),
+ 0
+ );
+
+ // μν κ±°λ μ μ² νΈλ€λ¬
+ interface orderApplyBody {
+ productId: string;
+ accountId: string;
+ reservation?: {
+ start: string;
+ end: string;
+ };
+ }
+
+ const orderApplyHandler = async (
+ e: React.MouseEvent,
+ order: any[],
+ accountId: string
+ ) => {
+ e.preventDefault();
+ try {
+ order.map(async (item: any) => {
+ const body: orderApplyBody = {
+ productId: item.id,
+ accountId
+ };
+ await buyProduct(body);
+ });
+ if (confirm("κ²°μ κ° μλ£λμμ΅λλ€.\nμ£Όλ¬Έ λ΄μμ νμΈνμκ² μ΅λκΉ?")) {
+ navigate("/sweethome/mypage");
+ } else {
+ return;
+ }
+ order.map((item: any) => {
+ dispatch({ type: "GETBUYITEM", items: item.id });
+ });
+ dispatch({
+ type: "RETURN_CART",
+ items: cart.filter((item: any) => {
+ return !order.includes(item);
+ })
+ });
+ } catch (error) {
+ console.log("κ²°μ μ€ν¨", error);
+ alert("μν μ£Όλ¬Έμ μ€ν¨νμ΅λλ€.");
+ }
+ };
+
+ return (
+ <>
+
+
+
+
μ£Όλ¬Έμ μμ± / κ²°μ
+
+
+
+
μ£Όλ¬ΈμμΈλ΄μ
+
+
μν μ΄λ―Έμ§
+
μνλͺ
+
μλ
+
κ°κ²©
+
μ΄ κΈμ‘
+
+
+
+
+
+ {order.map((item, i: number) => (
+ -
+
+
+
+
+
+
+
+ {item.title}
+
+
+ {item.quantity}κ°
+
+
+
+ {item.discountRate !== 0
+ ? `${convertPrice(item.price)}μ`
+ : `${convertPrice(
+ priceBeforeDiscount(item.price, item.discountRate)
+ )}μ`}
+
+
+ {item.discountRate !== 0
+ ? `${convertPrice(
+ priceBeforeDiscount(item.price, item.discountRate)
+ )}μ`
+ : ""}
+
+
+
+ {item.discountRate !== 0
+ ? convertPrice(item.price * item.quantity)
+ : convertPrice(
+ priceBeforeDiscount(item.price, item.discountRate) *
+ item.quantity
+ )}
+ μ
+
+
+ ))}
+
+
+
+
+
+
μ΄ {totalQuantity}κ°μ μν
+
β©{convertPrice(totalPrice)}
+
+
+
+
λ°°μ‘λΉ
+
β©0
+
+
+
+
ν©κ³
+
β©{convertPrice(totalPrice)}
+
+
+
+
+
μ£Όλ¬Έμ μ 보
+
+
+ μ£Όλ¬Έμλͺ
:
+ {user.displayName}
+
+
+ μ΄λ©μΌ:
+ {user.email}
+
+
+
+
+
+
κ²°μ μλ¨
+
+
+ {accountChecked ? (
+
+ {accountList.length ? (
+ accountList.map(account => (
+
{
+ setAccountId(account.id);
+ setBankName(account.bankName);
+ setIsActive(true)
+ }}>
+
{account.bankName}
+
{account.accountNumber}
+
μμ‘: {convertPrice(account.balance)}μ
+
+ ))
+ ) : (
+
+ κ³μ’λ₯Ό λ¨Όμ λ±λ‘ν΄μ£ΌμΈμ.
+
+ )}
+
+ ) : (
+
+
μ
κΈμν
+
κ΅λ―Όμν 123-4565-11234
+
μκΈμ£Ό: (μ£Ό)μ§κ°κ΅¬μΆμ΄
+
+ )}
+
+
+
+
+
μ΅μ’
κ²°μ κΈμ‘
+
+
β©{convertPrice(totalPrice)}
+ {bankName ? (
{bankName}μμ μ΄ {convertPrice(totalPrice)}μ κ²°μ μμ μ
λλ€.
) : null}
+
+
+
+
+ orderApplyHandler(e, order, accountId)}
+ />
+
+
+ >
+ );
+};
+
+export default Buy;
diff --git a/src/routes/Cart/Cart.tsx b/src/routes/Cart/Cart.tsx
new file mode 100644
index 00000000..17638e58
--- /dev/null
+++ b/src/routes/Cart/Cart.tsx
@@ -0,0 +1,95 @@
+import { useEffect } from "react";
+import { useNavigate } from "react-router-dom";
+import { useSelector } from "react-redux";
+import { FaEquals, FaPlus } from "react-icons/fa";
+import { convertPrice } from "~/utils/convert";
+import CartList from "~/components/Cart/CartList";
+import styles from "~/styles/Cart/Cart.module.scss";
+
+const Cart = () => {
+ const navigate = useNavigate();
+
+ useEffect(() => {
+ if (!localStorage.getItem('token')) {
+ alert('λ‘κ·ΈμΈμ ν΄μ£ΌμΈμ! π ');
+ navigate('/sweethome/login');
+ }
+ },[])
+
+
+ const select = useSelector((state: any) => state.selectedCart);
+ const cart = useSelector((state: any) => state.cart);
+
+ const total = [...select];
+
+ const totalQuantity = total.reduce((acc, cur) => (acc += cur.quantity), 0);
+ const totalProductPrice = total.reduce((acc, cur) => (acc += cur.price), 0);
+ const totalPrice = totalProductPrice;
+
+ useEffect(() => {}, [total]);
+
+ return (
+ <>
+ {localStorage.getItem('token') ?
+
+
+
+
μ₯λ°κ΅¬λ
+
+
+
+
+
μν μ΄λ―Έμ§
+
μνλͺ
+
μλ
+
κ°κ²©
+
μ΄ κΈμ‘
+
+
+
+
+ {cart.length ? (
+
+ ) : (
+
μ₯λ°κ΅¬λμ λ΄κΈ΄ μνμ΄ μμ΅λλ€.
+ )}
+
+
+
+
{`μ΄ ${totalQuantity}κ°μ μν`}
+
β©{convertPrice(totalProductPrice)}
+
+
+
+
λ°°μ‘λΉ
+
β©0
+
+
+
+
ν©κ³
+
β©{convertPrice(totalPrice)}
+
+
+
+ navigate("/sweethome/buy", { state: select })}
+ />
+ navigate("/sweethome/buy", { state: cart })}
+ />
+
+
+
+ :
+ }
+ >
+ );
+};
+
+export default Cart;
diff --git a/src/routes/Home/Home.tsx b/src/routes/Home/Home.tsx
new file mode 100644
index 00000000..c8d088f9
--- /dev/null
+++ b/src/routes/Home/Home.tsx
@@ -0,0 +1,16 @@
+import { Slider } from "~/utils/slider.tsx";
+import styles from "~/styles/Home/Home.module.scss";
+
+const Home = () => {
+ return (
+ <>
+
+
+
+
+
+ >
+ );
+};
+
+export default Home;
diff --git a/src/routes/Login/Login.tsx b/src/routes/Login/Login.tsx
new file mode 100644
index 00000000..e792d2e2
--- /dev/null
+++ b/src/routes/Login/Login.tsx
@@ -0,0 +1,94 @@
+import { useState } from "react";
+import { useNavigate, Link } from "react-router-dom";
+import { useDispatch } from "react-redux";
+import { logIn } from "~/api/requests";
+import styles from "~/styles/Login/Login.module.scss";
+
+
+const Login = () => {
+ const [email, setEmail] = useState("");
+ const [password, setPassword] = useState("");
+ const dispatch = useDispatch();
+ const navigate = useNavigate();
+
+ const loginHandler = async (e: any) => {
+ e.preventDefault();
+
+ let body = {
+ email: email,
+ password: password
+ };
+
+ try {
+ const res = await logIn(body);
+ if (res) {
+ if (res.user.email === import.meta.env.VITE_ADMIN_ACCOUNT) {
+ navigate("/sweethome/admin");
+ dispatch({ type: "RETURN", account: res });
+ dispatch({ type: "LOGOUT", state: true });
+ } else {
+ navigate("/sweethome")
+ dispatch({ type: "RETURN", account: res });
+ dispatch({ type: "LOGOUT", state: true });
+ }
+ } else {
+ dispatch({ type: "LOGOUT", state: false });
+ alert("λ‘κ·ΈμΈ μ€ν¨νμμ΅λλ€.")
+ }
+ } catch (error: any) {
+ alert(error.message);
+ }
+ };
+
+ return (
+ <>
+
+
+
+
λ‘κ·ΈμΈ
+
+
+
μμ΄λ μ°ΎκΈ°
+
|
+
λΉλ°λ²νΈ μ°ΎκΈ°
+
+
+
+
μμ§ νμμ΄ μλμ κ°μ?
+
νμ κ°μ
μ νμλ©΄ λ€μνκ³ νΉλ³ν ννμ λ리μΈμ
+
+
+
+
+
+
+ >
+ );
+};
+export default Login;
diff --git a/src/routes/Mypage/MyBankAccount.tsx b/src/routes/Mypage/MyBankAccount.tsx
new file mode 100644
index 00000000..2a6c4372
--- /dev/null
+++ b/src/routes/Mypage/MyBankAccount.tsx
@@ -0,0 +1,101 @@
+import { useEffect, useState } from 'react';
+import { useDispatch } from 'react-redux';
+import { getBankList, getAccountList } from '~/api/requests';
+import Account from '~/components/MyPage/MyBankAccount/Account';
+import AccountModal from '~/components/MyPage/MyBankAccount/AccountModal';
+import Loading from '~/components/common/Loading';
+import styles from '~/styles/Mypage/MyBankAccount.module.scss';
+
+interface Bank {
+ id: string;
+ bankName: string;
+ bankCode: string;
+ accountNumber: string;
+ balance: number;
+}
+
+const MyBankAccount = () => {
+ const [showModal, setShowModal] = useState(false)
+ const [bankList, setBankList] = useState([])
+ const [accountList, setAccountList] = useState([])
+ const [watch, setWatch] = useState(false)
+ const [isLoading, setIsLoading] = useState(false);
+ const dispatch = useDispatch();
+
+ useEffect(() => {
+ checkBankList();
+ checkAccountList();
+ },[watch])
+
+
+ // μ ν κ°λ₯ν μν λͺ©λ‘ μ‘°ν
+ const checkBankList = async () => {
+ setIsLoading(true);
+ try {
+ const res = await getBankList();
+ setBankList(res);
+ } catch (error) {
+ alert('μν μ 보λ₯Ό λΆλ¬μ€λ λ° μ€ν¨νμμ΅λλ€.');
+ }
+ setIsLoading(false);
+ }
+
+ // λ±λ‘λ κ³μ’ μ‘°ν
+ const checkAccountList = async () => {
+ setIsLoading(true);
+ try {
+ const res = await getAccountList();
+ setAccountList(res.accounts);
+ dispatch({ type: "GET_ACCOUNT_LIST", accountList: res });
+ } catch (error) {
+ alert('κ³μ’ μ 보 λΆλ¬μ€λ λ° μ€ν¨νμμ΅λλ€.')
+ }
+ setIsLoading(false);
+ }
+
+ return (
+ <>
+ {isLoading? : null}
+ {showModal && (
+ )}
+
+
+
+
κ³μ’ κ΄λ¦¬
+
+ {accountList.length > 0
+ ? (accountList.map((item, i: number)=> (
+
)))
+ : (
+
+
+
λ±λ‘λ κ³μ’κ° μμ΅λλ€.
+
κ³μ’ λ²νΈλ₯Ό λ±λ‘ν΄ μ£ΌμΈμ!
+
+
+ )}
+
+
+
+ >
+ )
+}
+
+export default MyBankAccount
\ No newline at end of file
diff --git a/src/routes/Mypage/MyInfo.tsx b/src/routes/Mypage/MyInfo.tsx
new file mode 100644
index 00000000..f30e5a45
--- /dev/null
+++ b/src/routes/Mypage/MyInfo.tsx
@@ -0,0 +1,131 @@
+import { useSelector } from 'react-redux';
+import { useForm } from 'react-hook-form';
+import { editInfo } from '~/api/requests';
+import styles from '~/styles/Mypage/MyInfo.module.scss';
+
+interface Password {
+ oldPassword: string,
+ newPassword: string
+}
+
+const MyInfo = () => {
+ const user = useSelector((state: any) => state.user)
+
+ const {
+ register,
+ handleSubmit,
+ formState: { errors, isSubmitting},
+ reset
+ } = useForm({
+ mode: 'onChange',
+ });
+
+ const userPassword = {
+ minLength: {
+ value: 8,
+ message: "λΉλ°λ²νΈλ μ΅μ 8μμ
λλ€."
+ },
+ maxLength: {
+ value: 16,
+ message: "λΉλ°λ²νΈλ μ΅λ 16μμ
λλ€."
+ }
+ }
+
+
+ const ChangePWHandler = async({ oldPassword, newPassword }: Password) => {
+ if (oldPassword.length < 8 || newPassword.length < 8) return alert('λΉλ°λ²νΈλ 8μμ΄μ μ
λ ₯ν΄μ£ΌμΈμ.')
+ const body = {
+ oldPassword,
+ newPassword
+ }
+ try {
+ const res = await editInfo(body)
+ if (res) {
+ alert('λΉλ°λ²νΈκ° λ³κ²½λμμ΅λλ€.')
+ reset();
+ } else {
+ alert('λΉλ°λ²νΈλ₯Ό λ€μ μ
λ ₯ν΄ μ£ΌμΈμ.')
+ reset();
+ }
+ } catch (error: any) {
+ alert(error.message);
+ }
+ }
+
+ return (
+
+ )
+}
+
+export default MyInfo;
\ No newline at end of file
diff --git a/src/routes/Mypage/MyOrder.tsx b/src/routes/Mypage/MyOrder.tsx
new file mode 100644
index 00000000..2e3cf820
--- /dev/null
+++ b/src/routes/Mypage/MyOrder.tsx
@@ -0,0 +1,210 @@
+import { useEffect, useState } from "react";
+import {
+ cancelTransaction,
+ confirmedTransaction,
+ getAllTransactions,
+ getTransaction,
+} from "~/api/requests";
+import { convertPrice, convertDate, sortDate } from "~/utils/convert";
+import MyOrderDetails from "~/routes/Mypage/MyOrderDetails";
+import Loading from "~/components/common/Loading";
+import styles from "~/styles/Mypage/MyOrder.module.scss";
+
+type AllTransactions = TransactionDetail[]
+
+interface TransactionDetail {
+ detailId: string
+ product: {
+ productId: string
+ title: string
+ price: number
+ description: string
+ tags: string[]
+ thumbnail: string
+ discountRate: number
+ }
+ reservation: Reservation | null
+ timePaid: string
+ isCanceled: boolean
+ done: boolean
+}
+
+interface Reservation {
+ start: string
+ end: string
+ isCanceled: boolean
+ isExpired: boolean
+}
+
+
+const MyOrder = () => {
+ const [allList, setAllList] = useState([]);
+ const [showDetails, setShowDetails] = useState(false);
+ const [orderDetails, setOrderDetails] = useState({});
+ const [isLoading, setIsLoading] = useState(false);
+ const [watch, setWatch] = useState(false);
+
+ useEffect(() => {
+ allTransactions();
+ }, [watch]);
+
+ // μ 체 κ±°λ λ΄μ
+ const allTransactions = async () => {
+ setIsLoading(true);
+ const allRes = await getAllTransactions();
+ if (allRes) {
+ setAllList(
+ allRes
+ .filter((res: TransactionDetail) => !res.isCanceled)
+ .sort((a: TransactionDetail, b: TransactionDetail) => sortDate(b.timePaid) - sortDate(a.timePaid))
+ );
+ } else {
+ alert("μ£Όλ¬Έ λ΄μμ΄ μμ΅λλ€.")
+ }
+ setIsLoading(false);
+ };
+
+ // ꡬ맀 μ·¨μ
+ const cancelHandler = async (
+ e: React.MouseEvent,
+ id: string
+ ) => {
+ e.preventDefault();
+ setIsLoading(true);
+ try {
+ const body = { detailId: id };
+ const res = await cancelTransaction(body);
+ if (res) {
+ setWatch(!watch)
+ alert("ꡬ맀 μ·¨μλμμ΅λλ€.");
+ } else {
+ alert("ꡬ맀 νμ λ μνμ μ·¨μν μ μμ΅λλ€.");
+ }
+ } catch (error: any) {
+ alert(error.message);
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ // ꡬ맀 νμ
+ const confirmHandler = async (
+ e: React.MouseEvent,
+ Id: string
+ ) => {
+ e.preventDefault();
+ try {
+ const body = { detailId: Id };
+ const res = await confirmedTransaction(body);
+ if (res) {
+ setWatch(!watch)
+ alert("ꡬ맀 νμ μλ£!")
+ }
+ } catch (error: any) {
+ alert(error.message);
+ }
+ };
+
+ // λ¨μΌ μν μμΈ
+ const showDetailsHandler = async (
+ e: React.MouseEvent,
+ id: string
+ ) => {
+ e.preventDefault();
+ try {
+ const body = { detailId: id };
+ const res = await getTransaction(body);
+ setOrderDetails(res);
+ setShowDetails(true);
+ } catch (error: any) {
+ alert(error.message)
+ }
+ };
+
+ return (
+ <>
+ {isLoading ? : null}
+ {showDetails ? (
+
+ ) : null}
+
+
+
+
μ£Όλ¬Έ λ΄μ κ΄λ¦¬
+
+
+
+
+
NO.
+
μν μ΄λ―Έμ§
+
μνλͺ
+
μν κ°κ²©
+
μ£Όλ¬Έ μΌμ
+
ꡬ맀 νμ
+
λΉκ³
+
+
+
+
+
+
+ >
+ );
+};
+
+export default MyOrder;
diff --git a/src/routes/Mypage/MyOrderDetails.tsx b/src/routes/Mypage/MyOrderDetails.tsx
new file mode 100644
index 00000000..110f008e
--- /dev/null
+++ b/src/routes/Mypage/MyOrderDetails.tsx
@@ -0,0 +1,80 @@
+import { TfiClose } from "react-icons/tfi";
+import { convertDate, convertPrice } from '~/utils/convert';
+import styles from "~/styles/Mypage/MyOrderDetails.module.scss";
+
+interface DetailsProps {
+ setShowDetails: React.Dispatch>
+ orderDetails: TransactionDetail
+}
+interface TransactionDetail {
+ detailId: string
+ product: {
+ productId: string
+ title: string
+ price: number
+ description: string
+ tags: string[]
+ thumbnail: string
+ discountRate: number
+ photo: string
+ }
+ timePaid: string
+ done: boolean
+ account: {
+ bankName: string
+ accountNumber: string
+ }
+}
+
+const MyOrderDetails = ({ setShowDetails, orderDetails }: DetailsProps) => {
+ return (
+
+
+
setShowDetails(false)}
+ >
+
+
+
+
μ£Όλ¬Έ μμΈ μ 보
+
+
+
+
+
+
+
+
μ£Όλ¬Έλ²νΈ
+
+ {orderDetails.product.productId}
+
+
μ£Όλ¬Έλ μ§
+
+ {convertDate(orderDetails.timePaid)}
+
+
+
+
{orderDetails.product.title}
+
μνκΈμ‘ β©{convertPrice(orderDetails.product.price)}
+
μννμ {orderDetails.done}
+
+
+
κ²°μ μμΈ
+
κ°μ κ³μ’ κ²°μ β©{convertPrice(orderDetails.product.price)}
+
+ {orderDetails.account.bankName}
+ ({orderDetails.account.accountNumber})
+
+
+
+
+
+
+ );
+};
+
+export default MyOrderDetails;
diff --git a/src/routes/Mypage/Mypage.tsx b/src/routes/Mypage/Mypage.tsx
new file mode 100644
index 00000000..65eeddec
--- /dev/null
+++ b/src/routes/Mypage/Mypage.tsx
@@ -0,0 +1,94 @@
+import { useEffect, useState } from 'react';
+import { useSelector } from 'react-redux';
+import { useNavigate } from 'react-router-dom';
+import { logIn } from '~/api/requests';
+import SubNav from '~/components/common/SubNav';
+import MyInfo from "~/routes/Mypage/MyInfo";
+import AccountList from "~/routes/Mypage/MyBankAccount";
+import Transactions from '~/routes/Mypage/MyOrder';
+import styles from '~/styles/Mypage/Mypage.module.scss';
+
+
+const MyPage = () => {
+ const user = useSelector((state:any) => state.user)
+ const navigate = useNavigate();
+ const [password, setPassword] = useState('')
+ const [passwordConfirm, setPasswordConfirm] = useState(false);
+
+ const subNav: string[] = ["μ£Όλ¬Έ λ΄μ κ΄λ¦¬", "κ³μ’ μ 보 κ΄λ¦¬", "κ°μΈ μ 보 κ΄λ¦¬"];
+ const [category, setCategory] = useState('');
+
+ useEffect(() => {
+ if (!localStorage.getItem('token')) {
+ alert('λ‘κ·ΈμΈμ ν΄μ£ΌμΈμ! π ');
+ navigate('/sweethome/login');
+ }
+ },[])
+
+ const onPasswordHandler = (e: React.ChangeEvent) => {
+ setPassword(e.target.value);
+ }
+
+ const handleSubmitPasswordConfirm = async (event: React.FormEvent) => {
+ event.preventDefault();
+ const body = {
+ email: user.email,
+ password,
+ };
+
+ try {
+ const res = await logIn(body);
+ if (res) {
+ setPasswordConfirm(true);
+ } else {
+ alert('λΉλ°λ²νΈκ° μΌμΉνμ§ μμ΅λλ€.')
+ }
+ } catch (error: any) {
+ alert(error.message)
+ }
+
+ };
+
+ return (
+ <>
+ {localStorage.getItem('token') ?
+
+
+ {(category === "μ£Όλ¬Έ λ΄μ κ΄λ¦¬" || category === "" ) &&
}
+ {category === "κ³μ’ μ 보 κ΄λ¦¬" &&
}
+ {category === "κ°μΈ μ 보 κ΄λ¦¬" && (!passwordConfirm?
+
+
+
+
κ°μΈ μ 보 μμ
+
+
νμλμ μ 보λ₯Ό μμ νκ² λ³΄νΈνκΈ° μν΄ λΉλ°λ²νΈλ₯Ό λ€μ ν λ² νμΈν΄ μ£ΌμΈμ!
+
+
+
+ :
)
+ }
+
+ :
+ }
+ >
+ )
+
+}
+
+export default MyPage
diff --git a/src/routes/NotFound/NotFount.tsx b/src/routes/NotFound/NotFount.tsx
new file mode 100644
index 00000000..8ead4899
--- /dev/null
+++ b/src/routes/NotFound/NotFount.tsx
@@ -0,0 +1,26 @@
+import { NavLink } from "react-router-dom";
+import { RiEmotionUnhappyLine } from "react-icons/ri"
+import styles from "~/styles/NotFound/NotFound.module.scss";
+
+const NotFount = () => {
+ return (
+ <>
+
+
+
+
+
404
+
νμ΄μ§λ₯Ό μ°Ύμ μ μμ΅λλ€.
+
+
+
+
+
+
+
+
+ >
+ )
+}
+
+export default NotFount;
\ No newline at end of file
diff --git a/src/routes/Shop/Shop.tsx b/src/routes/Shop/Shop.tsx
new file mode 100644
index 00000000..9b5f4f07
--- /dev/null
+++ b/src/routes/Shop/Shop.tsx
@@ -0,0 +1,86 @@
+import { useState, useEffect } from 'react';
+import { getAllProducts } from '~/api/requests';
+import ProductItem from '~/components/Shop/ProductItem';
+import styles from '~/styles/Shop/Shop.module.scss';
+
+const Shop = () => {
+ type AllProduct = GetProduct[]
+
+ interface GetProduct {
+ id: string
+ title: string
+ price: number
+ description: string
+ tags: string
+ thumbnail: string | null
+ isSoldOut: boolean
+ discountRate: number
+ }
+
+ const [allProducts, setAllProducts] = useState([]);
+ const [originalProducts, setOriginalProducts] = useState([]);
+ const [click, ] = useState(false);
+
+ useEffect(() => {
+ spreadAllProducts();
+ }, [])
+
+ useEffect(() => {
+ }, [allProducts])
+
+ const spreadAllProducts = async () => {
+ try {
+ const res = await getAllProducts();
+ setAllProducts(res);
+ setOriginalProducts(res);
+ } catch (error: any) {
+ alert(error.message)
+ }
+ }
+
+ // μν μΉ΄ν
κ³ λ¦¬
+ const categorys = [ "ALL", "FURNITURE", "KITCHEN", "BEDROOM" ];
+
+ // μν μΉ΄ν
κ³ λ¦¬λ³ νν° κΈ°λ₯
+ const categoryHandler = (e: React.MouseEvent) => {
+ if ((e.target as HTMLButtonElement).value === "ALL") {
+ setAllProducts(originalProducts)
+ } else if ((e.target as HTMLButtonElement).value === "FURNITURE") {
+ setAllProducts(originalProducts.filter(product => product.tags === "FURNITURE"))
+ } else if ((e.target as HTMLButtonElement).value === "KITCHEN") {
+ setAllProducts(originalProducts.filter(product => product.tags === "KITCHEN"))
+ } else if ((e.target as HTMLButtonElement).value === "BEDROOM") {
+ setAllProducts(originalProducts.filter(product => product.tags === "BEDROOM"))
+ }
+ }
+
+ return (
+ <>
+
+
+
+
+ {allProducts.map((product: GetProduct)=> (
+
+ ))}
+
+
+
+ >
+ )
+}
+
+export default Shop
\ No newline at end of file
diff --git a/src/routes/Shop/ShopDetail.tsx b/src/routes/Shop/ShopDetail.tsx
new file mode 100644
index 00000000..e7d53c60
--- /dev/null
+++ b/src/routes/Shop/ShopDetail.tsx
@@ -0,0 +1,218 @@
+import { getProduct } from "~/api/requests";
+import { priceBeforeDiscount, convertPrice } from "~/utils/convert";
+import { useState, useEffect } from "react";
+import { useParams, useNavigate } from "react-router-dom";
+import { useSelector, useDispatch } from "react-redux";
+import Loading from "~/components/common/Loading";
+import styles from "~/styles/Shop/ShopDetail.module.scss";
+
+const ShopDetail = () => {
+ type Params = {
+ id: string | undefined;
+ };
+
+ const { id } = useParams();
+ const navigate = useNavigate();
+ const dispatch = useDispatch();
+ const globalCart = useSelector((state: any) => state.cart);
+
+ const [product, setProduct] = useState({});
+ const [count, setCount] = useState(1);
+ const [isLoading, setIsLoading] = useState(false);
+
+ useEffect(() => {
+ getProductHandler(id);
+ }, []);
+
+ // λ¨μΌ μν μ‘°ν
+ const getProductHandler = async (id: any) => {
+ setIsLoading(true);
+ try {
+ const res = await getProduct(id);
+ res["quantity"] = count;
+ setProduct(res);
+ } catch (error: any) {
+ alert(error.message);
+ }
+ setIsLoading(false);
+ };
+
+ // μν μλ κ³μ°
+ const productCountHandler = (type: string) => {
+ if (type === "plus") {
+ setCount(count + 1);
+ } else {
+ if (count === 1) return;
+ setCount(count - 1);
+ }
+ };
+
+ // μ₯λ°κ΅¬λ μ€λ³΅ μ²λ¦¬
+ const cartDuplicationHandler = (id: string, quantity: number) => {
+ const found = globalCart.filter((el: any) => el.id === id)[0];
+ const idx = globalCart.indexOf(found);
+ const cartItem = {
+ id: product.id,
+ title: product.title,
+ price: product.price,
+ discountPrice: product.price,
+ quantity: quantity,
+ description: product.description,
+ tags: product.tags,
+ thumbnail: product.thumbnail,
+ photo: product.photo,
+ isSoldOut: product.isSoldOut,
+ reservations: product.reservations,
+ discountRate: product.discountRate,
+ isChecked: false
+ };
+ dispatch({
+ type: "RETURN_CART",
+ items: [
+ ...globalCart.slice(0, idx),
+ cartItem,
+ ...globalCart.slice(idx + 1)
+ ]
+ });
+ };
+
+ // μ₯λ°κ΅¬λ νΈλ€λ¬
+ const cartHandler = () => {
+ const cartItem = {
+ id: product.id,
+ title: product.title,
+ price: product.price,
+ discountPrice: product.price,
+ quantity: count,
+ description: product.description,
+ tags: product.tags,
+ thumbnail: product.thumbnail,
+ photo: product.photo,
+ isSoldOut: product.isSoldOut,
+ reservations: product.reservations,
+ discountRate: product.discountRate,
+ isChecked: false
+ };
+
+ const found = globalCart.find((el: any) => el.id === cartItem.id);
+
+ if (found) {
+ cartDuplicationHandler(cartItem.id, found.quantity + count);
+ } else {
+ dispatch({ type: "RETURN_CART", items: [...globalCart, cartItem] });
+ }
+
+ if (confirm("μ₯λ°κ΅¬λλ₯Ό νμΈνμκ² μ΅λκΉ?")) {
+ navigate("/sweethome/cart");
+ } else return;
+ };
+
+ const buyNowHandler = () => {
+ if (!localStorage.getItem("token")) {
+ alert("λ‘κ·ΈμΈμ΄ νμν©λλ€.");
+ navigate("/sweethome/login");
+ } else {
+ navigate("/sweethome/buy", { state: [product] });
+ }
+ };
+
+ return (
+ <>
+ {isLoading ? : null}
+
+
+
+
+
+
+
+
{product.tags}
+
{product.title}
+
+ {convertPrice(product.price)}μ
+
+
+
+ {convertPrice(
+ priceBeforeDiscount(product.price, product.discountRate)
+ )}
+ μ
+
+
+ {product.discountRate ? `${product.discountRate}%` : ""}
+
+
+
+
+
+ buyNowHandler()}
+ />
+ cartHandler()}
+ />
+
+
+
+
+
+
+ μν μμΈ μ 보
+
+
+
{product.description}
+
+
+
+
+
+
+
+ >
+ );
+};
+
+export default ShopDetail;
diff --git a/src/routes/SignUp/SignUp.tsx b/src/routes/SignUp/SignUp.tsx
new file mode 100644
index 00000000..a70e6d6c
--- /dev/null
+++ b/src/routes/SignUp/SignUp.tsx
@@ -0,0 +1,188 @@
+import { useState } from "react";
+import { useForm } from "react-hook-form";
+import { useNavigate } from "react-router-dom";
+import { signUp } from "~/api/requests";
+import styles from "~/styles/Signup/SignUp.module.scss";
+import Loading from "~/components/common/Loading";
+
+interface SignUpBody {
+ email: string
+ password: string
+ displayName: string
+ profileImgBase64?: string
+ pwConfirm?: string
+}
+
+const SignUp = () => {
+ const [isAgree, setIsAgree] = useState(false);
+ const [isLoading, setIsLoading] = useState(false);
+ const navigate = useNavigate();
+ const {
+ register,
+ handleSubmit,
+ watch,
+ formState: { errors, isSubmitting },
+ reset
+ } = useForm({
+ mode: 'onChange'
+ });
+
+ const emailValidation = {
+ required: "μ΄λ©μΌμ νμ μ
λ ₯μ
λλ€.",
+ pattern: {
+ value: /\S+@\S+\.\S+/,
+ message: "μ΄λ©μΌ νμμ λ§μ§ μμ΅λλ€.",
+ }
+ };
+
+ const nameValidation = {
+ required: "μ΄λ¦μ νμ μ
λ ₯μ
λλ€.",
+ minLength: {
+ value: 3,
+ message: "μ΄λ¦μ 3μμ΄μμ
λλ€.",
+ }
+ };
+ const passwordValidation = {
+ required: "λΉλ°λ²νΈλ νμ μ
λ ₯μ
λλ€.",
+ pattern: {
+ value: /^[A-za-z0-9]*$/ ,
+ message: 'μλ¬Έμ μ«μλ§ κ°λ₯ν©λλ€.' ,
+ } ,
+ minLength: {
+ value: 8,
+ message: "λΉλ°λ²νΈλ 8 ~ 16μμ
λλ€."
+ }
+ };
+
+
+ const onAgreeHandler = (e: React.ChangeEvent) => {
+ if (e.target.checked) {
+ setIsAgree(!isAgree);
+ }
+ };
+
+ const onSubmitHandler = async ({email, displayName, password}: SignUpBody) => {
+ setIsLoading(true);
+
+ if (!isAgree) {
+ return alert("μ΄μ©μ½κ΄ λ° κ°μΈμ 보μμ§μ λμν΄ μ£ΌμΈμ!");
+ }
+ let body = {
+ email,
+ displayName,
+ password
+ };
+ try {
+ isAgree && await signUp(body)
+ reset();
+ if (confirm("νμκ°μ
μ±κ³΅!\nλ‘κ·ΈμΈ νμ΄μ§λ‘ μ΄λνμκ² μ΅λκΉ?")) {
+ navigate('/sweethome/login')
+ } else {
+ navigate('/sweethome')
+ }
+ } catch (error) {
+ console.log("SignUp Error", error);
+ }
+ setIsLoading(false);
+ };
+
+ return (
+ <>
+ {isLoading ? : null}
+
+ >
+ );
+};
+
+export default SignUp;
diff --git a/src/routes/index.tsx b/src/routes/index.tsx
new file mode 100644
index 00000000..1660e01c
--- /dev/null
+++ b/src/routes/index.tsx
@@ -0,0 +1,66 @@
+import { createBrowserRouter } from "react-router-dom";
+import App from "~/App";
+import Home from "~/routes/Home/Home";
+import About from "~/routes/About/About";
+import Shop from "~/routes/Shop/Shop";
+import ShopDetail from "~/routes/Shop/ShopDetail";
+import Mypage from "~/routes/Mypage/Mypage";
+import Cart from "~/routes/Cart/Cart";
+import Login from "~/routes/Login/Login";
+import SignUp from "~/routes/SignUp/SignUp";
+import Admin from "~/routes/Admin/Admin";
+import Buy from "~/routes/Buy/Buy";
+import NotFound from "~/routes/NotFound/NotFount";
+
+export default createBrowserRouter([
+ {
+ path: "/sweethome",
+ element: ,
+ children: [
+ {
+ path: "/sweethome",
+ element:
+ },
+ {
+ path: "/sweethome/about",
+ element:
+ },
+ {
+ path: "/sweethome/shop",
+ element:
+ },
+ {
+ path: "/sweethome/shop/:id",
+ element:
+ },
+ {
+ path: "/sweethome/mypage",
+ element:
+ },
+ {
+ path: "/sweethome/cart",
+ element:
+ },
+ {
+ path: "/sweethome/login",
+ element:
+ },
+ {
+ path: "/sweethome/signup",
+ element:
+ },
+ {
+ path: "/sweethome/admin",
+ element:
+ },
+ {
+ path: "/sweethome/buy",
+ element:
+ }
+ ]
+ },
+ {
+ path: "*",
+ element:
+ }
+]);
diff --git a/src/store/index.ts b/src/store/index.ts
new file mode 100644
index 00000000..a76aa6d5
--- /dev/null
+++ b/src/store/index.ts
@@ -0,0 +1,6 @@
+import { createStore } from "redux";
+import reducers from "~/reducers";
+
+const store = createStore(reducers);
+
+export { store };
diff --git a/src/styles/.DS_Store b/src/styles/.DS_Store
new file mode 100644
index 00000000..a45cd949
Binary files /dev/null and b/src/styles/.DS_Store differ
diff --git a/src/styles/About/About.module.scss b/src/styles/About/About.module.scss
new file mode 100644
index 00000000..c2bc76c2
--- /dev/null
+++ b/src/styles/About/About.module.scss
@@ -0,0 +1,45 @@
+@import '../common/colors.scss';
+@import '../common/fonts.scss';
+
+.about {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ .container {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ max-width: 1440px;
+ min-height: calc(100vh - (100px + 150px));
+ gap: 120px;
+
+ .aboutImg {
+ min-width: 300px;
+ max-width: 30vw;
+ max-height: calc(width / 3 * 4);
+ overflow: hidden;
+
+ img {
+ width: 100%;
+ height: 100%;
+ }
+ }
+
+ .aboutText {
+ text-align: right;
+
+ .title {
+ font-family: $font-logo;
+ font-size: $font-logo-size;
+ margin-bottom: 30px;
+ }
+
+ .introduction {
+ font-family: "Pretendard";
+ line-height: 1.6;
+ }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/styles/Admin/Admin.module.scss b/src/styles/Admin/Admin.module.scss
new file mode 100644
index 00000000..93a0d5fd
--- /dev/null
+++ b/src/styles/Admin/Admin.module.scss
@@ -0,0 +1,51 @@
+@import '../common/colors.scss';
+@import '../common/fonts.scss';
+
+.container {
+ display: flex;
+ justify-content: center;
+
+ .nav {
+ display: flex;
+ justify-content: center;
+ width: 200px;
+ height: auto;
+ border-right: 1px solid $base-color-gray;
+
+ .category {
+ position: relative;
+ top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ gap: 20px;
+ height: 30px;
+ text-align: center;
+
+ li {
+ cursor: pointer;
+ }
+ li:nth-child(1) {
+ margin-top: 15px;
+ }
+ }
+ }
+ .contentsWrapper{
+ width: calc(100% - 200px);
+ display:flex;
+ justify-content:center;
+
+ .contents {
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+ align-items: center;
+ width: 1000px;
+ max-width: 1240px;
+ min-height: 600px;
+ margin: 50px 0 50px;
+ overflow: auto;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/styles/Admin/AdminOrder.module.scss b/src/styles/Admin/AdminOrder.module.scss
new file mode 100644
index 00000000..88cdbc8b
--- /dev/null
+++ b/src/styles/Admin/AdminOrder.module.scss
@@ -0,0 +1,88 @@
+@import '../common/colors.scss';
+@import '../common/fonts.scss';
+
+.adminOrder {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ margin: 50px auto;
+ min-height: calc(100vh - (100px + 150px));
+ font-family: "Pretendard";
+
+ .container {
+ min-width: 1000px;
+ max-width: 1440px;
+
+ .title {
+ display: flex;
+ justify-content: center;
+ margin-bottom: 40px;
+
+ h2 {
+ font-size: 24px;
+ font-weight: 700;
+ }
+ }
+
+ .list_nav {
+ margin-bottom: 10px;
+
+ .list_nav_container {
+ display: grid;
+ justify-content: center;
+ align-items: center;
+ grid-template-columns: .7fr repeat(5, 1.6fr) repeat(3, 1fr);
+ width: 100%;
+ height: 60px;
+ background-color: $base-color-lightgray;
+ border-radius: 10px;
+ font-family: "Pretendard";
+ font-weight: 600;
+ text-align: center;
+ }
+ }
+
+ .content {
+ font-size: 14px;
+
+ .allList {
+ .list {
+ display: grid;
+ grid-template-columns: .7fr repeat(5, 1.6fr) repeat(3, 1fr);
+ justify-content: center;
+ align-items: center;
+ height: 100px;
+ border: 1px solid $base-color-gray;
+ border-radius: 10px;
+ margin-bottom: 10px;
+ text-align: center;
+
+
+ .listBtn {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 4px;
+ font-family: "Pretendard";
+
+ .cancelBtn,
+ .confirmBtn {
+ width: 60px;
+ height: 26px;
+ border-radius: 10px;
+ border-style: none;
+ font-size: 14px;
+ cursor: pointer;
+ background-color: $point-color-pink;
+ &:hover {
+ opacity: .8;
+ }
+ }
+ }
+
+ }
+ }
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/styles/Admin/AdminProduct.module.scss b/src/styles/Admin/AdminProduct.module.scss
new file mode 100644
index 00000000..a7260368
--- /dev/null
+++ b/src/styles/Admin/AdminProduct.module.scss
@@ -0,0 +1,170 @@
+@import '../common/colors.scss';
+@import '../common/fonts.scss';
+
+.adminProduct {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ font-family: "Pretendard";
+
+ .addProductContainer {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+
+ .addProduct {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+
+ .title{
+ margin-bottom: 50px;
+
+ h2 {
+ font-family: $font-main;
+ font-size: $font-main-size;
+ font-weight: bold;
+ }
+ }
+
+ form {
+ .productTitle,
+ .productPrice,
+ .productDescription,
+ .productTag,
+ .productDiscount {
+ .label {
+ p {
+ font-family: "Pretendard-Regular";
+ font-size: 16px;
+ font-weight: 500;
+ margin-bottom: 4px;
+ }
+
+ .input {
+ width: 430px;
+ height: 30px;
+ padding-left: 10px;
+ margin-bottom: 20px;
+ border: 1px solid $base-color-gray;
+ border-radius: 10px;
+ outline: none;
+ background: none;
+ color: $font-color;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+ }
+ }
+ }
+
+ .productTag {
+ margin-bottom: 20px;
+ }
+
+ .productThumbnail,
+ .productPhoto {
+ p {
+ font-family: "Pretendard-Regular";
+ font-size: 16px;
+ font-weight: 500;
+ margin-bottom: 4px;
+ }
+
+ .input {
+ width: 420px;
+ height: 28px;
+ margin-bottom: 20px;
+ outline: none;
+ background: none;
+ color: $font-color;
+ }
+
+ }
+
+ .productIsSoldOut {
+ span {
+ margin-right: 6px;
+ }
+
+ .input {
+ margin-bottom: 20px;
+ }
+ }
+
+ .btn {
+ width: 430px;
+ height: 50px;
+ border-style: none;
+ border-radius: 10px;
+ background-color: $base-color-gray;
+ color: $base-color-black;
+ cursor: pointer;
+ }
+ }
+ }
+
+ .adminProductList {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ height: 1000px;
+
+ .title{
+ margin: 50px 0 50px;
+
+ p {
+ font-family: $font-main;
+ font-size: $font-main-size;
+ font-weight: bold;
+ }
+ }
+
+ .allProduct {
+ .wrapper {
+ table {
+ text-align: center;
+
+ thead {
+ font-family: "Pretendard";
+
+ tr {
+ th {
+ padding: 10px 20px 10px;
+ border: 1px solid $base-color-gray;
+ font-weight: 500;
+ }
+ }
+ }
+
+ tbody {
+ tr {
+ text-align: center;
+
+ td {
+ border: 1px solid $base-color-gray;
+ }
+
+ .icon {
+ .modifyBtn {
+ font-size: 24px;
+ margin-right: 10px;
+ }
+
+ .deleteBtn {
+ font-size: 24px;
+ }
+ }
+
+ }
+ }
+ }
+ }
+ }
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/styles/Admin/AdminUser.module.scss b/src/styles/Admin/AdminUser.module.scss
new file mode 100644
index 00000000..26612a5d
--- /dev/null
+++ b/src/styles/Admin/AdminUser.module.scss
@@ -0,0 +1,57 @@
+@import '../common/colors.scss';
+@import '../common/fonts.scss';
+
+.adminUser {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ margin-bottom: 50px;
+
+ .container {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+
+ .title {
+ margin-bottom: 50px;
+
+ h2 {
+ font-family: $font-main;
+ font-size: $font-main-size;
+ font-weight: bold;
+ }
+ }
+
+ .wrapper {
+ margin-bottom: 150px;
+
+ table {
+ font-family: "Pretendard";
+ font-size: 14px;
+
+ thead {
+ tr {
+ th {
+ padding: 10px 20px 10px;
+ border: 1px solid $base-color-gray;
+ font-weight: 500;
+ }
+ }
+ }
+
+ tbody {
+ tr {
+ td {
+ padding: 10px 20px 10px;
+ border: 1px solid $base-color-gray;
+ font-weight: 300;
+ text-align: center;
+ }
+ }
+ }
+ }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/styles/Buy/Buy.module.scss b/src/styles/Buy/Buy.module.scss
new file mode 100644
index 00000000..b273e122
--- /dev/null
+++ b/src/styles/Buy/Buy.module.scss
@@ -0,0 +1,287 @@
+@import "../common/colors.scss";
+@import "../common/fonts.scss";
+
+
+.buy {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ min-height: calc(100vh - (100px + 150px));
+ margin: 50px auto;
+ font-family: "Pretendard";
+ color: $font-color;
+
+ h4 {
+ font-size: 22px;
+ font-weight: 600;
+ margin: 0 0 10px 10px;
+
+ }
+
+ .container {
+ min-width: 1000px;
+ max-width: 1440px;
+ margin: 20px 0;
+
+ .title {
+ display: flex;
+ justify-content: center;
+ margin-bottom: 40px;
+
+ h2 {
+ font-size: 24px;
+ font-weight: 700;
+ }
+ }
+
+ .list_nav {
+ .list_nav_container {
+ display: grid;
+ justify-content: center;
+ align-items: center;
+ grid-template-columns: 1.3fr 1.5fr repeat(3, 1fr);
+ width: 100%;
+ height: 60px;
+ background-color: $base-color-lightgray;
+ border-radius: 10px;
+ font-family: "Pretendard";
+ font-weight: 600;
+ text-align: center;
+ }
+ }
+
+ .buyList {
+ .container {
+ width: 100%;
+
+ .cartItem {
+ display: grid;
+ grid-template-columns: 1.3fr 1.5fr repeat(3, 1fr);
+ align-items: center;
+ min-width: 1000px;
+ max-width: 1440px;
+ padding: 20px 0 20px;
+ margin-bottom: 20px;
+ border: 1px solid $base-color-gray;
+ border-radius: 10px;
+ text-align: center;
+
+ .checkbox {
+
+ }
+
+ a {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ .itemImg {
+ width: 100px;
+ height: 100px;
+
+ img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ }
+ }
+ }
+
+ .itemTitle {
+ span {
+
+ }
+ }
+
+ .itemQuantity {
+ span {
+
+ }
+ }
+
+ .itemPrice {
+ display: flex;
+ flex-direction: column;
+
+ .originalPrice {
+ text-decoration: line-through;
+ }
+ }
+
+ .totalPrice {
+
+ }
+
+ .deleteBtn {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ cursor: pointer;
+
+ svg {
+ path {
+ padding: 20px;
+ &:hover {
+ color: $point-color-red;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ .total_price {
+ background-color: $base-color-lightgray;
+ border-radius: 10px;
+ height: 100px;
+ margin-bottom: 30px;
+
+ .total_price_container {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 100%;
+ font-size: 18px;
+ gap: 6px;
+
+ strong {
+ font-weight: 600;
+ }
+
+ .plus,
+ .equal {
+ svg {
+ path {
+ color: $point-color-mint;
+ }
+ }
+ margin: 0 8px 0;
+ }
+ }
+ }
+
+ .customer {
+ margin-bottom: 30px;
+
+ .customer_container {
+ display: grid;
+ justify-content: center;
+ align-items: center;
+ grid-template-columns: repeat(2, 1fr);
+ width: 100%;
+ height: 60px;
+ border: 1px solid $base-color-gray;
+ border-radius: 10px;
+ font-family: "Pretendard";
+ font-weight: 600;
+ text-align: center;
+
+ .name {
+ span {
+ margin-left: 10px;
+ }
+ }
+ .email {
+ span {
+ margin-left: 10px;
+ }
+ }
+ }
+ }
+
+ .credit {
+ margin-bottom: 30px;
+
+ .credit_container {
+ padding: 30px 70px;
+ border: 1px solid $base-color-gray;
+ border-radius: 10px;
+
+ .select {
+ display: flex;
+ justify-content: center;
+ gap: 20px;
+ margin-bottom: 20px;
+
+ p {
+ font-weight: 600;
+ }
+
+ }
+
+ .account {
+ .account_info {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ text-align: center;
+ align-items: center;
+ height: 50px;
+ border: 1px solid $base-color-gray;
+ border-radius: 10px;
+ margin-bottom: 10px;
+ box-sizing: border-box;
+ cursor: pointer;
+ &:hover {
+ background-color: $base-color-lightgray;
+ }
+ &:active {
+ border: 1.5px solid $point-color-mint;
+ }
+ }
+
+ .noAccount {
+ color: $point-color-red;
+ text-align: center;
+ }
+ }
+
+ .bank {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ gap: 20px;
+ height: 50px;
+ background-color: $base-color-lightgray;
+ border: 1px solid $base-color-gray;
+ border-radius: 10px;
+ }
+ }
+ }
+
+ .payment_details {
+ .details_container {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ border: 1px solid $base-color-gray;
+ border-radius: 10px;
+ padding: 30px;
+ gap: 6px;
+
+ span {
+ font-size: 24px;
+ font-weight: 600;
+ }
+ p {
+ margin: 5px 0;
+ }
+ }
+ }
+ }
+
+ .payment_btn {
+ margin: 30px 0;
+
+ .btn {
+ width: 500px;
+ height: 50px;
+ border-radius: 10px;
+ border-style: none;
+ color: $base-color-white;
+ background-color: $base-color-black;
+ cursor: pointer;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/styles/Cart/Cart.module.scss b/src/styles/Cart/Cart.module.scss
new file mode 100644
index 00000000..ab19c73d
--- /dev/null
+++ b/src/styles/Cart/Cart.module.scss
@@ -0,0 +1,118 @@
+@import "../common/colors.scss";
+@import "../common/fonts.scss";
+
+.checkbox {
+ svg {
+ width: 22px;
+ height: 22px;
+ }
+}
+
+.cart {
+ display: flex;
+ justify-content: center;
+ min-height: calc(100vh - (100px + 150px));
+ margin: 0 auto;
+ font-family: "Pretendard";
+ color: $font-color;
+
+ .container {
+ min-width: 1000px;
+ max-width: 1440px;
+ margin: 50px 0 50px;
+
+ .title {
+ display: flex;
+ justify-content: center;
+ margin-bottom: 40px;
+
+ h2 {
+ font-size: 24px;
+ font-weight: 700;
+ }
+ }
+
+ .list_nav {
+ margin-bottom: 10px;
+
+ .list_nav_container {
+ display: grid;
+ justify-content: center;
+ align-items: center;
+ grid-template-columns: 0.5fr 1fr 2fr 0.5fr repeat(2, 1fr) 0.5fr;
+ width: 100%;
+ height: 60px;
+ background-color: $base-color-lightgray;
+ border-radius: 10px;
+ font-family: "Pretendard";
+ font-weight: 600;
+ text-align: center;
+ }
+ }
+
+ .list_container {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width: 100%;
+ min-height: 30%;
+ border-radius: 10px;
+ margin-bottom: 30px;
+
+ p {
+ text-align: center;
+ font-size: 14px;
+ }
+ }
+
+ .total_price {
+ background-color: $base-color-lightgray;
+ border-radius: 10px;
+ height: 100px;
+ margin-bottom: 30px;
+
+ .total_price_container {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 100%;
+ font-size: 18px;
+ gap: 6px;
+
+ strong {
+ font-weight: 600;
+ }
+
+ .plus,
+ .equal {
+ svg {
+ path {
+ color: $point-color-mint;
+ }
+ }
+ margin: 0 8px 0;
+ }
+ }
+ }
+
+ .buttons {
+ display: flex;
+ justify-content: center;
+ gap: 10px;
+
+ .btn {
+ width: 200px;
+ height: 50px;
+ border-radius: 10px;
+ border-style: none;
+ cursor: pointer;
+ }
+ .btn_selected {
+ background-color: $base-color-gray;
+ }
+ .btn_selectedAll {
+ background-color: $point-color-pink;
+ }
+ }
+ }
+}
diff --git a/src/styles/Cart/CartList.module.scss b/src/styles/Cart/CartList.module.scss
new file mode 100644
index 00000000..cb128238
--- /dev/null
+++ b/src/styles/Cart/CartList.module.scss
@@ -0,0 +1,85 @@
+@import "../common/colors.scss";
+@import "../common/fonts.scss";
+
+.cartList {
+ .container {
+ width: 100%;
+ font-family: "Pretendard";
+
+ .cartItem {
+ display: grid;
+ grid-template-columns: 0.5fr 1fr 2fr 0.5fr repeat(2, 1fr) 0.5fr;
+ align-items: center;
+ min-width: 1000px;
+ max-width: 1440px;
+ padding: 20px 0 20px;
+ margin-bottom: 20px;
+ border: 1px solid $base-color-gray;
+ border-radius: 10px;
+ text-align: center;
+
+ a {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ .itemImg {
+ width: 100px;
+ height: 100px;
+
+ img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ }
+ }
+ }
+
+ .itemTitle {
+ span {
+
+ }
+ }
+
+ .itemQuantity {
+ span {
+
+ }
+ }
+
+ .itemPrice {
+ display: flex;
+ flex-direction: column;
+
+ .discountPrice {
+
+ }
+
+ .originalPrice {
+ text-decoration: line-through;
+ }
+ }
+
+ .totalPrice {
+
+ }
+
+ .deleteBtn {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ cursor: pointer;
+
+ svg {
+ path {
+ padding: 20px;
+ &:hover {
+ color: $point-color-red;
+ }
+ }
+ }
+
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/styles/Home/Home.module.scss b/src/styles/Home/Home.module.scss
new file mode 100644
index 00000000..8b897865
--- /dev/null
+++ b/src/styles/Home/Home.module.scss
@@ -0,0 +1,16 @@
+@import "../common/colors.scss";
+@import "../common/fonts.scss";
+
+.main {
+ position: relative;
+ width: 100vw;
+ height: calc(100vh - (100px + 150px));
+ display:flex;
+ justify-content: center;
+ align-items: center;
+
+ .container {
+ position: relative;
+ min-height: calc(100vh - (100px + 150px));
+ }
+}
diff --git a/src/styles/Loading.module.scss b/src/styles/Loading.module.scss
new file mode 100644
index 00000000..8f65e664
--- /dev/null
+++ b/src/styles/Loading.module.scss
@@ -0,0 +1,64 @@
+@import './common/colors.scss';
+@import './common/fonts.scss';
+
+@keyframes walking {
+ 0% {
+ left: -200px;
+ }
+ 100% {
+ left: -50px;
+ }
+}
+
+.loading {
+ position: fixed;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ margin: auto auto;
+ width: 100vw;
+ height: 100vh;
+ background-color: rgb(0, 0, 0, 0.5);
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ z-index: 9;
+
+ .container {
+ position: relative;
+ display: flex;
+
+ .car {
+ position: absolute;
+ top: 48px;
+ animation: walking 2s linear infinite alternate;
+ animation-direction: normal;
+
+ svg {
+ width: 50px;
+ height: 50px;
+
+ path {
+ color: $point-color-mint;
+ }
+
+ circle {
+ color: $point-color-mint;
+ }
+ }
+ }
+
+ .house {
+ svg {
+ width: 100px;
+ height: 100px;
+
+ path {
+ color: $point-color-mint;
+ }
+ }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/styles/Login/Login.module.scss b/src/styles/Login/Login.module.scss
new file mode 100644
index 00000000..4f8002ff
--- /dev/null
+++ b/src/styles/Login/Login.module.scss
@@ -0,0 +1,114 @@
+@import '../common/colors.scss';
+@import '../common/fonts.scss';
+
+* {
+ margin: 0;
+ padding: 0;
+ font-style: $font-login;
+ font-size: $font-login-size;
+ font-weight: $font-login-weight;
+}
+
+.login {
+ position: relative;
+ width: 100vw;
+ height: 700px;
+ display: flex;
+ justify-content: center;
+
+ .wrapper {
+ position: relative;
+
+ .form {
+ height: 300px;
+ margin: 25px;
+
+ h2 {
+ position: relative;
+ margin: 0 auto;
+ font-size: 24px;
+ font-weight: 700;
+ display: block;
+ width: fit-content;
+ top: 30px;
+ }
+
+ form {
+ display: block;
+ position: relative;
+ width: fit-content;
+ margin: 0 auto;
+ top: 100px;
+
+ .id,
+ .pwd {
+ width: fit-content;
+ position: block;
+ margin: 0 auto;
+ border-bottom: solid 1px;
+ padding: 20px;
+ input {
+ border: none;
+ }
+ }
+
+ .id {
+ display: flex;
+ gap: 39px;
+ }
+
+ .pwd {
+ display: flex;
+ gap: 30px;
+ }
+ }
+
+ .find {
+ position: relative;
+ width: fit-content;
+ margin: 0 auto;
+ top: 100px;
+ display: flex;
+ gap: 20px;
+
+ p {
+ font-size: 12px;
+ color: $base-color-gray;
+ cursor: pointer;
+ }
+ }
+ }
+
+ .signup {
+ position: relative;
+ top: 120px;
+ width: fit-content;
+ margin: 0 auto;
+
+ p {
+ display: block;
+ width: fit-content;
+ margin: 0 auto;
+ font-size: 12px;
+ line-height: 1.5;
+ }
+ }
+
+ button {
+ width: 430px;
+ height: 50px;
+ border-radius: 10px;
+ border-style: none;
+ cursor: pointer;
+ margin-bottom: 20px;
+ margin-top: 30px;
+ }
+ .btn__login {
+ background-color: $base-color-taupe;
+ }
+ .btn__signup {
+ background-color: $base-color-black;
+ color: white;
+ }
+ }
+}
diff --git a/src/styles/Mypage/Account.module.scss b/src/styles/Mypage/Account.module.scss
new file mode 100644
index 00000000..cb23e76c
--- /dev/null
+++ b/src/styles/Mypage/Account.module.scss
@@ -0,0 +1,31 @@
+@import '../common/colors.scss';
+@import '../common/fonts.scss';
+
+.account {
+ width: 430px;
+ height: 50px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ border: 1px solid #333;
+ border-radius: 10px;
+ margin: 10px 0;
+ color: #333;
+
+ .wrapper {
+ width: 90%;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+
+ .account_details {
+ display: flex;
+ gap: 10px;
+ }
+
+ .deleteBtn {
+ font-size: 20px;
+ cursor: pointer;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/styles/Mypage/AccountModal.module.scss b/src/styles/Mypage/AccountModal.module.scss
new file mode 100644
index 00000000..faa6720d
--- /dev/null
+++ b/src/styles/Mypage/AccountModal.module.scss
@@ -0,0 +1,123 @@
+@import '../common/colors.scss';
+@import '../common/fonts.scss';
+
+.title {
+ display: flex;
+ justify-content: center;
+ margin-bottom: 40px;
+ font-size: 24px;
+ font-weight: 700;
+}
+
+.btn {
+ width: 160px;
+ height: 50px;
+ border-radius: 10px;
+ border-style: none;
+ cursor: pointer;
+}
+
+.accountModal {
+ position: fixed;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ margin: auto auto;
+ width: 100%;
+ height: 100%;
+ background-color: rgb(0, 0, 0, 0.2);
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ form {
+ padding: 30px;
+ max-width: 700px;
+ max-height: 900px;
+ border-radius: 10px;
+ background-color: #fff;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+
+ .paymentContainer {
+ display: flex;
+ justify-content: center;
+ gap: 20px;
+ margin: 20px 0;
+
+ li {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ transition: all .2s ease-in-out;
+ cursor: pointer;
+
+ &:hover {
+ transform: scale(1.1);
+ }
+
+ img {
+ height: 50px;
+ }
+
+ p {
+ margin-top: 6px;
+ font-size: 10px;
+ }
+ }
+ }
+
+ .guide {
+ color: $point-color-red;
+ font-size: 12px;
+ }
+
+ .infoWrap {
+ margin: 30px 0 10px 50px;
+ width: 400px;
+
+ label {
+ display: flex;
+ font-size: 14px;
+ gap: 15px;
+ margin-bottom: 16px;
+
+ input {
+ text-align: center;
+ width: 60px;
+ border-top: none;
+ border-left: none;
+ border-right: none;
+ border-bottom: 1px solid $base-color-black;
+ outline-color: $point-color-mint;
+ }
+ }
+ }
+
+ .agreementCheck {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+
+ label {
+ border: none;
+ }
+
+ p{
+ font-size: 14px;
+ }
+ }
+
+ .btnWrap {
+ margin-top: 20px;
+
+ .registrationBtn {
+ background-color: $base-color-black;
+ color: $base-color-white;
+ margin-left: 10px;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/styles/Mypage/MyBankAccount.module.scss b/src/styles/Mypage/MyBankAccount.module.scss
new file mode 100644
index 00000000..a3f2bcf7
--- /dev/null
+++ b/src/styles/Mypage/MyBankAccount.module.scss
@@ -0,0 +1,44 @@
+@import '../common/colors.scss';
+@import '../common/fonts.scss';
+
+.title {
+ display: flex;
+ justify-content: center;
+ margin-bottom: 40px;
+ font-size: 24px;
+ font-weight: 700;
+}
+.btn {
+ width: 430px;
+ height: 50px;
+ border-radius: 10px;
+ border-style: none;
+ cursor: pointer;
+}
+
+.accountList {
+ margin: 50px 0;
+ height: 50%;
+ display: flex;
+ justify-content: center;
+
+ .noAccount {
+ display: flex;
+ justify-content: center;
+ margin-bottom: 20px;
+ padding: 20px 0;
+
+ .textWrap {
+ p {
+ text-align: center;
+ color: $point-color-red;
+ margin-bottom: 5px;
+ }
+ }
+ }
+
+ .btn {
+ background-color: $base-color-black;
+ color: $base-color-white;
+ }
+}
\ No newline at end of file
diff --git a/src/styles/Mypage/MyInfo.module.scss b/src/styles/Mypage/MyInfo.module.scss
new file mode 100644
index 00000000..36da9a3d
--- /dev/null
+++ b/src/styles/Mypage/MyInfo.module.scss
@@ -0,0 +1,65 @@
+@import '../common/colors.scss';
+@import '../common/fonts.scss';
+
+.title {
+ display: flex;
+ justify-content: center;
+ margin-bottom: 40px;
+ font-size: 24px;
+ font-weight: 700;
+}
+
+.btn {
+ width: 430px;
+ height: 50px;
+ border-radius: 10px;
+ border-style: none;
+ cursor: pointer;
+}
+
+.info {
+ margin: 50px 0;
+ height: 50%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ label {
+ display: flex;
+ align-items: center;
+ width: 420px;
+ height: 28px;
+ margin-bottom: 10px;
+ padding: 5px 0;
+ border-bottom: 1px solid $base-color-gray;
+ font-size: 14px;
+
+ p {
+ flex-shrink: 0;
+ width: 100px;
+ }
+
+ span {
+ color: $point-color-red;
+ font-size: 10px;
+ }
+
+ .input {
+ width: 180px;
+ height: 23px;
+ margin: 10px;
+ border: none;
+ outline: none;
+ font-size: 14px;
+ &::placeholder {
+ color: $font-color;
+ }
+
+ }
+ }
+
+ .btn {
+ background-color: $base-color-gray;
+ color: $base-color-black;
+ }
+}
\ No newline at end of file
diff --git a/src/styles/Mypage/MyOrder.module.scss b/src/styles/Mypage/MyOrder.module.scss
new file mode 100644
index 00000000..047e5a09
--- /dev/null
+++ b/src/styles/Mypage/MyOrder.module.scss
@@ -0,0 +1,84 @@
+@import "../common/colors.scss";
+@import "../common/fonts.scss";
+
+.myOrder {
+ display: flex;
+ justify-content: center;
+ margin: 50px auto;
+ min-height: calc(100vh - (100px + 150px));
+
+ .container {
+ min-width: 1000px;
+ max-width: 1440px;
+
+ .title {
+ display: flex;
+ justify-content: center;
+ margin-bottom: 40px;
+
+ h2 {
+ font-size: 24px;
+ font-weight: 700;
+ }
+ }
+
+ .list_nav {
+ margin-bottom: 10px;
+
+ .list_nav_container {
+ display: grid;
+ justify-content: center;
+ align-items: center;
+ grid-template-columns: .8fr 1fr 2fr repeat(4, 1fr);
+ width: 100%;
+ height: 60px;
+ background-color: $base-color-lightgray;
+ border-radius: 10px;
+ font-family: "Pretendard";
+ font-weight: 600;
+ text-align: center;
+ }
+ }
+
+ .content {
+ .allList {
+ .list {
+ display: grid;
+ grid-template-columns: .8fr 1fr 2fr repeat(4, 1fr);
+ justify-content: center;
+ align-items: center;
+ border: 1px solid $base-color-gray;
+ border-radius: 10px;
+ margin-bottom: 10px;
+ text-align: center;
+
+ .listImg {
+ img {
+ width: 100px;
+ height: auto;
+ }
+ }
+ }
+ .listBtn {
+ display: flex;
+ flex-direction: column;
+ gap: 4px;
+ font-family: "Pretendard";
+
+ .cancelBtn,
+ .confirmBtn {
+ width: 100px;
+ height: 26px;
+ border-radius: 10px;
+ border-style: none;
+ cursor: pointer;
+ background-color: $point-color-pink;
+ &:hover {
+ opacity: .8;
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/styles/Mypage/MyOrderDetails.module.scss b/src/styles/Mypage/MyOrderDetails.module.scss
new file mode 100644
index 00000000..69bb8daa
--- /dev/null
+++ b/src/styles/Mypage/MyOrderDetails.module.scss
@@ -0,0 +1,101 @@
+@import "../common/colors.scss";
+@import "../common/fonts.scss";
+
+.title {
+ margin-bottom: 20px;
+ font-size: 24px;
+ font-weight: 600;
+}
+
+.myOrderDetails {
+ position: fixed;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ margin: auto auto;
+ width: 100%;
+ height: 100%;
+ background-color: rgb(0, 0, 0, 0.5);
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ z-index: 9;
+
+ .container {
+ min-width: 800px;
+ min-height: 500px;
+ border-radius: 10px;
+ background-color: #fff;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ position: relative;
+
+ .closeBtn {
+ position: absolute;
+ top: 40px;
+ right: 50px;
+ cursor: pointer;
+
+ svg {
+ width: 20px;
+ height: 20px;
+ path {
+ &:hover {
+ color: $point-color-red;
+ }
+ }
+ }
+ }
+
+ .details {
+ display: flex;
+ gap: 30px;
+ margin-top: 20px;
+
+ .photo {
+ height: 320px;
+
+ img {
+ width: 100%;
+ height: 100%;
+ }
+ }
+
+ .order_content {
+ display: flex;
+ flex-direction: column;
+ justify-content: space-around;
+
+ p {
+ margin: 6px 0;
+ }
+
+ .order_number{
+ strong {
+ font-weight: 600;
+ }
+ }
+
+ .item_details {
+ margin: 20px 0;
+
+ strong {
+ font-size: 20px;
+ font-weight: 600;
+ }
+ }
+
+ .payment_details {
+ h4 {
+ font-size: 18px;
+ font-weight: 600;
+ }
+
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/styles/Mypage/Mypage.module.scss b/src/styles/Mypage/Mypage.module.scss
new file mode 100644
index 00000000..6fd1ae37
--- /dev/null
+++ b/src/styles/Mypage/Mypage.module.scss
@@ -0,0 +1,71 @@
+@import '../common/colors.scss';
+@import '../common/fonts.scss';
+
+
+.btn {
+ width: 430px;
+ height: 50px;
+ border-radius: 10px;
+ border-style: none;
+ background-color: $base-color-black;
+ color: $base-color-white;
+ cursor: pointer;
+}
+
+.mypage {
+ min-height: calc(100vh - (100px + 150px));
+
+}
+
+// κ°μΈ μ 보 μμ - PW νμΈμ°½
+.myPageConfirm {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ margin: 50px 0;
+
+ .wrapper {
+ .title {
+ display: flex;
+ justify-content: center;
+ margin-bottom: 40px;
+
+ h2 {
+ font-size: 24px;
+ font-weight: 700;
+ }
+ }
+
+ .form {
+ margin: 60px 0;
+ display: flex;
+ justify-content: center;
+
+ .PWContaniner {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ width: 420px;
+ height: 28px;
+ margin-bottom: 20px;
+ padding: 5px 0;
+ border-bottom: 1px solid #000;
+
+ p {
+ font-weight: 700;
+ }
+
+ input {
+ width: 420px;
+ height: 23px;
+ border: none;
+ outline: none;
+ font-size: 14px;
+ text-align: center;
+ }
+ }
+ }
+ }
+}
+
+
diff --git a/src/styles/NotFound/NotFound.module.scss b/src/styles/NotFound/NotFound.module.scss
new file mode 100644
index 00000000..8d768448
--- /dev/null
+++ b/src/styles/NotFound/NotFound.module.scss
@@ -0,0 +1,61 @@
+@import '../common/colors.scss';
+@import '../common/fonts.scss';
+
+.notfound {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ width: 100vw;
+ height: 100vh;
+ font-family: "Pretendard";
+
+ .container {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+
+ .textbox {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ color: $point-color-mint;
+ margin-bottom: 40px;
+
+ svg {
+ width: 100px;
+ height: 100px;
+
+ path {
+ color: $point-color-mint;
+ }
+ }
+
+ strong {
+ font-size: 80px;
+ color: $point-color-mint;
+ margin: 20px 0;
+ }
+
+ p {
+ font-size: 60px;
+ text-align: center;
+ color: $point-color-mint;color: $point-color-mint;
+ }
+ }
+
+ .btn {
+ input {
+ width: 200px;
+ height: 50px;
+ border-radius: 10px;
+ border: 1px solid $base-color-gray;
+ outline: none;
+ font-size: 20px;
+ background-color: $base-color-lightgray;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/styles/Shop/ProductItem.module.scss b/src/styles/Shop/ProductItem.module.scss
new file mode 100644
index 00000000..1ce72a26
--- /dev/null
+++ b/src/styles/Shop/ProductItem.module.scss
@@ -0,0 +1,63 @@
+@import '../common/colors.scss';
+@import '../common/fonts.scss';
+
+.productContainer {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ width: 285px;
+ height: 350px;
+ margin: 10px;
+ font-family: "Pretendard";
+
+ strong {
+ font-weight: 700;
+ font-size: 18px;
+ }
+
+ .productPhotoBox {
+ width: 285px;
+ height: 280px;
+ margin-bottom: 14px;
+
+ img {
+ width: 285px;
+ height: 280px;
+ }
+ }
+
+ .productInfo {
+ text-align: center;
+ margin-bottom: 6px;
+
+ .productName {
+ display: block;
+ font-size: 16px;
+ font-weight: 500;
+ }
+
+ strong {
+ margin-top: 5px;
+ font-size: 14px;
+ }
+ }
+
+ .productPriceBox {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ gap: 5px;
+
+ .priceDiscount {
+ font-weight: 400;
+ color: $point-color-red;
+ }
+
+ .priceThrough {
+ text-decoration: line-through;
+ font-size: 14px;
+ color: gray;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/styles/Shop/Shop.module.scss b/src/styles/Shop/Shop.module.scss
new file mode 100644
index 00000000..c36202a0
--- /dev/null
+++ b/src/styles/Shop/Shop.module.scss
@@ -0,0 +1,49 @@
+@import '../common/colors.scss';
+@import '../common/fonts.scss';
+
+.shop {
+ display:flex;
+ flex-direction:column;
+ justify-content: center;
+ align-items: center;
+ margin-bottom: 50px;
+
+ .menuWrap {
+ margin: 50px;
+
+ .menu {
+ display: flex;
+
+ input {
+ width: 130px;
+ height: 48px;
+ border: 1px solid $base-color-taupe;
+ border-radius: 38px;
+ background-color: $base-color-lightgray;
+ margin-right: 10px;
+ font-family: "Pretendard";
+ font-size: 16px;
+ font-weight: 500;
+ cursor: pointer;
+
+ .active {
+ background-color: #fadad8;
+ }
+
+ &:nth-child(4) {
+ margin-right: 0;
+ }
+ }
+
+
+ }
+ }
+
+ .productListWrap{
+ .productList {
+ display: grid;
+ grid-template-columns: repeat(4, 1fr);
+ grid-gap: 20px;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/styles/Shop/ShopDetail.module.scss b/src/styles/Shop/ShopDetail.module.scss
new file mode 100644
index 00000000..bc046ec4
--- /dev/null
+++ b/src/styles/Shop/ShopDetail.module.scss
@@ -0,0 +1,153 @@
+@import '../common/colors.scss';
+@import '../common/fonts.scss';
+
+.product {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ width: 100vw;
+ min-height: calc(100vh - (100px + 150px));
+ margin: 50px 0 50px;
+ font-family: "Pretendard";
+
+ .infoContainer {
+ display: flex;
+ justify-content: center;
+
+ .productImg {
+ margin-right: 100px;
+ width: 500px;
+ height: 500px;
+
+ img {
+ width: 100%;
+ height: 100%;
+ object-fit: center;
+ }
+ }
+
+ .productInfo {
+ color: $font-color;
+
+ .productText {
+ .tags {
+ margin-bottom: 30px;
+ font-family: "Markazi Text", serif;
+ font-size: 18px;
+ }
+
+ .title {
+ margin-bottom: 14px;
+ font-size: 24px;
+ font-weight: 600;
+ }
+
+ .discountPrice {
+ margin-bottom: 6px;
+ font-size: 22px;
+ font-weight: 400;
+ }
+
+ .price {
+ margin-bottom: 18px;
+
+ .originalPrice {
+ margin-right: 6px;
+ font-size: 18px;
+ text-decoration: line-through;
+ }
+
+ .discountRate {
+ font-size: 20px;
+ color: $point-color-red;
+ }
+ }
+
+ .description {
+ margin-bottom: 20px;
+ }
+ }
+
+ .productCount {
+ margin-bottom: 20px;
+
+ .countBox {
+ display: flex;
+ margin-bottom: 30px;
+
+ .count {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width: 40px;
+ border: 1px solid $base-color-gray;
+ font-size: 18px;
+ font-weight: 600;
+ text-align: center;
+ }
+
+ .plusBtn,
+ .minusBtn {
+ width: 40px;
+ height: 40px;
+ background-color: $base-color-lightgray;
+ border: 1px solid $base-color-gray;
+ }
+ }
+
+ .countPrice {
+ p {
+ margin-bottom: 6px;
+ }
+
+ span {
+ font-size: 24px;
+ }
+ }
+ }
+
+ .buttons {
+ .btn {
+ width: 200px;
+ height: 50px;
+ border-radius: 10px;
+ border-style: none;
+ cursor: pointer;
+ }
+
+ .buy {
+ margin-right: 8px;
+ background-color: $point-color-pink;
+ color: $base-color-black;
+ }
+ .cart {
+ background-color: $base-color-gray;
+ color: $base-color-black;
+ }
+ }
+ }
+ }
+
+ .detailContainer {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ margin: 80px 0;
+
+ .detailTitle {
+ span {
+ font-size: 24px;
+ font-weight: 600;
+ }
+ }
+
+ .detailDescription {
+ p {
+ margin: 40px 0 50px;
+ }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/styles/SignUp/SignUp.module.scss b/src/styles/SignUp/SignUp.module.scss
new file mode 100644
index 00000000..e21cee99
--- /dev/null
+++ b/src/styles/SignUp/SignUp.module.scss
@@ -0,0 +1,82 @@
+@import '../common/colors.scss';
+@import '../common/fonts.scss';
+
+.container {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ margin: 50px 0;
+
+ .title {
+ display: flex;
+ justify-content: center;
+ margin-bottom: 40px;
+ font-size: 24px;
+ font-weight: 700;
+ }
+
+ .label {
+ position: relative;
+ .input {
+ width: 430px;
+ height: 28px;
+ border: 1px solid #d5d5d5;
+ color: $font-color;
+ font-size: 14px;
+ outline: none;
+ background: none;
+ margin-bottom: 20px;
+ border-bottom: $base-color-gray 1px solid;
+ border-left: none;
+ border-right: none;
+ border-top: none;
+ &::placeholder {
+ color: $font-color;
+ }
+ }
+ span {
+ font-size: 12px;
+ color: $point-color-red;
+ position: absolute;
+ right: 0;
+ }
+ }
+
+
+ .agree {
+ margin: 40px 0;
+ width: 400px;
+ height: 100%;
+ font-size: 12px;
+
+ .checkBox {
+ display: flex;
+ gap: 10px;
+ font-size: 14px;
+ margin-bottom: 10px;
+ }
+
+ .agreeContainer {
+ display: flex;
+ justify-content: center;
+ width: 430px;
+ padding: 20px;
+ border-radius: 10px;
+ background-color: $base-color-gray;
+ box-sizing: border-box;
+ .agreeText{
+ width: 90%;
+ }
+ }
+ }
+
+ .btn {
+ width: 430px;
+ height: 50px;
+ border-radius: 10px;
+ border-style: none;
+ background-color: $base-color-black;
+ color: $base-color-white;
+ cursor: pointer;
+ }
+}
\ No newline at end of file
diff --git a/src/styles/SubNav.module.scss b/src/styles/SubNav.module.scss
new file mode 100644
index 00000000..f6c71d6e
--- /dev/null
+++ b/src/styles/SubNav.module.scss
@@ -0,0 +1,25 @@
+@import "./common/colors.scss";
+@import "./common/fonts.scss";
+
+.subnav {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 50px;
+ border-bottom: 1px solid $base-color-gray;
+ background-color: $base-color-lightgray;
+ font-family: "Pretendard";
+
+ .container {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ width: 75%;
+ max-width: 1440px;
+ gap: 50px;
+
+ .category {
+ cursor: pointer;
+ }
+ }
+}
diff --git a/src/styles/TheFooter.module.scss b/src/styles/TheFooter.module.scss
new file mode 100644
index 00000000..b7b0ec5d
--- /dev/null
+++ b/src/styles/TheFooter.module.scss
@@ -0,0 +1,86 @@
+@import './common/colors.scss';
+@import './common/fonts.scss';
+
+* {
+ margin: 0;
+ padding: 0;
+ color: $font-color;
+ font-family: 'Pretendard-Regular';
+}
+
+footer {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ // position: fixed;
+ // bottom: 0;
+ width: 100vw;
+ height: 150px;
+ background-color: $base-color-lightgray;
+
+ .container {
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+ align-items: center;
+ width: 90%;
+ max-width: 1440px;
+ margin-top: 20px;
+
+ ul {
+ display: flex;
+ flex-shrink: 0;
+ justify-content: space-evenly;
+ gap: 60px;
+
+ .logo {
+ width: 200px;
+
+ h1 {
+ font-family: $font-logo;
+ font-size: $font-logo-size;
+ }
+ }
+
+ .company,
+ .bank,
+ .customer {
+ div {
+ display: flex;
+ flex-direction: column;
+ font-size: 12px;
+
+ h2 {
+ font-weight: 700;
+ margin-bottom: 10px;
+ }
+
+ span {
+ line-height: 1.6em;
+ }
+ }
+ }
+
+ .tel {
+ div {
+ display: flex;
+ flex-direction: column;
+ font-size: 12px;
+
+ h2 {
+ font-size: 20px;
+ font-weight: 700;
+ margin-bottom: 10px;
+ }
+
+ span {
+ line-height: 1.6em;
+ }
+ }
+ }
+ @media (min-width: 1300px) {
+ gap: 100px;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/styles/TheHeader.module.scss b/src/styles/TheHeader.module.scss
new file mode 100644
index 00000000..12351b0a
--- /dev/null
+++ b/src/styles/TheHeader.module.scss
@@ -0,0 +1,124 @@
+@import "./common/colors.scss";
+@import "./common/fonts.scss";
+
+* {
+ margin: 0;
+ padding: 0;
+}
+
+a {
+ text-decoration: none;
+}
+
+header {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width: 100vw;
+ height: 100px;
+ border-bottom: solid 0.8px $base-color-gray;
+ padding-left: 40px;
+
+ .container {
+ position: relative;
+ display: flex;
+ width: 90%;
+ max-width: 1440px;
+ min-width: 1250px;
+
+ .logo {
+ display: flex;
+ align-items: center;
+ height: 50px;
+ margin-left: 70px;
+ margin-right: 70px;
+ font-family: $font-logo;
+ font-size: $font-logo-size;
+ }
+
+ .navbar {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ height: 50px;
+ right: 400px;
+ font-family: $font-nav;
+ font-size: $font-nav-size;
+ font-weight: $font-nav-weight;
+
+ ul {
+ display: flex;
+ justify-content: center;
+ gap: 50px;
+ list-style: none;
+
+ .menu {
+ font-family: $font-nav;
+ font-size: $font-nav-size;
+ font-weight: 100;
+ }
+
+ .active {
+ color: $point-color-mint;
+ }
+ }
+ }
+
+ .subNav {
+ position: absolute;
+ right: 0px;
+ height: 70px;
+ margin-right: 70px;
+
+ .user {
+ font-family: $font-login;
+ font-size: $font-login-size;
+ font-weight: $font-login-weight;
+ margin-bottom: 12px;
+
+ .userLogin {
+ cursor: pointer;
+ }
+
+ .userLogout {
+ cursor: pointer;
+ margin-left: 40px;
+ }
+
+ .userSignUp {
+ margin-left: 20px;
+ &::before {
+ content: "|";
+ margin-right: 20px;
+ }
+ }
+ }
+
+ .icons {
+ position: relative;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ gap: 30px;
+
+ .mypage,
+ .shoppingbag {
+ font-size: 20px;
+ }
+
+ .search {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ .searchIcon {
+ cursor: pointer;
+ width: 20px;
+ height: 24px;
+ transform: scale(1.3);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/styles/TheModal.module.scss b/src/styles/TheModal.module.scss
new file mode 100644
index 00000000..5e0cf32e
--- /dev/null
+++ b/src/styles/TheModal.module.scss
@@ -0,0 +1,82 @@
+@import "./common/colors.scss";
+@import "./common/fonts.scss";
+
+.modal {
+ position: fixed;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ margin: auto;
+ width: 100%;
+ height: 100%;
+ background-color: rgba(0, 0, 0, 0.2);
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ .container {
+ position: relative;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ min-width: 500px;
+ min-height: 500px;
+ border-radius: 10px;
+ background-color: $base-color-white;
+
+ .title{
+ margin-bottom: 30px;
+
+ h2 {
+ font-family: $font-main;
+ font-size: $font-main-size;
+ font-weight: bold;
+ }
+ }
+
+ .contents {
+ gap: 10px;
+
+ label {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 12px;
+ input {
+ width: 200px;
+ text-align: center;
+ }
+ }
+
+ .editBtn {
+ width: 100px;
+ height: 26px;
+ border-radius: 10px;
+ border-style: none;
+ margin-top: 20px;
+ cursor: pointer;
+ background-color: $point-color-pink;
+ font-family: "Pretendard";
+ &:hover {
+ opacity: .8;
+ }
+ }
+ }
+
+ .closeBtn {
+ position: absolute;
+ right: 20px;
+ top: 20px;
+
+ svg {
+ path {
+ &:hover {
+ color: $point-color-red;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/styles/TheSearchBar.module.scss b/src/styles/TheSearchBar.module.scss
new file mode 100644
index 00000000..23fdd990
--- /dev/null
+++ b/src/styles/TheSearchBar.module.scss
@@ -0,0 +1,45 @@
+@import "./common/colors.scss";
+@import "./common/fonts.scss";
+
+.searchContainer {
+ position: absolute;
+ top: 0;
+ right: 20px;
+ z-index: 9;
+ font-family: "Pretendard";
+
+ .search {
+ display: flex;
+ position: relative;
+ gap: 5px;
+
+ .searchBar {
+ border: 1px solid $base-color-gray;
+ width: 180px;
+ height: 28px;
+ outline: none;
+ font-size: 0.8rem;
+ padding: 4px 4px 4px 6px;
+ box-sizing: border-box;
+ margin-right: 8px;
+ }
+ }
+
+ .searchForm {
+ display: flex;
+ align-items: center;
+ width: 180px;
+ min-height: 32px;
+ border: 1px solid $base-color-gray;
+ border-top: none;
+ background-color: $base-color-lightgray;
+ padding: 4px 4px 4px 6px;
+ box-sizing: border-box;
+ margin-right: 10px;
+ font-size: 14px;
+
+ .none {
+ display: none;
+ }
+ }
+}
diff --git a/src/styles/common/colors.scss b/src/styles/common/colors.scss
new file mode 100644
index 00000000..814330f4
--- /dev/null
+++ b/src/styles/common/colors.scss
@@ -0,0 +1,19 @@
+/*******************************************************************
+// μμΉ : src/styles/common/colors.scss
+// μ€λͺ
: κ° μμμ μ μ©λ κ³΅ν΅ μμ SCSSλ₯Ό νκ³³μ λͺ¨μμ κ΄λ¦¬ν©λλ€.
+********************************************************************/
+
+// λ² μ΄μ€ μμ (base colors)
+$base-color-white: #FCFCFC;
+$base-color-lightgray: #F6F6F6;
+$base-color-gray: #D9D9D9;
+$base-color-taupe: #AFA8A8;
+$base-color-black: #333333;
+
+// ν¬μΈνΈ μμ (point colors)
+$point-color-mint: #41D3BD;
+$point-color-red: #E71D36;
+$point-color-pink: #FADAD8;
+
+// ν°νΈ κΈ°λ³Έ μ μ© μμ (font color)
+$font-color: #333333;
\ No newline at end of file
diff --git a/src/styles/common/fonts.scss b/src/styles/common/fonts.scss
new file mode 100644
index 00000000..f0bd2a8b
--- /dev/null
+++ b/src/styles/common/fonts.scss
@@ -0,0 +1,45 @@
+/*******************************************************************
+// μμΉ : src/styles/common/fonts.scss
+// μ€λͺ
: κ° μμμ μ μ©λ κ³΅ν΅ ν°νΈ SCSSλ₯Ό νκ³³μ λͺ¨μμ κ΄λ¦¬ν©λ.
+********************************************************************/
+
+/******* ν°νΈ 리μ€νΈ (Font List) *******/
+// Pretendard
+@font-face {
+ font-family: "Pretendard-Regular";
+ src: url("https://cdn.jsdelivr.net/gh/Project-Noonnu/noonfonts_2107@1.1/Pretendard-Regular.woff")
+ format("woff");
+ font-weight: 400;
+ font-style: normal;
+}
+
+// Poiret One (Logo)
+@import url("https://fonts.googleapis.com/css2?family=Poiret+One&display=swap");
+
+// Markazi Text
+@import url("https://fonts.googleapis.com/css2?family=Markazi+Text:wght@400;500;600;700&display=swap");
+
+
+/******* λ³μ 리μ€νΈ (Variables) *******/
+// Logo (λν λ‘κ³ κ΄λ ¨ ν°νΈ/μ¬μ΄μ¦)
+$font-logo: "Poiret One";
+$font-logo-size: 30px;
+
+// Navbar (λ€λΉκ²μ΄μ
λ° κ΄λ ¨ ν°νΈ/μ¬μ΄μ¦)
+$font-nav: "Pretendard";
+$font-nav-size: 22px;
+$font-nav-weight: 100;
+
+// Login, Logout, Sign-In (λ‘κ·ΈμΈ, λ‘κ·Έμμ, νμκ°μ
κ΄λ ¨ ν°νΈ/μ¬μ΄μ¦)
+// loginμΌλ‘ ν΅μΌνκ² μ΅λλ€.
+$font-login: "Markazi Text", serif;
+$font-login-size: 16px;
+$font-login-weight: 400;
+
+// Button (λ²νΌ κ΄λ ¨ ν°νΈ/μ¬μ΄μ¦)
+$font-btn: "Pretendard-Regular";
+$font-btn-size: 16px;
+
+// νμ΄μ§λ³ λν ν
μ€νΈ (e.g. νμκ°μ
, κ°μΈμ 보μμ λ±)
+$font-main: "Pretendard-Regular";
+$font-main-size: 24px;
\ No newline at end of file
diff --git a/src/styles/utils/Slider.module.scss b/src/styles/utils/Slider.module.scss
new file mode 100644
index 00000000..e657bfc9
--- /dev/null
+++ b/src/styles/utils/Slider.module.scss
@@ -0,0 +1,32 @@
+@import "../common/colors.scss";
+@import "../common/fonts.scss";
+
+// width: 1288px;
+// height: 578px;
+
+.slider {
+ position: relative;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ width: 1288px;
+ height: calc(width / 4 * 3);
+ max-width: 1440px;
+ max-height: calc(100vh - (100px + 150px));
+
+ .slides {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width: 100%;
+ height: 100%;
+ max-height: calc(100vh - (100px + 150px));
+
+ .images {
+ width: 100%;
+ height: 100%;
+ object-fit: contain;
+ }
+ }
+}
diff --git a/src/utils/convert.ts b/src/utils/convert.ts
new file mode 100644
index 00000000..99027bcd
--- /dev/null
+++ b/src/utils/convert.ts
@@ -0,0 +1,39 @@
+/*******************************************************************
+// μμΉ : src/utils/convert.ts
+// μ€λͺ
: νλ‘μ νΈ μ λ°μ κ±Έμ³ μμ£Ό μ¬μ©λλ ν¨μλ₯Ό ν κ³³μ λͺ¨μμ κ΄λ¦¬ν©λλ€.
+********************************************************************/
+
+// ν μΈ κ°κ²© κ³μ°
+const discountPrice = (productPrice: number, productDiscount: number) => {
+ return productPrice * ((100 - productDiscount) / 100);
+};
+
+// ν μΈ μ κ°κ²© κ³μ°
+const priceBeforeDiscount = (price:number, discountRate:number) => {
+ return price * 100 / (100 - discountRate)
+};
+
+// κΈμ‘ λ¨μ νμ
+const convertPrice = (price: number) => {
+ return price?.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
+};
+
+// λ μ§ νμ λ³κ²½
+const convertDate = (dateBody: string) => {
+ const date = new Date(dateBody);
+ const year = String(date.getFullYear()).padStart(2, "0");
+ const month = String(date.getMonth() + 1).padStart(2, "0");
+ const today = String(date.getDate()).padStart(2, "0");
+ const hour = String(date.getHours()).padStart(2, "0");
+ const min = String(date.getMinutes()).padStart(2, "0");
+ return `${year}.${month}.${today} | ${hour}:${min}`;
+};
+
+// λ μ§ μ λ ¬
+const sortDate = (dateBody: string) => {
+ const date = new Date(dateBody);
+ const times = date.getTime();
+ return times;
+}
+
+export { priceBeforeDiscount, discountPrice, convertPrice, convertDate, sortDate };
\ No newline at end of file
diff --git a/src/utils/slider.tsx b/src/utils/slider.tsx
new file mode 100644
index 00000000..9db31a53
--- /dev/null
+++ b/src/utils/slider.tsx
@@ -0,0 +1,51 @@
+import { Swiper, SwiperSlide } from "swiper/react";
+import {
+ Navigation,
+ Pagination,
+ Scrollbar,
+ A11y,
+ Autoplay,EffectFade
+} from "swiper";
+import "swiper/swiper-bundle.min.css";
+import main1 from "/public/assets/Home/main1.jpeg";
+import main2 from "/public/assets/Home/main2.jpeg";
+import main3 from "/public/assets/Home/main3.jpeg";
+import styles from "~/styles/utils/Slider.module.scss";
+
+export const Slider = ({}) => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
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/tsconfig.json b/tsconfig.json
new file mode 100644
index 00000000..bbf19996
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,32 @@
+{
+ "compilerOptions": {
+ "baseUrl": ".",
+ "paths": {
+ "~/*": ["src/*"]
+ },
+ "target": "ES2020",
+ "moduleResolution": "node",
+ "useDefineForClassFields": true,
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
+ "module": "ESNext",
+ "skipLibCheck": true,
+
+ /* Bundler mode */
+ // "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "noEmit": true,
+ "jsx": "react-jsx",
+ "allowSyntheticDefaultImports": true,
+ "esModuleInterop": true,
+
+ /* Linting */
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "include": ["src"],
+ "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..170c7971
--- /dev/null
+++ b/vite.config.ts
@@ -0,0 +1,15 @@
+import { defineConfig } from "vite";
+import react from "@vitejs/plugin-react";
+import path from "path";
+
+// https://vitejs.dev/config/
+export default defineConfig({
+ plugins: [react()],
+ base: "/sweethome",
+ resolve: {
+ alias: {
+ "~": path.resolve(__dirname, "./src")
+ }
+ },
+
+});