diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
new file mode 100644
index 00000000..62a81b5e
--- /dev/null
+++ b/.github/workflows/deploy.yml
@@ -0,0 +1,34 @@
+name: Deploy
+
+on:
+ push:
+ branches: ['develop']
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ container: pandoc/latex
+ steps:
+ - uses: actions/checkout@v2
+
+ - name: Install mustache (to update the date)
+ run: apk add ruby && gem install mustache
+
+ - name: creates output
+ run: sh ./build.sh
+
+ - name: Pushes to another repository
+ id: push_directory
+ uses: cpina/github-action-push-to-another-repository@main
+ env:
+ API_TOKEN_GITHUB: ${{ secrets.AUTO_ACTIONS }}
+ with:
+ source-directory: 'output'
+ destination-github-username: waldls
+ destination-repository-name: DeviceLife_Frontend
+ user-email: ${{ secrets.EMAIL }}
+ commit-message: ${{ github.event.commits[0].message }}
+ target-branch: develop
+
+ - name: Test get variable exported by push-to-another-repository
+ run: echo $DESTINATION_CLONED_DIRECTORY
\ No newline at end of file
diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml
new file mode 100644
index 00000000..42f2cea6
--- /dev/null
+++ b/.github/workflows/preview.yml
@@ -0,0 +1,43 @@
+name: Preview
+
+on:
+ pull_request:
+ branches: ['develop']
+
+jobs:
+ vercel-preview:
+ runs-on: ubuntu-latest
+
+ env:
+ VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
+ VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
+
+ steps:
+ - uses: actions/checkout@v4
+ - name: Install Vercel CLI
+ run: npm install --global vercel@latest && npm install --global pnpm
+ - name: Get Vercel Environment Variables
+ run: vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }}
+ - name: Build Project Artifacts
+ run: vercel build --token=${{ secrets.VERCEL_TOKEN }}
+ - name: Deploy Project Artifacts to Vercel
+ id: deploy
+
+ run: |
+
+ vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }} > vercel-output.txt
+ echo "preview_url=$(cat vercel-output.txt)" >> $GITHUB_OUTPUT
+
+ - name: Comment PR with Preview URL
+ uses: thollander/actions-comment-pull-request@v2
+ with:
+ message: |
+ โ
PREVIEW ${{ steps.deploy.outputs.preview_url }}
+
+permissions:
+ contents: read
+ pages: write
+ deployments: write
+ id-token: write
+ issues: write
+ pull-requests: write
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index bb92d236..56f49d75 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,3 +24,5 @@ dist-ssr
*.sln
*.sw?
.env
+.vercel
+.env*.local
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 4b519d63..4189f115 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,5 +1,10 @@
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
- "eslint.validate": ["typescript", "typescriptreact"]
+ "eslint.validate": ["typescript", "typescriptreact"],
+
+ "[typescript]": { "editor.formatOnSave": false },
+ "[typescriptreact]": { "editor.formatOnSave": false },
+
+ "prettier.prettierPath": "./node_modules/prettier"
}
diff --git a/README.md b/README.md
index 28c1fdc3..9bd9036a 100644
--- a/README.md
+++ b/README.md
@@ -1,75 +1,82 @@
# ๐ฑDevice Life - Frontend
-> ์๋ง์ ๋๋ฐ์ด์ค ์ค ์ ์ ์๊ฒ ์ต์ ์ ์กฐํฉ์ ์ ๊ณตํ๋ค
+> ์ต์ ์ ๊ธฐ๊ธฐ์กฐํฉ ์น ์๋น์ค
> UMC 9th Project - Client Repository
+
+
## ๐ ํ๋ก์ ํธ ์๊ฐ (Project Overview)
-์ด ์ ์ฅ์๋ Device Life์ ํด๋ผ์ด์ธํธ ์ ํ๋ฆฌ์ผ์ด์
์ฝ๋๋ฅผ ๊ด๋ฆฌํฉ๋๋ค. ์ฌ์ฉ์๊ฐ ์ง๊ด์ ์ผ๋ก ๊ธฐ๊ธฐ๋ฅผ ํ์ํ๊ณ , ์กฐํฉ์ ์์ฑํ๋ฉฐ, ์ค์๊ฐ์ผ๋ก ์๊ฐ์ ์ธ ํ๊ฐ ํผ๋๋ฐฑ์ ๋ฐ์ ์ ์๋ UI/UX ๊ตฌํ์ ์ง์คํฉ๋๋ค.
+์ด ์ ์ฅ์๋ ์ต์ ์ ๊ธฐ๊ธฐ ์กฐํฉ ์ถ์ฒ ์๋น์ค 'Device Life'์ ์น ํด๋ผ์ด์ธํธ ์ฝ๋๋ฅผ ๊ด๋ฆฌํฉ๋๋ค. ์ฌ์ฉ์๊ฐ ์๋ง์ ์ค๋งํธ ๊ธฐ๊ธฐ ์ฌ์ด์์ ์์ ์๊ฒ ๋ง๋ ์ต์ ์ ์กฐํฉ์ ์ฐพ์ ์ ์๋๋ก, ์ง๊ด์ ์ธ ํ์ ๊ฒฝํ๊ณผ ๋ก์ง ๊ธฐ๋ฐ์ ์ค์๊ฐ ํ๊ฐ ํผ๋๋ฐฑ์ ์ ๊ณตํ๋ ์์ฑ๋ ๋์ UI/UX ๊ตฌํ์ ์ง์คํฉ๋๋ค.
### โจ ํ๋ก ํธ์๋ ํต์ฌ ๊ธฐ๋ฅ (Key Features)
-* ์กฐํฉ ์ํฌ์คํ์ด์ค UI: ๊ธฐ๊ธฐ ์ถ๊ฐ/์ญ์ ์ ๋ถ๋๋ฌ์ด ์ธํฐ๋์
๋ฐ ์ํ ๊ด๋ฆฌ ๊ตฌํ
-* ์ค์๊ฐ ํ๊ฐ ํผ๋๋ฐฑ: ์ํ๊ณ, ์ถฉ์ , ์ปฌ๋ฌ ์ ์ ๋ฐ์ดํฐ๋ฅผ ์๊ฐ์ ๊ทธ๋ํ๋ ์์น๋ก ์ฆ์ ๋ ๋๋ง
-* ๊ธฐ๊ธฐ ํ์ ๋ฐ ํํฐ UI: ๊ฐ๊ฒฉ๋ ์กฐ์ ์ ์ํ Range Slider ์ปดํฌ๋ํธ ๋ฐ ์นดํ
๊ณ ๋ฆฌ ์นฉ ๊ตฌํ
-* ๋ผ์ดํ์คํ์ผ ์ ํ: ์ด๋ฏธ์ง ์นด๋ ๋ฐ ๋ธ๋๋ ๋ก๊ณ ๋ฅผ ํ์ฉํ ์ง๊ด์ ์ธ ์ฌ์ฉ์ ์
๋ ฅ ์ธํฐํ์ด์ค
-* ์ธํฐ๋์
: ๋ด ์กฐํฉ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ค์์ดํ ์ญ์ ๋ฐ ๋ชจ๋ฌ ์ ๋๋ฉ์ด์
์ฒ๋ฆฌ
+- ๋์ ์ ์ ๊ถํ ๋ฐ GNB ๋ ๋๋ง: ๋ก๊ทธ์ธ ์ ๋ฌด ๋ฐ ์จ๋ณด๋ฉ ์ํ์ ๋ฐ๋ผ ๋ฉ๋ด ๊ตฌ์ฑ๊ณผ ์ ๊ทผ ๊ถํ ์ ์ด
+- ์จ๋ณด๋ฉ ํ๋ก์ฐ: ์ ๊ท ์ ์ ๋ฅผ ์ํ ์คํ๋์ ํ๋ฉด, ๋ผ์ดํ์คํ์ผ ํ๊ทธ ์ ํ, ์ฒซ ์กฐํฉ ์์ฑ์ผ๋ก ์ด์ด์ง๋ ๋จ๊ณ๋ณ ํผ ์์ ๋ ๊ตฌํ
+- ๋ค์ค ํํฐ ๊ธฐ๋ฐ ๊ธฐ๊ธฐ ํ์: ์นดํ
๊ณ ๋ฆฌ ์นฉ, ๋จ์ผ/๋ค์ค ์ฒดํฌ๋ฐ์ค ํํฐ, 4๊ฐ์ง ์ ๋ ฌ ์ต์
์ ์กฐํฉํ ๊ฒ์ ์ธํฐํ์ด์ค ์ ๊ณต
+- ์กฐํฉ ๋ด๊ธฐ ์์คํ
: ํ์ฌ ์ ํ๋ ์กฐํฉ ์ํ๋ฅผ ์ ์งํ๋ฉฐ ์ค๋ณต ์ ์ฅ
+- ๋ผ์ดํ์คํ์ผ ์๋ ๋กํ
์ด์
: ์ ์ ์ก์
์ ๋ฐ์ํ์ฌ ์ ์ง/์ฌ์๋๋ ์๊ฐ์ ํ๊ทธ ๋กํ
์ด์
๋ฐ ๊ธฐ๊ธฐ ํ๋ ์ด์
์นด๋ ๊ตฌํ
+- ๋ก์ง ๊ธฐ๋ฐ ํ๊ฐ ๋ฆฌํฌํธ: ๊ธฐ๊ธฐ ๊ฐ ์ฐ๋์ฑ, ํธ์์ฑ, ๋ผ์ดํ์คํ์ผ ์ ํฉ๋ ๋ถ์ ๋ด์ฉ์ ๋ง์ดํ์ด์ง ๋ด ํ ์ค ํ๊ฐ ๋ฆฌํฌํธ๋ก ๋ ๋๋ง
---
+## ๐ง๐ปโ๐ป ํ์ (Contributors)
+
+|
|
|
|
+| :---------------------------------------------------------------: | :-----------------------------------------------------------------: | :---------------------------------------------------------------: |
+| ๋ฐ์ ๋ฏผ
[@waldls](https://github.com/waldls) | ์ด์ ์ฐ
[@Seony777](https://github.com/Seony777) | ์๋ณํ
[@H-un1](https://github.com/H-un1) |
+| **Frontend Lead** | **Frontend** | **Frontend** |
-## ๐ ๏ธ ๊ธฐ์ ์คํ (Tech Stack)
-| Category | Technology |
-| :--- | :--- |
-| **Language & Framework** |    |
-| **Styling** |  |
-| **State Management** | **Zustand** (Client), **TanStack Query** (Server) |
-| **Data Fetching** | Axios, TanStack Query |
-| **Tools** | ESLint, Prettier, npm |
-| **DevOps** | Git, GitHub, Vercel |
---
+## ๐ ๏ธ ๊ธฐ์ ์คํ (Tech Stack)
-## ๐ Git-flow ์ ๋ต (Git-flow Strategy)
+| ์ญํ | ์ข
๋ฅ | ์ ์ ๊ทผ๊ฑฐ |
+| :-- | :-- | :-- |
+| **Language & Framework** |    | TypeScript๋ก ํ์
์์ ์ฑ์ ํ๋ณดํ๊ณ , React ๊ธฐ๋ฐ ์ปดํฌ๋ํธ UI๋ฅผ ๊ตฌ์ฑํ์ผ๋ฉฐ, Vite์ ๋น ๋ฅธ ๋ฒ๋ค๋ง๊ณผ HMR๋ก ๊ฐ๋ฐ ์์ฐ์ฑ์ ๋์์ต๋๋ค. |
+| **Styling** |  | ์ ํธ๋ฆฌํฐ ๊ธฐ๋ฐ ์คํ์ผ๋ง์ผ๋ก ๋น ๋ฅด๊ณ ์ผ๊ด๋ UI๋ฅผ ๊ตฌํํ์ต๋๋ค. |
+| **UI Utilities** |   | SVGR๋ก SVG๋ฅผ React ์ปดํฌ๋ํธ๋ก ๊ด๋ฆฌํด ์ฌ์ฌ์ฉ์ฑ์ ๋์๊ณ , clsx๋ก ์กฐ๊ฑด๋ถ className ๋ก์ง์ ๊ฐ๊ฒฐํ๊ฒ ์ฒ๋ฆฌํ์ต๋๋ค. |
+| **State Management** |   | Zustand๋ก ํด๋ผ์ด์ธํธ ์ํ๋ฅผ ๊ฐ๋จํ ๊ด๋ฆฌํ๊ณ , TanStack Query๋ก ์๋ฒ ์ํ/์บ์ฑ์ ์ ์ธ์ ์ผ๋ก ๊ด๋ฆฌํ์ต๋๋ค. |
+| **Data Fetching** |   | Axios๋ก HTTP ์์ฒญ์ ์ฒ๋ฆฌํ๊ณ , TanStack Query๋ก ์์ฒญ ์ํ/์บ์ฑ/๋๊ธฐํ ๊ด๋ฆฌ๋ฅผ ์ํํ์ต๋๋ค. |
+| **Tools** |   | ESLint๋ก ์ฝ๋ ๊ท์น์ ํต์ผํ๊ณ , Prettier๋ก ํฌ๋งท์ ์๋ํํด ์ผ๊ด๋ ์ฝ๋ ์คํ์ผ์ ์ ์งํ์ต๋๋ค. |
+| **DevOps** |    | Git/GitHub๋ก ๋ฒ์ ๊ด๋ฆฌ ๋ฐ ํ์
์ ์งํํ๊ณ , Vercel๋ก ๋ฐฐํฌ ์๋ํ ๋ฐ CI/CD ๊ณผ์ ์ ๊ฐ์ํํ์ต๋๋ค. |
+| **Package Manager** |  | ํ์ค ํจํค์ง ๋งค๋์ (npm)๋ฅผ ์ฌ์ฉํ์ฌ ์์กด์ฑ ์ค์น ๋ฐ ๊ด๋ฆฌ๋ฅผ ์ํํ์ต๋๋ค. |
+| **Validation** |  | Zod๋ก API ์๋ต ๋ฐ ํผ ์
๋ ฅ ๊ฐ์ ์คํค๋ง ๊ธฐ๋ฐ์ผ๋ก ๊ฒ์ฆํด ๋ฐํ์ ์ค๋ฅ๋ฅผ ์ค์ด๊ณ ํ์
์์ ์ฑ์ ๊ฐํํ์ต๋๋ค. |
+| **Collaboration** |    | Notion์ ํตํ ๋ฌธ์ํ์ ํ๋ก์ ํธ ์๋ฃ ๊ด๋ฆฌ, Figma ๊ธฐ๋ฐ ๋์์ธ ํ์
, Discord๋ฅผ ํ์ฉํ ์ค์๊ฐ ์ปค๋ฎค๋์ผ์ด์
์ผ๋ก ํ ํ์
ํจ์จ์ ๋์์ต๋๋ค. |
-* main: ์ต์ข
์ ์ผ๋ก ์ฌ์ฉ์์๊ฒ ๋ฐฐํฌ๋๋ ๊ฐ์ฅ ์์ ์ ์ธ ๋ฒ์ ๋ธ๋์น
-* develop: ๋ค์ ์ถ์ ๋ฒ์ ์ ๊ฐ๋ฐํ๋ ์ค์ฌ ๋ธ๋์น. ๊ธฐ๋ฅ ๊ฐ๋ฐ ์๋ฃ ํ feature ๋ธ๋์น๋ค์ด ๋ณํฉ
-* feature: ๊ธฐ๋ฅ ๊ฐ๋ฐ์ฉ ๋ธ๋์น. develop์์ ๋ถ๊ธฐํ์ฌ ์์
---
+## ๐ ์ปจ๋ฒค์
(Conventions)
+
+- ๐ [Commit Convention](https://www.notion.so/Commit-Convention-305c82f125c980898111df6891b25578?source=copy_link)
+- ๐ชต [Branch Convention](https://www.notion.so/Branch-Convention-305c82f125c980afaecfdc5b00ad1f71?source=copy_link)
+- ๐ป [Coding Convention](https://www.notion.so/Coding-Convention-2dac82f125c980a8810bca8fadbe8b5f?source=copy_link)
+- ๐ข [API Convention](https://www.notion.so/API-Convention-2e0c82f125c9805bb0c3c22fda770978?source=copy_link)
+- ๐ [Issue Convention](https://www.notion.so/Issue-Convention-305c82f125c980029b7ce00b73962f66?source=copy_link)
+- โ
[PR Convention](https://www.notion.so/PR-Convention-305c82f125c9809e98ebe702534bf18a?source=copy_link)
+- ๐ [Folder Structure Convention](https://www.notion.so/Folder-Structure-Convention-2d4c82f125c98112bd64d946da9d2f34?source=copy_link)
-## ๐ ๋ธ๋์น ๊ท์น ๋ฐ ๋ค์ด๋ฐ (Branch Rules & Naming)
+---
-* ๋ชจ๋ ๊ธฐ๋ฅ ๊ฐ๋ฐ์ feature ๋ธ๋์น์์ ์์
-* ์์
์์ ์ , ํญ์ ์ต์ develop ๋ด์ฉ ๋ฐ์์ค๊ธฐ (git pull origin develop)
-* ์์
์๋ฃ ํ, develop์ผ๋ก Pull Request(PR) ์์ฑ
-* PR์ Reviewer(๋ฉ์
) ์ง์ ์ดํ ๋จธ์ง
-* ๋ธ๋์น ์ด๋ฆ ํ์: feature/์ด์๋ฒํธ-๊ธฐ๋ฅ๋ช
-* ์์: feature/1-login-ui
+## ๐ค ๊ทธ๋ผ์ด๋ ๋ฃฐ (Ground Rules)
+- **์ฐ๋ฝ ์์ฃผ ํ์ธํ๊ธฐ**
+ - ๋์ค์ฝ๋/์นด์นด์คํก ์๋ฆผ์ ์์ฃผ ํ์ธํฉ๋๋ค.
+
+- **์ ๊ทน์ ์ผ๋ก ์๊ฒฌ ๊ณต์ ํ๊ธฐ**
+ - ๋งํ๋ ๋ถ๋ถ์ด๋ ๋ณ๊ฒฝ ์ฌํญ์ด ์๊ธฐ๋ฉด ๋น ๋ฅด๊ฒ ๊ณต์ ํฉ๋๋ค.
+
+- **PR Merge ๊ท์น**
+ - ๊ธฐ๋ณธ์ ์ผ๋ก ์ ์ Approve ํ Mergeํ๋ฉฐ, PR ์์ฑ์๊ฐ ๋ธ๋์น๋ฅผ ์ญ์ ํฉ๋๋ค.
+ - ๋จ, ์ฌํ ๋ฑ ๊ฐ์ธ ์ผ์ ์ผ๋ก ํ์ธ์ด ์ด๋ ค์ด ๊ฒฝ์ฐ, ํด๋น ์ธ์์ ์ ์ธํ ํ์์ Approve๋ก Merge ๊ฐ๋ฅํฉ๋๋ค.
+
+- **๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค์น ๊ณต์ **
+ - ์์
์ค ์๋ก์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ค์นํ ๊ฒฝ์ฐ, ๋์ค์ฝ๋ ์ค๋ ๋์ ๋๊ธ๋ก ๊ณต์ ํฉ๋๋ค.
+
+- **Figma ์์น ๊ท์น**
+ - ๋์์ด๋๋๊ป์ ๋ณ๋๋ก ์๋ดํ ๊ฒฝ์ฐ๋ฅผ ์ ์ธํ๊ณ , ๊ฐ์ฅ ๊ฐ๊น์ด 4์ ๋ฐฐ์๋ก ์ค๋
ํ์ฌ ์ ์ฉํฉ๋๋ค.
+
---
-## ๐ฏ ์ปค๋ฐ ์ปจ๋ฒค์
(Commit Convention)
-
-### ์ฃผ์ ์ฌํญ
-* type์ ์๋ฌธ์๋ง ์ฌ์ฉ (feat, fix, refactor, docs, style, test, chore)
-* subject๋ ๋ชจ๋ ํ์ฌํ ๋์ฌ
-
-### ๐ ํ์
๋ชฉ๋ก
-
-| type | ์ค๋ช
|
-| :--- | :--- |
-| start | ์๋ก์ด ํ๋ก์ ํธ๋ฅผ ์์ํ ๋ |
-| feat | ์๋ก์ด ๊ธฐ๋ฅ์ ์ถ๊ฐํ ๋ |
-| fix | ๋ฒ๊ทธ๋ฅผ ์์ ํ ๋ |
-| design | CSS ๋ฑ ์ฌ์ฉ์ UI ๋์์ธ์ ๋ณ๊ฒฝํ ๋ |
-| refactor | ๊ธฐ๋ฅ ๋ณ๊ฒฝ ์์ด ์ฝ๋๋ฅผ ๋ฆฌํฉํ ๋งํ ๋ |
-| settings | ์ค์ ํ์ผ์ ๋ณ๊ฒฝํ ๋ |
-| comment | ํ์ํ ์ฃผ์์ ์ถ๊ฐํ๊ฑฐ๋ ๋ณ๊ฒฝํ ๋ |
-| dependency/Plugin | ์์กด์ฑ/ํ๋ฌ๊ทธ์ธ์ ์ถ๊ฐํ ๋ |
-| docs | README.md ๋ฑ ๋ฌธ์๋ฅผ ์์ ํ ๋ |
-| merge | ๋ธ๋์น๋ฅผ ๋ณํฉํ ๋ |
-| deploy | ๋น๋ ๋ฐ ๋ฐฐํฌ ๊ด๋ จ ์์
์ ํ ๋ |
-| rename | ํ์ผ ํน์ ํด๋๋ช
์ ์์ ํ๊ฑฐ๋ ์ฎ๊ธธ ๋ |
-| remove | ํ์ผ์ ์ญ์ ํ๋ ์์
๋ง ์ํํ์ ๋ |
-| revert | ์ด์ ๋ฒ์ ์ผ๋ก ๋กค๋ฐฑํ ๋ |
-
-### โจ ์์
-* feat: ์ปดํฌ๋ํธ ์ถ๊ฐ
-* fix: ๊ฐ๋ ค์ง ํ์ ํด๊ฒฐ
+## ๐ฐ ์ํฐํด ๋ชจ์ (Articles)
+
+| ์ด๋ฆ | ์ํฐํด ์ ๋ชฉ |
+| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| ๐ ๋ฐ์ ๋ฏผ | [์ํ ๊ธฐ๋ฐ ์ธํฐ๋์
๊ตฌํ๊ธฐ](https://velog.io/@waldls/Frontend-%EC%83%81%ED%83%9C-%EA%B8%B0%EB%B0%98-%EC%9D%B8%ED%84%B0%EB%9E%99%EC%85%98-%EA%B5%AC%ED%98%84%EA%B8%B0) |
+| ๐ ์ด์ ์ฐ | [Device Life Auth ์์คํ
๊ตฌํ ํ๊ณ ](https://www.notion.so/Device-Life-Auth-305564e055eb8007a616fde7ddb853d7?source=copy_link) |
diff --git a/build.sh b/build.sh
new file mode 100644
index 00000000..772d1617
--- /dev/null
+++ b/build.sh
@@ -0,0 +1,4 @@
+cd ../
+mkdir output
+cp -R ./Frontend/* ./output
+cp -R ./output ./Frontend/
diff --git a/index.html b/index.html
index 42fcf48c..fc71465b 100644
--- a/index.html
+++ b/index.html
@@ -2,9 +2,26 @@
-
+
- DeviceLife
+ Device Life
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/package-lock.json b/package-lock.json
index 0d431086..2fddd212 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,11 +8,26 @@
"name": "devicelife",
"version": "0.0.0",
"dependencies": {
+ "@hookform/resolvers": "^5.2.2",
+ "@react-oauth/google": "^0.13.4",
+ "@tanstack/react-query": "^5.90.20",
+ "@tanstack/react-query-devtools": "^5.91.2",
+ "@types/react-window": "^1.8.8",
+ "axios": "^1.13.2",
+ "clsx": "^2.1.1",
"react": "^19.2.0",
- "react-dom": "^19.2.0"
+ "react-dom": "^19.2.0",
+ "react-hook-form": "^7.71.1",
+ "react-router-dom": "^7.12.0",
+ "react-spinners": "^0.17.0",
+ "react-window": "^2.2.6",
+ "tailwind-merge": "^3.4.0",
+ "zod": "^4.3.5",
+ "zustand": "^5.0.10"
},
"devDependencies": {
"@eslint/js": "^9.39.1",
+ "@tailwindcss/vite": "^4.1.18",
"@types/node": "^24.10.4",
"@types/react": "^19.2.5",
"@types/react-dom": "^19.2.3",
@@ -24,9 +39,11 @@
"eslint-plugin-react-refresh": "^0.4.24",
"globals": "^16.5.0",
"prettier": "3.7.4",
+ "tailwindcss": "^4.1.18",
"typescript": "~5.9.3",
"typescript-eslint": "^8.46.4",
- "vite": "^7.2.4"
+ "vite": "^7.2.4",
+ "vite-plugin-svgr": "^4.5.0"
}
},
"node_modules/@babel/code-frame": {
@@ -911,6 +928,18 @@
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
+ "node_modules/@hookform/resolvers": {
+ "version": "5.2.2",
+ "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-5.2.2.tgz",
+ "integrity": "sha512-A/IxlMLShx3KjV/HeTcTfaMxdwy690+L/ZADoeaTltLx+CVuzkeVIPuybK3jrRfw7YZnmdKsVVHAlEPIAEUNlA==",
+ "license": "MIT",
+ "dependencies": {
+ "@standard-schema/utils": "^0.3.0"
+ },
+ "peerDependencies": {
+ "react-hook-form": "^7.55.0"
+ }
+ },
"node_modules/@humanfs/core": {
"version": "0.19.1",
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
@@ -1026,6 +1055,16 @@
"url": "https://opencollective.com/pkgr"
}
},
+ "node_modules/@react-oauth/google": {
+ "version": "0.13.4",
+ "resolved": "https://registry.npmjs.org/@react-oauth/google/-/google-0.13.4.tgz",
+ "integrity": "sha512-hGKyNEH+/PK8M0sFEuo3MAEk0txtHpgs94tDQit+s2LXg7b6z53NtzHfqDvoB2X8O6lGB+FRg80hY//X6hfD+w==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": ">=16.8.0",
+ "react-dom": ">=16.8.0"
+ }
+ },
"node_modules/@rolldown/pluginutils": {
"version": "1.0.0-beta.53",
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.53.tgz",
@@ -1033,6 +1072,29 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@rollup/pluginutils": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz",
+ "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "^1.0.0",
+ "estree-walker": "^2.0.2",
+ "picomatch": "^4.0.2"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
+ },
+ "peerDependenciesMeta": {
+ "rollup": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.54.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.54.0.tgz",
@@ -1241,12 +1303,501 @@
"optional": true,
"os": [
"linux"
- ]
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-gnu": {
+ "version": "4.54.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.54.0.tgz",
+ "integrity": "sha512-WGt5J8Ij/rvyqpFexxk3ffKqqbLf9AqrTBbWDk7ApGUzaIs6V+s2s84kAxklFwmMF/vBNGrVdYgbblCOFFezMQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-musl": {
+ "version": "4.54.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.54.0.tgz",
+ "integrity": "sha512-JzQmb38ATzHjxlPHuTH6tE7ojnMKM2kYNzt44LO/jJi8BpceEC8QuXYA908n8r3CNuG/B3BV8VR3Hi1rYtmPiw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-openharmony-arm64": {
+ "version": "4.54.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.54.0.tgz",
+ "integrity": "sha512-huT3fd0iC7jigGh7n3q/+lfPcXxBi+om/Rs3yiFxjvSxbSB6aohDFXbWvlspaqjeOh+hx7DDHS+5Es5qRkWkZg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-arm64-msvc": {
+ "version": "4.54.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.54.0.tgz",
+ "integrity": "sha512-c2V0W1bsKIKfbLMBu/WGBz6Yci8nJ/ZJdheE0EwB73N3MvHYKiKGs3mVilX4Gs70eGeDaMqEob25Tw2Gb9Nqyw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-ia32-msvc": {
+ "version": "4.54.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.54.0.tgz",
+ "integrity": "sha512-woEHgqQqDCkAzrDhvDipnSirm5vxUXtSKDYTVpZG3nUdW/VVB5VdCYA2iReSj/u3yCZzXID4kuKG7OynPnB3WQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-gnu": {
+ "version": "4.54.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.54.0.tgz",
+ "integrity": "sha512-dzAc53LOuFvHwbCEOS0rPbXp6SIhAf2txMP5p6mGyOXXw5mWY8NGGbPMPrs4P1WItkfApDathBj/NzMLUZ9rtQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-msvc": {
+ "version": "4.54.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.54.0.tgz",
+ "integrity": "sha512-hYT5d3YNdSh3mbCU1gwQyPgQd3T2ne0A3KG8KSBdav5TiBg6eInVmV+TeR5uHufiIgSFg0XsOWGW5/RhNcSvPg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@standard-schema/utils": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/@standard-schema/utils/-/utils-0.3.0.tgz",
+ "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==",
+ "license": "MIT"
+ },
+ "node_modules/@svgr/babel-plugin-add-jsx-attribute": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz",
+ "integrity": "sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/gregberge"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@svgr/babel-plugin-remove-jsx-attribute": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz",
+ "integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/gregberge"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz",
+ "integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/gregberge"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz",
+ "integrity": "sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/gregberge"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@svgr/babel-plugin-svg-dynamic-title": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz",
+ "integrity": "sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/gregberge"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@svgr/babel-plugin-svg-em-dimensions": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-8.0.0.tgz",
+ "integrity": "sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/gregberge"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@svgr/babel-plugin-transform-react-native-svg": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-8.1.0.tgz",
+ "integrity": "sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/gregberge"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@svgr/babel-plugin-transform-svg-component": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-8.0.0.tgz",
+ "integrity": "sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/gregberge"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@svgr/babel-preset": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-8.1.0.tgz",
+ "integrity": "sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@svgr/babel-plugin-add-jsx-attribute": "8.0.0",
+ "@svgr/babel-plugin-remove-jsx-attribute": "8.0.0",
+ "@svgr/babel-plugin-remove-jsx-empty-expression": "8.0.0",
+ "@svgr/babel-plugin-replace-jsx-attribute-value": "8.0.0",
+ "@svgr/babel-plugin-svg-dynamic-title": "8.0.0",
+ "@svgr/babel-plugin-svg-em-dimensions": "8.0.0",
+ "@svgr/babel-plugin-transform-react-native-svg": "8.1.0",
+ "@svgr/babel-plugin-transform-svg-component": "8.0.0"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/gregberge"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@svgr/core": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz",
+ "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/core": "^7.21.3",
+ "@svgr/babel-preset": "8.1.0",
+ "camelcase": "^6.2.0",
+ "cosmiconfig": "^8.1.3",
+ "snake-case": "^3.0.4"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/gregberge"
+ }
+ },
+ "node_modules/@svgr/hast-util-to-babel-ast": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz",
+ "integrity": "sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.21.3",
+ "entities": "^4.4.0"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/gregberge"
+ }
+ },
+ "node_modules/@svgr/plugin-jsx": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-8.1.0.tgz",
+ "integrity": "sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/core": "^7.21.3",
+ "@svgr/babel-preset": "8.1.0",
+ "@svgr/hast-util-to-babel-ast": "8.0.0",
+ "svg-parser": "^2.0.4"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/gregberge"
+ },
+ "peerDependencies": {
+ "@svgr/core": "*"
+ }
+ },
+ "node_modules/@tailwindcss/node": {
+ "version": "4.1.18",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.18.tgz",
+ "integrity": "sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/remapping": "^2.3.4",
+ "enhanced-resolve": "^5.18.3",
+ "jiti": "^2.6.1",
+ "lightningcss": "1.30.2",
+ "magic-string": "^0.30.21",
+ "source-map-js": "^1.2.1",
+ "tailwindcss": "4.1.18"
+ }
+ },
+ "node_modules/@tailwindcss/oxide": {
+ "version": "4.1.18",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.18.tgz",
+ "integrity": "sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 10"
+ },
+ "optionalDependencies": {
+ "@tailwindcss/oxide-android-arm64": "4.1.18",
+ "@tailwindcss/oxide-darwin-arm64": "4.1.18",
+ "@tailwindcss/oxide-darwin-x64": "4.1.18",
+ "@tailwindcss/oxide-freebsd-x64": "4.1.18",
+ "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.18",
+ "@tailwindcss/oxide-linux-arm64-gnu": "4.1.18",
+ "@tailwindcss/oxide-linux-arm64-musl": "4.1.18",
+ "@tailwindcss/oxide-linux-x64-gnu": "4.1.18",
+ "@tailwindcss/oxide-linux-x64-musl": "4.1.18",
+ "@tailwindcss/oxide-wasm32-wasi": "4.1.18",
+ "@tailwindcss/oxide-win32-arm64-msvc": "4.1.18",
+ "@tailwindcss/oxide-win32-x64-msvc": "4.1.18"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-android-arm64": {
+ "version": "4.1.18",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.18.tgz",
+ "integrity": "sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-darwin-arm64": {
+ "version": "4.1.18",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.18.tgz",
+ "integrity": "sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-darwin-x64": {
+ "version": "4.1.18",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.18.tgz",
+ "integrity": "sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-freebsd-x64": {
+ "version": "4.1.18",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.18.tgz",
+ "integrity": "sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
+ "version": "4.1.18",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.18.tgz",
+ "integrity": "sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
+ "version": "4.1.18",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.18.tgz",
+ "integrity": "sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm64-musl": {
+ "version": "4.1.18",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.18.tgz",
+ "integrity": "sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
},
- "node_modules/@rollup/rollup-linux-x64-gnu": {
- "version": "4.54.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.54.0.tgz",
- "integrity": "sha512-WGt5J8Ij/rvyqpFexxk3ffKqqbLf9AqrTBbWDk7ApGUzaIs6V+s2s84kAxklFwmMF/vBNGrVdYgbblCOFFezMQ==",
+ "node_modules/@tailwindcss/oxide-linux-x64-gnu": {
+ "version": "4.1.18",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.18.tgz",
+ "integrity": "sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==",
"cpu": [
"x64"
],
@@ -1255,12 +1806,15 @@
"optional": true,
"os": [
"linux"
- ]
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
},
- "node_modules/@rollup/rollup-linux-x64-musl": {
- "version": "4.54.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.54.0.tgz",
- "integrity": "sha512-JzQmb38ATzHjxlPHuTH6tE7ojnMKM2kYNzt44LO/jJi8BpceEC8QuXYA908n8r3CNuG/B3BV8VR3Hi1rYtmPiw==",
+ "node_modules/@tailwindcss/oxide-linux-x64-musl": {
+ "version": "4.1.18",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.18.tgz",
+ "integrity": "sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==",
"cpu": [
"x64"
],
@@ -1269,26 +1823,45 @@
"optional": true,
"os": [
"linux"
- ]
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
},
- "node_modules/@rollup/rollup-openharmony-arm64": {
- "version": "4.54.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.54.0.tgz",
- "integrity": "sha512-huT3fd0iC7jigGh7n3q/+lfPcXxBi+om/Rs3yiFxjvSxbSB6aohDFXbWvlspaqjeOh+hx7DDHS+5Es5qRkWkZg==",
+ "node_modules/@tailwindcss/oxide-wasm32-wasi": {
+ "version": "4.1.18",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.18.tgz",
+ "integrity": "sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==",
+ "bundleDependencies": [
+ "@napi-rs/wasm-runtime",
+ "@emnapi/core",
+ "@emnapi/runtime",
+ "@tybys/wasm-util",
+ "@emnapi/wasi-threads",
+ "tslib"
+ ],
"cpu": [
- "arm64"
+ "wasm32"
],
"dev": true,
"license": "MIT",
"optional": true,
- "os": [
- "openharmony"
- ]
+ "dependencies": {
+ "@emnapi/core": "^1.7.1",
+ "@emnapi/runtime": "^1.7.1",
+ "@emnapi/wasi-threads": "^1.1.0",
+ "@napi-rs/wasm-runtime": "^1.1.0",
+ "@tybys/wasm-util": "^0.10.1",
+ "tslib": "^2.4.0"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
},
- "node_modules/@rollup/rollup-win32-arm64-msvc": {
- "version": "4.54.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.54.0.tgz",
- "integrity": "sha512-c2V0W1bsKIKfbLMBu/WGBz6Yci8nJ/ZJdheE0EwB73N3MvHYKiKGs3mVilX4Gs70eGeDaMqEob25Tw2Gb9Nqyw==",
+ "node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
+ "version": "4.1.18",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.18.tgz",
+ "integrity": "sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA==",
"cpu": [
"arm64"
],
@@ -1297,26 +1870,15 @@
"optional": true,
"os": [
"win32"
- ]
- },
- "node_modules/@rollup/rollup-win32-ia32-msvc": {
- "version": "4.54.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.54.0.tgz",
- "integrity": "sha512-woEHgqQqDCkAzrDhvDipnSirm5vxUXtSKDYTVpZG3nUdW/VVB5VdCYA2iReSj/u3yCZzXID4kuKG7OynPnB3WQ==",
- "cpu": [
- "ia32"
],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "win32"
- ]
+ "engines": {
+ "node": ">= 10"
+ }
},
- "node_modules/@rollup/rollup-win32-x64-gnu": {
- "version": "4.54.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.54.0.tgz",
- "integrity": "sha512-dzAc53LOuFvHwbCEOS0rPbXp6SIhAf2txMP5p6mGyOXXw5mWY8NGGbPMPrs4P1WItkfApDathBj/NzMLUZ9rtQ==",
+ "node_modules/@tailwindcss/oxide-win32-x64-msvc": {
+ "version": "4.1.18",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.18.tgz",
+ "integrity": "sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q==",
"cpu": [
"x64"
],
@@ -1325,21 +1887,79 @@
"optional": true,
"os": [
"win32"
- ]
- },
- "node_modules/@rollup/rollup-win32-x64-msvc": {
- "version": "4.54.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.54.0.tgz",
- "integrity": "sha512-hYT5d3YNdSh3mbCU1gwQyPgQd3T2ne0A3KG8KSBdav5TiBg6eInVmV+TeR5uHufiIgSFg0XsOWGW5/RhNcSvPg==",
- "cpu": [
- "x64"
],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/vite": {
+ "version": "4.1.18",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.18.tgz",
+ "integrity": "sha512-jVA+/UpKL1vRLg6Hkao5jldawNmRo7mQYrZtNHMIVpLfLhDml5nMRUo/8MwoX2vNXvnaXNNMedrMfMugAVX1nA==",
"dev": true,
"license": "MIT",
- "optional": true,
- "os": [
- "win32"
- ]
+ "dependencies": {
+ "@tailwindcss/node": "4.1.18",
+ "@tailwindcss/oxide": "4.1.18",
+ "tailwindcss": "4.1.18"
+ },
+ "peerDependencies": {
+ "vite": "^5.2.0 || ^6 || ^7"
+ }
+ },
+ "node_modules/@tanstack/query-core": {
+ "version": "5.90.20",
+ "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.90.20.tgz",
+ "integrity": "sha512-OMD2HLpNouXEfZJWcKeVKUgQ5n+n3A2JFmBaScpNDUqSrQSjiveC7dKMe53uJUg1nDG16ttFPz2xfilz6i2uVg==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/tannerlinsley"
+ }
+ },
+ "node_modules/@tanstack/query-devtools": {
+ "version": "5.92.0",
+ "resolved": "https://registry.npmjs.org/@tanstack/query-devtools/-/query-devtools-5.92.0.tgz",
+ "integrity": "sha512-N8D27KH1vEpVacvZgJL27xC6yPFUy0Zkezn5gnB3L3gRCxlDeSuiya7fKge8Y91uMTnC8aSxBQhcK6ocY7alpQ==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/tannerlinsley"
+ }
+ },
+ "node_modules/@tanstack/react-query": {
+ "version": "5.90.20",
+ "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.90.20.tgz",
+ "integrity": "sha512-vXBxa+qeyveVO7OA0jX1z+DeyCA4JKnThKv411jd5SORpBKgkcVnYKCiBgECvADvniBX7tobwBmg01qq9JmMJw==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@tanstack/query-core": "5.90.20"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/tannerlinsley"
+ },
+ "peerDependencies": {
+ "react": "^18 || ^19"
+ }
+ },
+ "node_modules/@tanstack/react-query-devtools": {
+ "version": "5.91.2",
+ "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.91.2.tgz",
+ "integrity": "sha512-ZJ1503ay5fFeEYFUdo7LMNFzZryi6B0Cacrgr2h1JRkvikK1khgIq6Nq2EcblqEdIlgB/r7XDW8f8DQ89RuUgg==",
+ "license": "MIT",
+ "dependencies": {
+ "@tanstack/query-devtools": "5.92.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/tannerlinsley"
+ },
+ "peerDependencies": {
+ "@tanstack/react-query": "^5.90.14",
+ "react": "^18 || ^19"
+ }
},
"node_modules/@types/babel__core": {
"version": "7.20.5",
@@ -1415,7 +2035,6 @@
"version": "19.2.7",
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz",
"integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==",
- "dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
@@ -1432,6 +2051,15 @@
"@types/react": "^19.2.0"
}
},
+ "node_modules/@types/react-window": {
+ "version": "1.8.8",
+ "resolved": "https://registry.npmjs.org/@types/react-window/-/react-window-1.8.8.tgz",
+ "integrity": "sha512-8Ls660bHR1AUA2kuRvVG9D/4XpRC6wjAaPT9dil7Ckc76eP9TKWZwwmgfq8Q1LANX3QNDnoU4Zp48A3w+zK69Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/react": "*"
+ }
+ },
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.50.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.50.1.tgz",
@@ -1787,6 +2415,23 @@
"dev": true,
"license": "Python-2.0"
},
+ "node_modules/asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
+ "license": "MIT"
+ },
+ "node_modules/axios": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz",
+ "integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==",
+ "license": "MIT",
+ "dependencies": {
+ "follow-redirects": "^1.15.6",
+ "form-data": "^4.0.4",
+ "proxy-from-env": "^1.1.0"
+ }
+ },
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -1850,6 +2495,19 @@
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
}
},
+ "node_modules/call-bind-apply-helpers": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
+ "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
"node_modules/callsites": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
@@ -1860,6 +2518,19 @@
"node": ">=6"
}
},
+ "node_modules/camelcase": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
+ "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/caniuse-lite": {
"version": "1.0.30001761",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001761.tgz",
@@ -1898,6 +2569,15 @@
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
+ "node_modules/clsx": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
+ "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@@ -1918,6 +2598,18 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/combined-stream": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+ "license": "MIT",
+ "dependencies": {
+ "delayed-stream": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -1932,6 +2624,46 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/cookie": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz",
+ "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/cosmiconfig": {
+ "version": "8.3.6",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz",
+ "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "import-fresh": "^3.3.0",
+ "js-yaml": "^4.1.0",
+ "parse-json": "^5.2.0",
+ "path-type": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/d-fischer"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.9.5"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
"node_modules/cross-spawn": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
@@ -1951,40 +2683,165 @@
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
"integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
+ "license": "MIT"
+ },
+ "node_modules/debug": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "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,
"license": "MIT"
},
- "node_modules/debug": {
- "version": "4.4.3",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
- "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
- "dev": true,
+ "node_modules/delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/detect-libc": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
+ "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/dot-case": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz",
+ "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "no-case": "^3.0.4",
+ "tslib": "^2.0.3"
+ }
+ },
+ "node_modules/dunder-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
+ "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.2.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/electron-to-chromium": {
+ "version": "1.5.267",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz",
+ "integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/enhanced-resolve": {
+ "version": "5.18.4",
+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.4.tgz",
+ "integrity": "sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "graceful-fs": "^4.2.4",
+ "tapable": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/entities": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
+ "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/error-ex": {
+ "version": "1.3.4",
+ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz",
+ "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-arrayish": "^0.2.1"
+ }
+ },
+ "node_modules/es-define-property": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
+ "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-errors": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-object-atoms": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
+ "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
"license": "MIT",
"dependencies": {
- "ms": "^2.1.3"
+ "es-errors": "^1.3.0"
},
"engines": {
- "node": ">=6.0"
- },
- "peerDependenciesMeta": {
- "supports-color": {
- "optional": true
- }
+ "node": ">= 0.4"
}
},
- "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,
- "license": "MIT"
- },
- "node_modules/electron-to-chromium": {
- "version": "1.5.267",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz",
- "integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==",
- "dev": true,
- "license": "ISC"
+ "node_modules/es-set-tostringtag": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
+ "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.6",
+ "has-tostringtag": "^1.0.2",
+ "hasown": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
},
"node_modules/esbuild": {
"version": "0.27.2",
@@ -2274,6 +3131,13 @@
"node": ">=4.0"
}
},
+ "node_modules/estree-walker": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
+ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/esutils": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
@@ -2381,6 +3245,42 @@
"dev": true,
"license": "ISC"
},
+ "node_modules/follow-redirects": {
+ "version": "1.15.11",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
+ "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/RubenVerborgh"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=4.0"
+ },
+ "peerDependenciesMeta": {
+ "debug": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/form-data": {
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
+ "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==",
+ "license": "MIT",
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "es-set-tostringtag": "^2.1.0",
+ "hasown": "^2.0.2",
+ "mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
@@ -2396,6 +3296,15 @@
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/gensync": {
"version": "1.0.0-beta.2",
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
@@ -2406,6 +3315,43 @@
"node": ">=6.9.0"
}
},
+ "node_modules/get-intrinsic": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
+ "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "es-define-property": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.1.1",
+ "function-bind": "^1.1.2",
+ "get-proto": "^1.0.1",
+ "gopd": "^1.2.0",
+ "has-symbols": "^1.1.0",
+ "hasown": "^2.0.2",
+ "math-intrinsics": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
+ "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
+ "license": "MIT",
+ "dependencies": {
+ "dunder-proto": "^1.0.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
"node_modules/glob-parent": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
@@ -2432,6 +3378,25 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/gopd": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
+ "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/graceful-fs": {
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+ "dev": true,
+ "license": "ISC"
+ },
"node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
@@ -2442,6 +3407,45 @@
"node": ">=8"
}
},
+ "node_modules/has-symbols": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
+ "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-tostringtag": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
+ "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
+ "license": "MIT",
+ "dependencies": {
+ "has-symbols": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/hasown": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+ "license": "MIT",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
"node_modules/hermes-estree": {
"version": "0.25.1",
"resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz",
@@ -2496,6 +3500,13 @@
"node": ">=0.8.19"
}
},
+ "node_modules/is-arrayish": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+ "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@@ -2526,6 +3537,16 @@
"dev": true,
"license": "ISC"
},
+ "node_modules/jiti": {
+ "version": "2.6.1",
+ "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz",
+ "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "jiti": "lib/jiti-cli.mjs"
+ }
+ },
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -2559,64 +3580,339 @@
"node": ">=6"
}
},
- "node_modules/json-buffer": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
- "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
+ "node_modules/json-buffer": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
+ "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/json-parse-even-better-errors": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "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,
+ "license": "MIT"
+ },
+ "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,
+ "license": "MIT"
+ },
+ "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,
+ "license": "MIT",
+ "bin": {
+ "json5": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/keyv": {
+ "version": "4.5.4",
+ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
+ "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "json-buffer": "3.0.1"
+ }
+ },
+ "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,
+ "license": "MIT",
+ "dependencies": {
+ "prelude-ls": "^1.2.1",
+ "type-check": "~0.4.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/lightningcss": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.2.tgz",
+ "integrity": "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==",
+ "dev": true,
+ "license": "MPL-2.0",
+ "dependencies": {
+ "detect-libc": "^2.0.3"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ },
+ "optionalDependencies": {
+ "lightningcss-android-arm64": "1.30.2",
+ "lightningcss-darwin-arm64": "1.30.2",
+ "lightningcss-darwin-x64": "1.30.2",
+ "lightningcss-freebsd-x64": "1.30.2",
+ "lightningcss-linux-arm-gnueabihf": "1.30.2",
+ "lightningcss-linux-arm64-gnu": "1.30.2",
+ "lightningcss-linux-arm64-musl": "1.30.2",
+ "lightningcss-linux-x64-gnu": "1.30.2",
+ "lightningcss-linux-x64-musl": "1.30.2",
+ "lightningcss-win32-arm64-msvc": "1.30.2",
+ "lightningcss-win32-x64-msvc": "1.30.2"
+ }
+ },
+ "node_modules/lightningcss-android-arm64": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.30.2.tgz",
+ "integrity": "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-darwin-arm64": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.2.tgz",
+ "integrity": "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-darwin-x64": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.2.tgz",
+ "integrity": "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-freebsd-x64": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.2.tgz",
+ "integrity": "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm-gnueabihf": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.2.tgz",
+ "integrity": "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm64-gnu": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.2.tgz",
+ "integrity": "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==",
+ "cpu": [
+ "arm64"
+ ],
"dev": true,
- "license": "MIT"
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
},
- "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==",
+ "node_modules/lightningcss-linux-arm64-musl": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.2.tgz",
+ "integrity": "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==",
+ "cpu": [
+ "arm64"
+ ],
"dev": true,
- "license": "MIT"
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
},
- "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==",
+ "node_modules/lightningcss-linux-x64-gnu": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.2.tgz",
+ "integrity": "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==",
+ "cpu": [
+ "x64"
+ ],
"dev": true,
- "license": "MIT"
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
},
- "node_modules/json5": {
- "version": "2.2.3",
- "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
- "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "node_modules/lightningcss-linux-x64-musl": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.2.tgz",
+ "integrity": "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==",
+ "cpu": [
+ "x64"
+ ],
"dev": true,
- "license": "MIT",
- "bin": {
- "json5": "lib/cli.js"
- },
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
"engines": {
- "node": ">=6"
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
}
},
- "node_modules/keyv": {
- "version": "4.5.4",
- "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
- "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
+ "node_modules/lightningcss-win32-arm64-msvc": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.2.tgz",
+ "integrity": "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==",
+ "cpu": [
+ "arm64"
+ ],
"dev": true,
- "license": "MIT",
- "dependencies": {
- "json-buffer": "3.0.1"
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
}
},
- "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==",
+ "node_modules/lightningcss-win32-x64-msvc": {
+ "version": "1.30.2",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.2.tgz",
+ "integrity": "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==",
+ "cpu": [
+ "x64"
+ ],
"dev": true,
- "license": "MIT",
- "dependencies": {
- "prelude-ls": "^1.2.1",
- "type-check": "~0.4.0"
- },
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
"engines": {
- "node": ">= 0.8.0"
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
}
},
+ "node_modules/lines-and-columns": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/locate-path": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
@@ -2640,6 +3936,16 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/lower-case": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
+ "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.0.3"
+ }
+ },
"node_modules/lru-cache": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
@@ -2650,6 +3956,46 @@
"yallist": "^3.0.2"
}
},
+ "node_modules/magic-string": {
+ "version": "0.30.21",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
+ "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.5"
+ }
+ },
+ "node_modules/math-intrinsics": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
+ "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-db": "1.52.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
"node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@@ -2696,6 +4042,17 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/no-case": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz",
+ "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "lower-case": "^2.0.2",
+ "tslib": "^2.0.3"
+ }
+ },
"node_modules/node-releases": {
"version": "2.0.27",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz",
@@ -2766,6 +4123,25 @@
"node": ">=6"
}
},
+ "node_modules/parse-json": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
+ "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.0.0",
+ "error-ex": "^1.3.1",
+ "json-parse-even-better-errors": "^2.3.0",
+ "lines-and-columns": "^1.1.6"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
@@ -2786,6 +4162,16 @@
"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,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
@@ -2876,6 +4262,12 @@
"node": ">=6.0.0"
}
},
+ "node_modules/proxy-from-env": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
+ "license": "MIT"
+ },
"node_modules/punycode": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
@@ -2901,6 +4293,7 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz",
"integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"scheduler": "^0.27.0"
},
@@ -2908,6 +4301,23 @@
"react": "^19.2.3"
}
},
+ "node_modules/react-hook-form": {
+ "version": "7.71.1",
+ "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.71.1.tgz",
+ "integrity": "sha512-9SUJKCGKo8HUSsCO+y0CtqkqI5nNuaDqTxyqPsZPqIwudpj4rCrAz/jZV+jn57bx5gtZKOh3neQu94DXMc+w5w==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/react-hook-form"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17 || ^18 || ^19"
+ }
+ },
"node_modules/react-refresh": {
"version": "0.18.0",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz",
@@ -2918,6 +4328,64 @@
"node": ">=0.10.0"
}
},
+ "node_modules/react-router": {
+ "version": "7.12.0",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.12.0.tgz",
+ "integrity": "sha512-kTPDYPFzDVGIIGNLS5VJykK0HfHLY5MF3b+xj0/tTyNYL1gF1qs7u67Z9jEhQk2sQ98SUaHxlG31g1JtF7IfVw==",
+ "license": "MIT",
+ "dependencies": {
+ "cookie": "^1.0.1",
+ "set-cookie-parser": "^2.6.0"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=18",
+ "react-dom": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-router-dom": {
+ "version": "7.12.0",
+ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.12.0.tgz",
+ "integrity": "sha512-pfO9fiBcpEfX4Tx+iTYKDtPbrSLLCbwJ5EqP+SPYQu1VYCXdy79GSj0wttR0U4cikVdlImZuEZ/9ZNCgoaxwBA==",
+ "license": "MIT",
+ "dependencies": {
+ "react-router": "7.12.0"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=18",
+ "react-dom": ">=18"
+ }
+ },
+ "node_modules/react-spinners": {
+ "version": "0.17.0",
+ "resolved": "https://registry.npmjs.org/react-spinners/-/react-spinners-0.17.0.tgz",
+ "integrity": "sha512-L/8HTylaBmIWwQzIjMq+0vyaRXuoAevzWoD35wKpNTxxtYXWZp+xtgkfD7Y4WItuX0YvdxMPU79+7VhhmbmuTQ==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
+ "node_modules/react-window": {
+ "version": "2.2.6",
+ "resolved": "https://registry.npmjs.org/react-window/-/react-window-2.2.6.tgz",
+ "integrity": "sha512-v89O08xRdpCaEuf380B39D1C/0KgUDZA59xft6SVAjzjz/xQxSyXrgDWHymIsYI6TMrqE8WO+G0/PB9AGE8VNA==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^18.0.0 || ^19.0.0",
+ "react-dom": "^18.0.0 || ^19.0.0"
+ }
+ },
"node_modules/resolve-from": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
@@ -2986,6 +4454,12 @@
"semver": "bin/semver.js"
}
},
+ "node_modules/set-cookie-parser": {
+ "version": "2.7.2",
+ "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz",
+ "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==",
+ "license": "MIT"
+ },
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@@ -3009,6 +4483,17 @@
"node": ">=8"
}
},
+ "node_modules/snake-case": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz",
+ "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "dot-case": "^3.0.4",
+ "tslib": "^2.0.3"
+ }
+ },
"node_modules/source-map-js": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
@@ -3045,6 +4530,13 @@
"node": ">=8"
}
},
+ "node_modules/svg-parser": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz",
+ "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/synckit": {
"version": "0.11.11",
"resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz",
@@ -3061,6 +4553,37 @@
"url": "https://opencollective.com/synckit"
}
},
+ "node_modules/tailwind-merge": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.4.0.tgz",
+ "integrity": "sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/dcastil"
+ }
+ },
+ "node_modules/tailwindcss": {
+ "version": "4.1.18",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz",
+ "integrity": "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/tapable": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz",
+ "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ }
+ },
"node_modules/tinyglobby": {
"version": "0.2.15",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
@@ -3091,6 +4614,13 @@
"typescript": ">=4.8.4"
}
},
+ "node_modules/tslib": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "dev": true,
+ "license": "0BSD"
+ },
"node_modules/type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@@ -3267,6 +4797,21 @@
}
}
},
+ "node_modules/vite-plugin-svgr": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/vite-plugin-svgr/-/vite-plugin-svgr-4.5.0.tgz",
+ "integrity": "sha512-W+uoSpmVkSmNOGPSsDCWVW/DDAyv+9fap9AZXBvWiQqrboJ08j2vh0tFxTD/LjwqwAd3yYSVJgm54S/1GhbdnA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@rollup/pluginutils": "^5.2.0",
+ "@svgr/core": "^8.1.0",
+ "@svgr/plugin-jsx": "^8.1.0"
+ },
+ "peerDependencies": {
+ "vite": ">=2.6.0"
+ }
+ },
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -3314,10 +4859,9 @@
}
},
"node_modules/zod": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/zod/-/zod-4.2.1.tgz",
- "integrity": "sha512-0wZ1IRqGGhMP76gLqz8EyfBXKk0J2qo2+H3fi4mcUP/KtTocoX08nmIAHl1Z2kJIZbZee8KOpBCSNPRgauucjw==",
- "dev": true,
+ "version": "4.3.5",
+ "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.5.tgz",
+ "integrity": "sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g==",
"license": "MIT",
"peer": true,
"funding": {
@@ -3336,6 +4880,35 @@
"peerDependencies": {
"zod": "^3.25.0 || ^4.0.0"
}
+ },
+ "node_modules/zustand": {
+ "version": "5.0.10",
+ "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.10.tgz",
+ "integrity": "sha512-U1AiltS1O9hSy3rul+Ub82ut2fqIAefiSuwECWt6jlMVUGejvf+5omLcRBSzqbRagSM3hQZbtzdeRc6QVScXTg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.20.0"
+ },
+ "peerDependencies": {
+ "@types/react": ">=18.0.0",
+ "immer": ">=9.0.6",
+ "react": ">=18.0.0",
+ "use-sync-external-store": ">=1.2.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "immer": {
+ "optional": true
+ },
+ "react": {
+ "optional": true
+ },
+ "use-sync-external-store": {
+ "optional": true
+ }
+ }
}
}
}
diff --git a/package.json b/package.json
index c11f2b4e..49afd26e 100644
--- a/package.json
+++ b/package.json
@@ -10,11 +10,26 @@
"preview": "vite preview"
},
"dependencies": {
+ "@hookform/resolvers": "^5.2.2",
+ "@react-oauth/google": "^0.13.4",
+ "@tanstack/react-query": "^5.90.20",
+ "@tanstack/react-query-devtools": "^5.91.2",
+ "@types/react-window": "^1.8.8",
+ "axios": "^1.13.2",
+ "clsx": "^2.1.1",
"react": "^19.2.0",
- "react-dom": "^19.2.0"
+ "react-dom": "^19.2.0",
+ "react-hook-form": "^7.71.1",
+ "react-router-dom": "^7.12.0",
+ "react-spinners": "^0.17.0",
+ "react-window": "^2.2.6",
+ "tailwind-merge": "^3.4.0",
+ "zod": "^4.3.5",
+ "zustand": "^5.0.10"
},
"devDependencies": {
"@eslint/js": "^9.39.1",
+ "@tailwindcss/vite": "^4.1.18",
"@types/node": "^24.10.4",
"@types/react": "^19.2.5",
"@types/react-dom": "^19.2.3",
@@ -26,8 +41,10 @@
"eslint-plugin-react-refresh": "^0.4.24",
"globals": "^16.5.0",
"prettier": "3.7.4",
+ "tailwindcss": "^4.1.18",
"typescript": "~5.9.3",
"typescript-eslint": "^8.46.4",
- "vite": "^7.2.4"
+ "vite": "^7.2.4",
+ "vite-plugin-svgr": "^4.5.0"
}
}
diff --git a/public/devicelife.svg b/public/devicelife.svg
new file mode 100644
index 00000000..62919200
--- /dev/null
+++ b/public/devicelife.svg
@@ -0,0 +1,34 @@
+
diff --git a/public/og-thumbnail.png b/public/og-thumbnail.png
new file mode 100644
index 00000000..dff78e70
Binary files /dev/null and b/public/og-thumbnail.png differ
diff --git a/public/vite.svg b/public/vite.svg
deleted file mode 100644
index e7b8dfb1..00000000
--- a/public/vite.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/src/App.css b/src/App.css
deleted file mode 100644
index e69de29b..00000000
diff --git a/src/App.tsx b/src/App.tsx
index 729b1ea3..e11b017d 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,5 +1,8 @@
+import { RouterProvider } from 'react-router-dom';
+import { router } from '@/routes/router';
+
const App = () => {
- return App
;
+ return ;
};
export default App;
diff --git a/src/apis/auth/postJoin.ts b/src/apis/auth/postJoin.ts
new file mode 100644
index 00000000..c3178748
--- /dev/null
+++ b/src/apis/auth/postJoin.ts
@@ -0,0 +1,14 @@
+import { axiosInstance } from '@/apis/axios/axios';
+import type { SignupRequest, SignupResponse } from '@/types/auth/signup';
+import { useMutation } from '@tanstack/react-query';
+
+export const postJoin = async (payload: SignupRequest): Promise => {
+ const { data } = await axiosInstance.post('/api/auth/join', payload);
+ return data;
+};
+
+export const usePostJoin = () => {
+ return useMutation({
+ mutationFn: postJoin,
+ });
+};
diff --git a/src/apis/auth/postJoinEmail.ts b/src/apis/auth/postJoinEmail.ts
new file mode 100644
index 00000000..8588ecf3
--- /dev/null
+++ b/src/apis/auth/postJoinEmail.ts
@@ -0,0 +1,22 @@
+import { axiosInstance } from '@/apis/axios/axios';
+import type {
+ EmailDuplicateRequest,
+ EmailDuplicateResponse,
+} from '@/types/auth/signup';
+import { useMutation } from '@tanstack/react-query';
+
+export const postJoinEmail = async (
+ payload: EmailDuplicateRequest
+): Promise => {
+ const { data } = await axiosInstance.post(
+ '/api/auth/join/email',
+ payload
+ );
+ return data;
+};
+
+export const usePostJoinEmail = () => {
+ return useMutation({
+ mutationFn: postJoinEmail,
+ });
+};
diff --git a/src/apis/auth/postLogin.ts b/src/apis/auth/postLogin.ts
new file mode 100644
index 00000000..d02a5416
--- /dev/null
+++ b/src/apis/auth/postLogin.ts
@@ -0,0 +1,15 @@
+import { cookieAxiosInstance } from '@/apis/axios/cookieAxios';
+import type { LoginRequest, LoginResponse } from '@/types/auth/login';
+import { useMutation } from '@tanstack/react-query';
+
+export const postLogin = async (payload: LoginRequest): Promise => {
+ // refreshToken์ httpOnly ์ฟ ํค๋ก ์๋ ์์ ๋จ
+ const { data } = await cookieAxiosInstance.post('/api/auth/login', payload);
+ return data;
+};
+
+export const usePostLogin = () => {
+ return useMutation({
+ mutationFn: postLogin,
+ });
+};
diff --git a/src/apis/auth/postLogout.ts b/src/apis/auth/postLogout.ts
new file mode 100644
index 00000000..04194d48
--- /dev/null
+++ b/src/apis/auth/postLogout.ts
@@ -0,0 +1,18 @@
+import { cookieAxiosInstance } from '@/apis/axios/cookieAxios';
+import type { LogoutResponse } from '@/types/auth/logout';
+import { useMutation } from '@tanstack/react-query';
+
+export const postLogout = async (): Promise => {
+ // refreshToken์ httpOnly ์ฟ ํค๋ก ์๋ ์ ์ก๋จ
+ const { data } = await cookieAxiosInstance.post(
+ '/api/auth/logout',
+ {}
+ );
+ return data;
+};
+
+export const usePostLogout = () => {
+ return useMutation({
+ mutationFn: postLogout,
+ });
+};
diff --git a/src/apis/auth/postRefresh.ts b/src/apis/auth/postRefresh.ts
new file mode 100644
index 00000000..0ea381ba
--- /dev/null
+++ b/src/apis/auth/postRefresh.ts
@@ -0,0 +1,18 @@
+import { cookieAxiosInstance } from '@/apis/axios/cookieAxios';
+import type { RefreshTokenResponse } from '@/types/auth/refresh';
+import { useMutation } from '@tanstack/react-query';
+
+export const postRefresh = async (): Promise => {
+ // refreshToken์ httpOnly ์ฟ ํค๋ก ์๋ ์ ์ก๋จ
+ const { data } = await cookieAxiosInstance.post(
+ '/api/auth/refresh',
+ {}
+ );
+ return data;
+};
+
+export const usePostRefresh = () => {
+ return useMutation({
+ mutationFn: postRefresh,
+ });
+};
diff --git a/src/apis/axios/axios.ts b/src/apis/axios/axios.ts
new file mode 100644
index 00000000..5c3371e6
--- /dev/null
+++ b/src/apis/axios/axios.ts
@@ -0,0 +1,17 @@
+// ๋ฉ์ธ axios ์ธ์คํด์ค ํ์ผ
+
+import axios from 'axios';
+import { setupRequestInterceptor, setupResponseInterceptor } from '@/apis/axios/interceptors';
+
+const baseURL = import.meta.env.VITE_SERVER_API_URL;
+
+export const axiosInstance = axios.create({
+ baseURL,
+ withCredentials: false, // ๊ธฐ๋ณธ์ ์ผ๋ก ์ฟ ํค ๋ฏธํฌํจ (์ฟ ํค ํ์ํ API๋ cookieAxiosInstance ์ฌ์ฉ)
+});
+
+// ์์ฒญ ์ธํฐ์
ํฐ ์ค์
+setupRequestInterceptor(axiosInstance);
+
+// ์๋ต ์ธํฐ์
ํฐ ์ค์
+setupResponseInterceptor(axiosInstance);
\ No newline at end of file
diff --git a/src/apis/axios/cookieAxios.ts b/src/apis/axios/cookieAxios.ts
new file mode 100644
index 00000000..4230c401
--- /dev/null
+++ b/src/apis/axios/cookieAxios.ts
@@ -0,0 +1,10 @@
+// ์ฟ ํค๊ฐ ํ์ํ API ์ ์ฉ axios ์ธ์คํด์ค (์ธํฐ์
ํฐ ์์)
+
+import axios from 'axios';
+
+const baseURL = import.meta.env.VITE_SERVER_API_URL;
+
+export const cookieAxiosInstance = axios.create({
+ baseURL,
+ withCredentials: true, // ์ฟ ํค/์ธ์
์๋ ํฌํจ
+});
diff --git a/src/apis/axios/interceptors.ts b/src/apis/axios/interceptors.ts
new file mode 100644
index 00000000..d96e340c
--- /dev/null
+++ b/src/apis/axios/interceptors.ts
@@ -0,0 +1,151 @@
+/*
+์์ฒญ ๋ฐ ์๋ต ์ธํฐ์
ํฐ
+ *
+ * [401 ์๋ฌ ์ฒ๋ฆฌ ํ๋ฆ]
+ * 1. 401 ์๋ฌ ๋ฐ์
+ * 2. ํ ํฐ ๊ฐฑ์ ์๋ (refreshToken์ httpOnly ์ฟ ํค๋ก ์๋ ์ ์ก๋จ)
+ * 3. ํ ํฐ ๊ฐฑ์ (refreshPromise)
+ * - ์ฑ๊ณต: ์ accessToken์ผ๋ก ์๋ ์์ฒญ ์ฌ์๋
+ * - ์คํจ: ๋ก๊ทธ์ธ ํ์ด์ง๋ก ๋ฆฌ๋ค์ด๋ ํธ (refreshToken ๋ง๋ฃ ๋๋ ์์)
+ * 4. ๋์ ์์ฒญ ์ฒ๋ฆฌ: ์ฌ๋ฌ ์์ฒญ์ด ๋์์ 401์ ๋ฐ์ผ๋ฉด refreshPromise๋ฅผ ๊ณต์ ํ์ฌ ํ ํฐ ๊ฐฑ์ ์ 1๋ฒ๋ง ์ํ
+*/
+import type { InternalAxiosRequestConfig, AxiosInstance } from 'axios';
+import {
+ getAccessToken,
+ setAccessToken,
+ clearAccessToken,
+} from '@/utils/authStorage';
+import { postRefresh } from '@/apis/auth/postRefresh';
+import { setAuthorizationHeader } from '@/utils/setAuthorizationHeader';
+import { ROUTES } from '@/constants/routes';
+
+
+// ๋ชจ๋ ๋ ๋ฒจ ์ํ
+
+// ํ ํฐ ๊ฐฑ์ ์ค์ธ Promise (๋์ ์์ฒญ ์ ๊ณต์ )
+let refreshPromise: Promise | null = null;
+// ์ค๋ณต ๋ฆฌ๋ค์ด๋ ํธ ๋ฐฉ์ง ํ๋๊ทธ
+let isRedirectingToLogin = false;
+
+
+// ์ ํธ๋ฆฌํฐ ํจ์
+
+/* ๋ก๊ทธ์ธ ํ์ด์ง๋ก ๋ฆฌ๋ค์ด๋ ํธ ํจ์ (์ค๋ณต ๋ฐฉ์ง)
+ - ์ฌ๋ฌ ์์ฒญ์ด ๋์์ ์คํจํด๋ ๋ฆฌ๋ค์ด๋ ํธ๋ 1๋ฒ๋ง ์คํ
+ - ๋น๋ก๊ทธ์ธ ์ํ์์ 401 ๋ฐ์ ์์๋ ๋ฆฌ๋ค์ด๋ ํธ ์ํ
+*/
+const redirectToLoginOnce = () => {
+ if (isRedirectingToLogin) return;
+
+ isRedirectingToLogin = true;
+ clearAccessToken();
+ window.location.href = ROUTES.auth.login;
+};
+
+
+// ์์ฒญ ์ธํฐ์
ํฐ
+/*
+ * ์์ฒญ ์ธํฐ์
ํฐ ์ค์
+ * - ๋งค ์์ฒญ ์ ์ accessToken์ Authorization ํค๋์ ์ถ๊ฐ
+ * - ์ฌ๋ก๊ทธ์ธ ํ ํ๋๊ทธ ๋ฆฌ์
+*/
+export const setupRequestInterceptor = (instance: AxiosInstance) => {
+ instance.interceptors.request.use((config) => {
+ const accessToken = getAccessToken();
+
+ // ์ฌ๋ก๊ทธ์ธ ํ ํ ํฐ์ด ๋ค์ ์๊ธฐ๋ฉด ๋ฆฌ๋ค์ด๋ ํธ ํ๋๊ทธ ๋ฆฌ์
+ if (accessToken && isRedirectingToLogin) {
+ isRedirectingToLogin = false;
+ }
+
+ if (accessToken) {
+ setAuthorizationHeader(config, accessToken);
+ }
+
+ return config;
+ });
+};
+
+
+// ์๋ต ์ธํฐ์
ํฐ
+/*
+ * ์๋ต ์ธํฐ์
ํฐ ์ค์
+ * - 401 ์๋ฌ ์ ํ ํฐ ๊ฐฑ์ ํ ์๋ ์์ฒญ ์ฌ์๋
+ * - ๋์ ์์ฒญ ์ฒ๋ฆฌ: refreshPromise๋ฅผ ๊ณต์ ํ์ฌ ํ ํฐ ๊ฐฑ์ ์ 1๋ฒ๋ง ์ํ
+ */
+export const setupResponseInterceptor = (instance: AxiosInstance) => {
+ instance.interceptors.response.use(
+ (response) => response,
+ async (error) => {
+
+ // [1] ์ฌ์ ๊ฒ์ฆ: 401 ์๋ฌ๊ฐ ์๋๊ฑฐ๋ ์ฌ์๋ ๋ถ๊ฐ๋ฅํ ๊ฒฝ์ฐ early return
+ if (!error.config) {
+ return Promise.reject(error);
+ }
+
+ const originalRequest = error.config as InternalAxiosRequestConfig & {
+ _retry?: boolean;
+ };
+
+ if (error.response?.status !== 401) {
+ return Promise.reject(error);
+ }
+
+ if (originalRequest._retry) {
+ return Promise.reject(error);
+ }
+
+ // ์ฌ์๋ ํ๋๊ทธ ์ค์ (๋ฌดํ๋ฃจํ ๋ฐฉ์ง)
+ originalRequest._retry = true;
+
+ // [2] ์ด๋ฏธ ๋ค๋ฅธ ์์ฒญ์ด ํ ํฐ ๊ฐฑ์ ์ค์ด๋ฉด ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋ค๋ฆผ
+ if (refreshPromise) {
+ try {
+ const newToken = await refreshPromise;
+ setAuthorizationHeader(originalRequest, newToken);
+ return instance(originalRequest);
+ } catch (refreshError) {
+ redirectToLoginOnce();
+ return Promise.reject(refreshError);
+ }
+ }
+
+
+ // [3] ํ ํฐ ๊ฐฑ์ Promise ์์ฑ ๋ฐ ์คํ
+ // - try: ํ ํฐ ๊ฐฑ์ API ํธ์ถ (refreshToken์ httpOnly ์ฟ ํค๋ก ์๋ ์ ์ก) โ ์ฑ๊ณต ์ ์ accessToken ๋ฐํ
+ // - catch: ์คํจ ์ ๋ก๊ทธ์ธ ๋ฆฌ๋ค์ด๋ ํธ โ ์๋ฌ re-throw (์ธ๋ถ catch๋ก ์ ํ)
+ // - finally: ์ฑ๊ณต/์คํจ ๊ด๊ณ์์ด refreshPromise ์ด๊ธฐํ
+ refreshPromise = (async () => {
+ try {
+ const data = await postRefresh();
+
+ if (!data?.result?.accessToken) {
+ throw new Error('ํ ํฐ ์ฌ๋ฐ๊ธ ์๋ต์ด ์ฌ๋ฐ๋ฅด์ง ์์ต๋๋ค.');
+ }
+
+ // ์ accessToken ์ ์ฅ (refreshToken์ httpOnly ์ฟ ํค๋ก ์๋ฒ์์ ๊ด๋ฆฌ)
+ setAccessToken(data.result.accessToken);
+
+ return data.result.accessToken;
+ } catch (refreshError) {
+ redirectToLoginOnce();
+ throw refreshError; // ์ธ๋ถ catch๋ก ์ ํ
+ } finally {
+ refreshPromise = null; // ํญ์ ์ด๊ธฐํ (์ฑ๊ณต/์คํจ ๋ฌด๊ด)
+ }
+ })();
+
+ // [4] ํ ํฐ ๊ฐฑ์ ๊ฒฐ๊ณผ์ ๋ฐ๋ผ ์๋ ์์ฒญ ์ฌ์๋ ๋๋ ์๋ฌ ๋ฐํ
+ // - ์ฑ๊ณต: ์ ํ ํฐ์ผ๋ก ์๋ ์์ฒญ ์ฌ์๋
+ // - ์คํจ: [4]์ catch์์ ์ด๋ฏธ ๋ฆฌ๋ค์ด๋ ํธ ์ฒ๋ฆฌ๋จ, ์ฌ๊ธฐ์๋ ์๋ฌ๋ง ์ ๋ฌ
+ try {
+ const newToken = await refreshPromise;
+ setAuthorizationHeader(originalRequest, newToken);
+ return instance(originalRequest);
+ } catch (refreshError) {
+ return Promise.reject(refreshError);
+ }
+ }
+ );
+};
+
diff --git a/src/apis/combo/deleteCombo.ts b/src/apis/combo/deleteCombo.ts
new file mode 100644
index 00000000..720341e6
--- /dev/null
+++ b/src/apis/combo/deleteCombo.ts
@@ -0,0 +1,23 @@
+import { axiosInstance } from '@/apis/axios/axios';
+import type { DeleteComboResponse } from '@/types/combo/combo';
+import { useMutation, useQueryClient } from '@tanstack/react-query';
+import { queryKey } from '@/constants/queryKey';
+
+// ์กฐํฉ ์ญ์
+export const deleteCombo = async (comboId: number): Promise => {
+ const { data } = await axiosInstance.delete(
+ `/api/combos/${comboId}`
+ );
+ return data;
+};
+
+export const useDeleteCombo = () => {
+ const queryClient = useQueryClient();
+
+ return useMutation({
+ mutationFn: (comboId: number) => deleteCombo(comboId),
+ onSuccess: () => {
+ queryClient.invalidateQueries({ queryKey: [queryKey.COMBOS] });
+ },
+ });
+};
diff --git a/src/apis/combo/deleteComboDevice.ts b/src/apis/combo/deleteComboDevice.ts
new file mode 100644
index 00000000..815d7484
--- /dev/null
+++ b/src/apis/combo/deleteComboDevice.ts
@@ -0,0 +1,33 @@
+import { axiosInstance } from '@/apis/axios/axios';
+import type { DeleteComboDeviceResponse } from '@/types/combo/combo';
+import { useMutation, useQueryClient } from '@tanstack/react-query';
+import { queryKey } from '@/constants/queryKey';
+import { usePollComboEvaluation } from '@/hooks/usePollComboEvaluation';
+
+// ์กฐํฉ์์ ๊ธฐ๊ธฐ ์ญ์
+export const deleteComboDevice = async (
+ comboId: number,
+ deviceId: number
+): Promise => {
+ const { data } = await axiosInstance.delete(
+ `/api/combos/${comboId}/devices/${deviceId}`
+ );
+ return data;
+};
+
+export const useDeleteComboDevice = () => {
+ const queryClient = useQueryClient();
+ const { poll } = usePollComboEvaluation();
+
+ return useMutation({
+ mutationFn: ({ comboId, deviceId }: { comboId: number; deviceId: number }) =>
+ deleteComboDevice(comboId, deviceId),
+ onSuccess: (_data, variables) => {
+ // ์กฐํฉ ๋ชฉ๋ก๊ณผ ์์ธ ์ ๋ณด ์บ์ ๋ฌดํจํ
+ queryClient.invalidateQueries({ queryKey: [queryKey.COMBOS] });
+ queryClient.invalidateQueries({ queryKey: [queryKey.COMBO_DETAIL] });
+ // ์กฐํฉ ํ๊ฐ ํด๋ง ์์
+ poll(variables.comboId);
+ },
+ });
+};
diff --git a/src/apis/combo/getComboEvaluation.ts b/src/apis/combo/getComboEvaluation.ts
new file mode 100644
index 00000000..f55be82a
--- /dev/null
+++ b/src/apis/combo/getComboEvaluation.ts
@@ -0,0 +1,24 @@
+import { axiosInstance } from '@/apis/axios/axios';
+import type { GetComboEvaluationResponse, ComboEvaluationResult } from '@/types/combo/evaluation';
+import { useQuery } from '@tanstack/react-query';
+import { queryKey } from '@/constants/queryKey';
+
+// ์กฐํฉ ํ๊ฐ ์ ์ ์กฐํ API
+export const getComboEvaluation = async (comboId: number): Promise => {
+ const { data } = await axiosInstance.get(
+ `/api/combos/${comboId}/evaluation`
+ );
+ return data.result!;
+};
+
+// ์กฐํฉ ํ๊ฐ ์กฐํ ํ
(์บ์ ๊ตฌ๋
+ ์ด๊ธฐ fetch)
+export const useComboEvaluation = (comboId: number | undefined) => {
+ return useQuery({
+ queryKey: [queryKey.COMBO_EVALUATION, comboId],
+ queryFn: () => getComboEvaluation(comboId!),
+ enabled: !!comboId,
+ staleTime: Infinity, // ํด๋ง์ด setQueryData๋ก ๊ฐฑ์ ํ๋ฏ๋ก ์๋ refetch ๋ถํ์
+ retry: false, // 404(EVAL_4041)์ผ ๋ ๋ฌดํ ์ฌ์๋ ๋ฐฉ์ง
+ });
+};
+
diff --git a/src/apis/combo/getComboId.ts b/src/apis/combo/getComboId.ts
new file mode 100644
index 00000000..afb13dc5
--- /dev/null
+++ b/src/apis/combo/getComboId.ts
@@ -0,0 +1,18 @@
+import { axiosInstance } from '@/apis/axios/axios';
+import type { GetComboResponse, GetComboResult } from '@/types/combo/combo';
+import { useQuery } from '@tanstack/react-query';
+import { queryKey } from '@/constants/queryKey';
+
+// ์กฐํฉ ์์ธ ์กฐํ
+export const getCombo = async (comboId: number): Promise => {
+ const { data } = await axiosInstance.get(`/api/combos/${comboId}`);
+ return data.result!;
+};
+
+export const useGetCombo = (comboId: number | null) => {
+ return useQuery({
+ queryKey: [queryKey.COMBO_DETAIL, comboId],
+ queryFn: () => getCombo(comboId!),
+ enabled: comboId !== null,
+ });
+};
diff --git a/src/apis/combo/getCombos.ts b/src/apis/combo/getCombos.ts
new file mode 100644
index 00000000..6f5c47bd
--- /dev/null
+++ b/src/apis/combo/getCombos.ts
@@ -0,0 +1,22 @@
+import { axiosInstance } from '@/apis/axios/axios';
+import type { GetCombosResponse, GetCombosResult } from '@/types/combo/combo';
+import { useQuery } from '@tanstack/react-query';
+import { queryKey } from '@/constants/queryKey';
+import { useAuth } from '@/hooks/useAuth';
+
+// ์กฐํฉ ๋ชฉ๋ก ์กฐํ
+export const getCombos = async (): Promise => {
+ const { data } = await axiosInstance.get('/api/combos');
+ return data.result ?? [];
+};
+
+export const useGetCombos = () => {
+ const { isLoggedIn } = useAuth();
+
+ return useQuery({
+
+ queryKey: [queryKey.COMBOS],
+ queryFn: getCombos,
+ enabled: isLoggedIn
+ });
+};
diff --git a/src/apis/combo/postComboDevices.ts b/src/apis/combo/postComboDevices.ts
new file mode 100644
index 00000000..2a6e805d
--- /dev/null
+++ b/src/apis/combo/postComboDevices.ts
@@ -0,0 +1,38 @@
+import { axiosInstance } from '@/apis/axios/axios';
+import type {
+ PostComboDeviceRequest,
+ PostComboDeviceResponse,
+} from '@/types/combo/combo';
+import { useMutation, useQueryClient } from '@tanstack/react-query';
+import { queryKey } from '@/constants/queryKey';
+import { usePollComboEvaluation } from '@/hooks/usePollComboEvaluation';
+
+// ์กฐํฉ์ ๊ธฐ๊ธฐ ์ถ๊ฐ
+export const postComboDevice = async (
+ comboId: number,
+ payload: PostComboDeviceRequest
+): Promise => {
+ const { data } = await axiosInstance.post(
+ `/api/combos/${comboId}/devices`,
+ payload
+ );
+ return data;
+};
+
+export const usePostComboDevice = () => {
+ const queryClient = useQueryClient();
+ const { poll } = usePollComboEvaluation();
+
+ return useMutation({
+ mutationFn: ({ comboId, deviceId }: { comboId: number; deviceId: number }) =>
+ postComboDevice(comboId, { deviceId }),
+ onSuccess: (_data, variables) => {
+ // ์กฐํฉ ๋ชฉ๋ก ์บ์ ๋ฌดํจํ
+ queryClient.invalidateQueries({ queryKey: [queryKey.COMBOS] });
+ // ์กฐํฉ ์์ธ ์ ๋ณด ์บ์ ๋ฌดํจํ
+ queryClient.invalidateQueries({ queryKey: [queryKey.COMBO_DETAIL] });
+ // ์กฐํฉ ํ๊ฐ ํด๋ง ์์
+ poll(variables.comboId);
+ },
+ });
+};
diff --git a/src/apis/combo/postComboPin.ts b/src/apis/combo/postComboPin.ts
new file mode 100644
index 00000000..c45f6bea
--- /dev/null
+++ b/src/apis/combo/postComboPin.ts
@@ -0,0 +1,23 @@
+import { axiosInstance } from '@/apis/axios/axios';
+import type { PostComboPinResponse } from '@/types/combo/combo';
+import { useMutation, useQueryClient } from '@tanstack/react-query';
+import { queryKey } from '@/constants/queryKey';
+
+// ์กฐํฉ Pin ํ ๊ธ
+export const postComboPin = async (comboId: number): Promise => {
+ const { data } = await axiosInstance.post(
+ `/api/combos/${comboId}/pin`
+ );
+ return data;
+};
+
+export const usePostComboPin = () => {
+ const queryClient = useQueryClient();
+
+ return useMutation({
+ mutationFn: (comboId: number) => postComboPin(comboId),
+ onSuccess: () => {
+ queryClient.invalidateQueries({ queryKey: [queryKey.COMBOS] });
+ },
+ });
+};
diff --git a/src/apis/combo/postCreateCombination.ts b/src/apis/combo/postCreateCombination.ts
new file mode 100644
index 00000000..680dc0a1
--- /dev/null
+++ b/src/apis/combo/postCreateCombination.ts
@@ -0,0 +1,22 @@
+import { axiosInstance } from '@/apis/axios/axios';
+import type { PostCreateCombinationRequest, PostCreateCombinationResponse } from '@/types/combo/createCombo'
+import { useMutation } from '@tanstack/react-query';
+import type { AxiosError } from 'axios';
+import type { CommonResponse } from '@/types/common';
+
+// ์กฐํฉ ์์ฑ API
+export const postCreateCombination = async (payload: PostCreateCombinationRequest): Promise => {
+ const { data } = await axiosInstance.post('/api/combos', payload);
+ return data;
+};
+
+// ์กฐํฉ ์์ฑ Mutation
+export const usePostCreateCombination = () => {
+ return useMutation<
+ PostCreateCombinationResponse,
+ AxiosError>,
+ PostCreateCombinationRequest
+ >({
+ mutationFn: postCreateCombination,
+ });
+};
diff --git a/src/apis/combo/putCombos.ts b/src/apis/combo/putCombos.ts
new file mode 100644
index 00000000..1af25ace
--- /dev/null
+++ b/src/apis/combo/putCombos.ts
@@ -0,0 +1,29 @@
+import { axiosInstance } from '@/apis/axios/axios';
+import type { PutComboRequest, PutComboResponse } from '@/types/combo/combo';
+import { useMutation, useQueryClient } from '@tanstack/react-query';
+import { queryKey } from '@/constants/queryKey';
+
+// ์กฐํฉ ์์
+export const putCombo = async (
+ comboId: number,
+ payload: PutComboRequest
+): Promise => {
+ const { data } = await axiosInstance.put(
+ `/api/combos/${comboId}`,
+ payload
+ );
+ return data;
+};
+
+export const usePutCombo = () => {
+ const queryClient = useQueryClient();
+
+ return useMutation({
+ mutationFn: ({ comboId, comboName }: { comboId: number; comboName: string }) =>
+ putCombo(comboId, { comboName }),
+ onSuccess: () => {
+ // ์กฐํฉ ๋ชฉ๋ก ์บ์ ๋ฌดํจํ (๋ฆฌํ๋ ์)
+ queryClient.invalidateQueries({ queryKey: [queryKey.COMBOS] });
+ },
+ });
+};
diff --git a/src/apis/devices/getBrands.ts b/src/apis/devices/getBrands.ts
new file mode 100644
index 00000000..828703b6
--- /dev/null
+++ b/src/apis/devices/getBrands.ts
@@ -0,0 +1,18 @@
+import { axiosInstance } from '@/apis/axios/axios';
+import type { GetBrandsResponse } from '@/types/devices';
+import { useQuery } from '@tanstack/react-query';
+import { queryKey } from '@/constants/queryKey';
+
+export const getBrands = async (deviceType?: string): Promise => {
+ const params = deviceType ? { deviceType } : {};
+ const { data } = await axiosInstance.get('/api/brands', { params });
+ return data;
+};
+
+export const useGetBrands = (deviceType?: string) => {
+ return useQuery({
+ queryKey: [queryKey.BRANDS, deviceType],
+ queryFn: () => getBrands(deviceType),
+ enabled: true,
+ });
+};
diff --git a/src/apis/devices/searchDevices.ts b/src/apis/devices/searchDevices.ts
new file mode 100644
index 00000000..b1e315c2
--- /dev/null
+++ b/src/apis/devices/searchDevices.ts
@@ -0,0 +1,35 @@
+import { axiosInstance } from '@/apis/axios/axios';
+import type {
+ SearchDevicesParams,
+ GetDevicesSearchResponse,
+ DeviceSearchResult,
+} from '@/types/devices';
+import { useInfiniteQuery } from '@tanstack/react-query';
+import { queryKey } from '@/constants/queryKey';
+
+export const searchDevices = async (
+ params: SearchDevicesParams
+): Promise => {
+ const { data } = await axiosInstance.get(
+ '/api/devices/search',
+ { params }
+ );
+ return data.result ?? { devices: [], nextCursor: null, hasNext: false };
+};
+
+export const useSearchDevices = (params: Omit) => {
+ return useInfiniteQuery({
+ queryKey: [queryKey.DEVICE_SEARCH, params],
+ queryFn: ({ pageParam }) =>
+ searchDevices({
+ ...params,
+ cursor: pageParam as string | undefined,
+ }),
+ initialPageParam: undefined as string | undefined,
+ getNextPageParam: (lastPage) =>
+ lastPage?.hasNext ? lastPage.nextCursor : undefined,
+ enabled: true,
+ staleTime: 1000 * 60 * 5,
+ placeholderData: (prev) => prev,
+ });
+};
diff --git a/src/apis/findCredential/postFindId.ts b/src/apis/findCredential/postFindId.ts
new file mode 100644
index 00000000..8abc7df7
--- /dev/null
+++ b/src/apis/findCredential/postFindId.ts
@@ -0,0 +1,17 @@
+import { axiosInstance } from '@/apis/axios/axios';
+import type { FindIdRequest, FindIdResponse } from '@/types/findCredential/findId';
+import { useMutation } from '@tanstack/react-query';
+
+export const postFindId = async (payload: FindIdRequest): Promise => {
+ const { data } = await axiosInstance.post(
+ '/api/find-credential/find-id',
+ payload
+ );
+ return data;
+};
+
+export const usePostFindId = () => {
+ return useMutation({
+ mutationFn: postFindId,
+ });
+};
diff --git a/src/apis/findCredential/postFindPassword.ts b/src/apis/findCredential/postFindPassword.ts
new file mode 100644
index 00000000..12e6a135
--- /dev/null
+++ b/src/apis/findCredential/postFindPassword.ts
@@ -0,0 +1,64 @@
+import { cookieAxiosInstance } from '@/apis/axios/cookieAxios';
+import type {
+ SendMailRequest,
+ SendMailResponse,
+ VerifyCodeRequest,
+ VerifyCodeResponse,
+ ResetPasswordRequest,
+ ResetPasswordResponse,
+} from '@/types/findCredential/findPassword';
+import { useMutation } from '@tanstack/react-query';
+
+// step1 - ๋ฉ์ผ ์ ์ก ์์ฒญ API ํจ์
+export const postSendMail = async (
+ payload: SendMailRequest
+): Promise => {
+ const { data } = await cookieAxiosInstance.post(
+ '/api/find-credential/find-password/send-mail',
+ payload
+ );
+ return data;
+};
+
+// step1 - ๋ฉ์ผ ์ ์ก ์์ฒญ ํ
+export const usePostSendMail = () => {
+ return useMutation({
+ mutationFn: postSendMail,
+ });
+};
+
+// step2 - ์ธ์ฆ์ฝ๋ ํ์ธ API ํจ์
+export const postVerifyCode = async (
+ payload: VerifyCodeRequest
+): Promise => {
+ const { data } = await cookieAxiosInstance.post(
+ '/api/find-credential/find-password/verify-code',
+ payload
+ );
+ return data;
+};
+
+// step2 - ์ธ์ฆ์ฝ๋ ํ์ธ ํ
+export const usePostVerifyCode = () => {
+ return useMutation({
+ mutationFn: postVerifyCode,
+ });
+};
+
+// step3 - ๋น๋ฐ๋ฒํธ ๋ฆฌ์
API ํจ์
+export const postResetPassword = async (
+ payload: ResetPasswordRequest
+): Promise => {
+ const { data } = await cookieAxiosInstance.post(
+ '/api/find-credential/find-password/reset',
+ payload
+ );
+ return data;
+};
+
+// step3 - ๋น๋ฐ๋ฒํธ ๋ฆฌ์
ํ
+export const usePostResetPassword = () => {
+ return useMutation({
+ mutationFn: postResetPassword,
+ });
+};
diff --git a/src/apis/lifestyle/getLifestyleDevice.ts b/src/apis/lifestyle/getLifestyleDevice.ts
new file mode 100644
index 00000000..0764c2e4
--- /dev/null
+++ b/src/apis/lifestyle/getLifestyleDevice.ts
@@ -0,0 +1,25 @@
+import { axiosInstance } from '@/apis/axios/axios';
+import { useQuery } from '@tanstack/react-query';
+import { queryKey } from '@/constants/queryKey';
+
+import type { LifestyleDeviceResponse, LifestyleTagKey } from '@/types/lifestyle/lifestyle';
+
+export const getLifestyleDevice = async (
+ tagKey: LifestyleTagKey
+): Promise => {
+ const { data } = await axiosInstance.get('/api/lifestyle/featured', {
+ params: { tagKey },
+ });
+
+ return data;
+};
+
+export const useGetLifestyleDevice = (tagKey: LifestyleTagKey) => {
+ return useQuery({
+ queryKey: [queryKey.LIFESTYLE_DEVICE, tagKey],
+ queryFn: () => getLifestyleDevice(tagKey),
+ enabled: !!tagKey,
+ staleTime: 1000 * 60 * 5,
+ placeholderData: (prev) => prev,
+ });
+};
diff --git a/src/apis/mypage/getUserProfile.ts b/src/apis/mypage/getUserProfile.ts
new file mode 100644
index 00000000..dd3815dd
--- /dev/null
+++ b/src/apis/mypage/getUserProfile.ts
@@ -0,0 +1,23 @@
+import { axiosInstance } from '@/apis/axios/axios';
+import type { UserProfileResponse, UserProfileResult } from '@/types/mypage/user';
+import { useQuery } from '@tanstack/react-query';
+import { queryKey } from '@/constants/queryKey';
+import { hasAccessToken } from '@/utils/authStorage';
+
+// ์ ์ ์ ๋ณด ์กฐํ API
+export const getUserProfile = async (): Promise => {
+ const { data } = await axiosInstance.get('/api/mypage/user-profile');
+ return data.result;
+};
+
+// ์ ์ ์ ๋ณด ์กฐํ Query
+export const useGetUserProfile = () => {
+ const hasTokens = hasAccessToken();
+
+ return useQuery({
+ queryKey: [queryKey.USER_PROFILE],
+ queryFn: getUserProfile,
+ enabled: hasTokens, // ํ ํฐ์ด ์์ ๋๋ง ์กฐํ
+ staleTime: 1000 * 60 * 10,
+ });
+};
\ No newline at end of file
diff --git a/src/apis/mypage/patchEditProfile.ts b/src/apis/mypage/patchEditProfile.ts
new file mode 100644
index 00000000..1b6ff66b
--- /dev/null
+++ b/src/apis/mypage/patchEditProfile.ts
@@ -0,0 +1,19 @@
+import { axiosInstance } from '@/apis/axios/axios';
+import { useMutation } from '@tanstack/react-query';
+import type { EditProfileRequest, EditProfileResponse } from '@/types/mypage/editProfile';
+
+export const patchEditProfile = async (
+ payload: EditProfileRequest
+): Promise => {
+ const { data } = await axiosInstance.patch(
+ '/api/mypage/user-profile',
+ payload
+ );
+ return data;
+};
+
+export const usePatchEditProfile = () => {
+ return useMutation({
+ mutationFn: patchEditProfile,
+ });
+};
diff --git a/src/apis/mypage/putEditPassword.ts b/src/apis/mypage/putEditPassword.ts
new file mode 100644
index 00000000..f62cba68
--- /dev/null
+++ b/src/apis/mypage/putEditPassword.ts
@@ -0,0 +1,19 @@
+import { axiosInstance } from '@/apis/axios/axios';
+import { useMutation } from '@tanstack/react-query';
+import type { EditPasswordRequest, EditPasswordResponse } from '@/types/mypage/editPassword';
+
+export const putEditPassword = async (
+ payload: EditPasswordRequest
+): Promise => {
+ const { data } = await axiosInstance.put(
+ '/api/mypage/user-profile/password',
+ payload
+ );
+ return data;
+};
+
+export const usePutEditPassword = () => {
+ return useMutation({
+ mutationFn: putEditPassword,
+ });
+};
diff --git a/src/apis/onboarding/postComplete.ts b/src/apis/onboarding/postComplete.ts
new file mode 100644
index 00000000..03aacb96
--- /dev/null
+++ b/src/apis/onboarding/postComplete.ts
@@ -0,0 +1,22 @@
+import { axiosInstance } from '@/apis/axios/axios';
+import type { PostOnboardingCompleteResponse } from '@/types/onboarding/complete';
+import { useMutation, useQueryClient } from '@tanstack/react-query';
+import { queryKey } from '@/constants/queryKey';
+
+// ์จ๋ณด๋ฉ ์๋ฃ API
+export const postOnboardingComplete = async (): Promise => {
+ const { data } = await axiosInstance.post('/api/onboarding/complete', {});
+ return data;
+};
+
+// ์จ๋ณด๋ฉ ์๋ฃ Mutation
+export const usePostOnboardingComplete = () => {
+ const queryClient = useQueryClient();
+ return useMutation({
+ mutationFn: postOnboardingComplete,
+ onSuccess: async () => {
+ // ์จ๋ณด๋ฉ ์๋ฃ ์ ์ ์ ํ๋กํ refetch ์๋ฃ๊น์ง ๋๊ธฐ (๊ฐ๋์์ ์ต์ ๋ฐ์ดํฐ ์ฌ์ฉ)
+ await queryClient.refetchQueries({ queryKey: [queryKey.USER_PROFILE] });
+ },
+ });
+};
diff --git a/src/apis/recentlyViewed/getRecentlyViewed.ts b/src/apis/recentlyViewed/getRecentlyViewed.ts
new file mode 100644
index 00000000..89037d20
--- /dev/null
+++ b/src/apis/recentlyViewed/getRecentlyViewed.ts
@@ -0,0 +1,19 @@
+import { axiosInstance } from '@/apis/axios/axios';
+import { useQuery } from '@tanstack/react-query';
+import { queryKey } from '@/constants/queryKey';
+import type { RecentlyViewedDevicesResponse, RecentlyViewedDevice } from '@/types/recentlyViewed/recentlyViewed';
+
+// ์ต๊ทผ ๋ณธ ๊ธฐ๊ธฐ ๋ชฉ๋ก ์กฐํ API
+export const getRecentlyViewed = async (): Promise => {
+ const { data } = await axiosInstance.get('/api/recently-viewed');
+ return data.result ?? [];
+};
+
+// ์ต๊ทผ ๋ณธ ๊ธฐ๊ธฐ ๋ชฉ๋ก ์กฐํ Query
+export const useGetRecentlyViewed = () => {
+ return useQuery({
+ queryKey: [queryKey.RECENTLY_VIEWED],
+ queryFn: getRecentlyViewed,
+ staleTime: 1000 * 30, // 30์ด๊ฐ ์บ์ ์ ์ง
+ });
+};
diff --git a/src/apis/recentlyViewed/postRecentlyViewed.ts b/src/apis/recentlyViewed/postRecentlyViewed.ts
new file mode 100644
index 00000000..b1102300
--- /dev/null
+++ b/src/apis/recentlyViewed/postRecentlyViewed.ts
@@ -0,0 +1,24 @@
+import { axiosInstance } from '@/apis/axios/axios';
+import { useMutation, useQueryClient } from '@tanstack/react-query';
+import { queryKey } from '@/constants/queryKey';
+import type { CommonResponse } from '@/types/common';
+
+// ์ต๊ทผ ๋ณธ ๊ธฐ๊ธฐ ๊ธฐ๋ก API
+export const postRecentlyViewed = async (deviceId: number): Promise => {
+ const { data } = await axiosInstance.post(
+ `/api/recently-viewed/${deviceId}`
+ );
+ return data;
+};
+
+// ์ต๊ทผ ๋ณธ ๊ธฐ๊ธฐ ๊ธฐ๋ก Mutation
+export const usePostRecentlyViewed = () => {
+ const queryClient = useQueryClient();
+
+ return useMutation({
+ mutationFn: (deviceId: number) => postRecentlyViewed(deviceId),
+ onSuccess: () => {
+ queryClient.invalidateQueries({ queryKey: [queryKey.RECENTLY_VIEWED] });
+ },
+ });
+};
diff --git a/src/apis/tag/getTags.ts b/src/apis/tag/getTags.ts
new file mode 100644
index 00000000..26b5c361
--- /dev/null
+++ b/src/apis/tag/getTags.ts
@@ -0,0 +1,23 @@
+import { axiosInstance } from '@/apis/axios/axios';
+import type { GetTagsResponse, GetTagsResult } from '@/types/tag/tag';
+import { useQuery } from '@tanstack/react-query';
+import { queryKey } from '@/constants/queryKey';
+
+// ํ๊ทธ ๋ชฉ๋ก ์กฐํ API
+// ์ ์ฒด ํ๊ทธ๋ฅผ ๊ฐ์ ธ์ค๋ ค๋ฉด ํญ์ type: 'LIFESTYLE'์ ๋ณด๋ด์ผ ํจ
+export const getTags = async (): Promise => {
+ const { data } = await axiosInstance.get('/api/tags', {
+ params: { type: 'LIFESTYLE' },
+ });
+ return data.result ?? [];
+};
+
+// ํ๊ทธ ๋ชฉ๋ก ์กฐํ Query
+export const useGetTags = () => {
+ return useQuery({
+ queryKey: [queryKey.TAGS],
+ queryFn: getTags,
+ staleTime: 1000 * 60 * 60, // 1์๊ฐ
+ gcTime: 1000 * 60 * 60 * 24, // 24์๊ฐ
+ });
+};
diff --git a/src/apis/tag/postTags.ts b/src/apis/tag/postTags.ts
new file mode 100644
index 00000000..42fb0a00
--- /dev/null
+++ b/src/apis/tag/postTags.ts
@@ -0,0 +1,22 @@
+import { axiosInstance } from '@/apis/axios/axios';
+import type { PostUserTagsRequest, PostUserTagsResponse } from '@/types/tag/tag';
+import { useMutation, useQueryClient } from '@tanstack/react-query';
+import { queryKey } from '@/constants/queryKey';
+
+// ์ ์ ํ๊ทธ ์ ์ฅ API (replace ๋์)
+export const postUserTags = async (payload: PostUserTagsRequest): Promise => {
+ const { data } = await axiosInstance.post('/api/tags/user', payload);
+ return data;
+};
+
+// ์ ์ ํ๊ทธ ์ ์ฅ Mutation
+export const usePostUserTags = () => {
+ const queryClient = useQueryClient();
+ return useMutation({
+ mutationFn: postUserTags,
+ onSuccess: async () => {
+ // ํ๊ทธ ์ ์ฅ ์ฑ๊ณต ์ ์ ์ ํ๋กํ refetch ์๋ฃ๊น์ง ๋๊ธฐ (๋ค์ ํ์ด์ง์์ ์ต์ ๋ฐ์ดํฐ ์ฌ์ฉ)
+ await queryClient.refetchQueries({ queryKey: [queryKey.USER_PROFILE] });
+ },
+ });
+};
diff --git a/src/assets/fonts/KIMM_bold.woff2 b/src/assets/fonts/KIMM_bold.woff2
new file mode 100644
index 00000000..b069578d
Binary files /dev/null and b/src/assets/fonts/KIMM_bold.woff2 differ
diff --git a/src/assets/fonts/WantedSansVariable.woff2 b/src/assets/fonts/WantedSansVariable.woff2
new file mode 100644
index 00000000..edca6ec9
Binary files /dev/null and b/src/assets/fonts/WantedSansVariable.woff2 differ
diff --git a/src/assets/icons/X.svg b/src/assets/icons/X.svg
new file mode 100644
index 00000000..0316ab5c
--- /dev/null
+++ b/src/assets/icons/X.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/assets/icons/alarm.svg b/src/assets/icons/alarm.svg
new file mode 100644
index 00000000..b683b836
--- /dev/null
+++ b/src/assets/icons/alarm.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/icons/back.svg b/src/assets/icons/back.svg
new file mode 100644
index 00000000..4dc809df
--- /dev/null
+++ b/src/assets/icons/back.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/assets/icons/back_gray.svg b/src/assets/icons/back_gray.svg
new file mode 100644
index 00000000..1aded9d2
--- /dev/null
+++ b/src/assets/icons/back_gray.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/icons/cancel.svg b/src/assets/icons/cancel.svg
new file mode 100644
index 00000000..f3b25411
--- /dev/null
+++ b/src/assets/icons/cancel.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/assets/icons/charge.svg b/src/assets/icons/charge.svg
new file mode 100644
index 00000000..b7386fec
--- /dev/null
+++ b/src/assets/icons/charge.svg
@@ -0,0 +1,6 @@
+
diff --git a/src/assets/icons/checkbox.svg b/src/assets/icons/checkbox.svg
new file mode 100644
index 00000000..c52dd5f6
--- /dev/null
+++ b/src/assets/icons/checkbox.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/icons/checkbox_on.svg b/src/assets/icons/checkbox_on.svg
new file mode 100644
index 00000000..6448b7ed
--- /dev/null
+++ b/src/assets/icons/checkbox_on.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/icons/closedeye.svg b/src/assets/icons/closedeye.svg
new file mode 100644
index 00000000..be520238
--- /dev/null
+++ b/src/assets/icons/closedeye.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/icons/connectivity.svg b/src/assets/icons/connectivity.svg
new file mode 100644
index 00000000..86022d9b
--- /dev/null
+++ b/src/assets/icons/connectivity.svg
@@ -0,0 +1,12 @@
+
diff --git a/src/assets/icons/dropdown.svg b/src/assets/icons/dropdown.svg
new file mode 100644
index 00000000..1d62b0cc
--- /dev/null
+++ b/src/assets/icons/dropdown.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/icons/ellipse_black.svg b/src/assets/icons/ellipse_black.svg
new file mode 100644
index 00000000..dafe9283
--- /dev/null
+++ b/src/assets/icons/ellipse_black.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/icons/ellipse_gray.svg b/src/assets/icons/ellipse_gray.svg
new file mode 100644
index 00000000..ee6ca192
--- /dev/null
+++ b/src/assets/icons/ellipse_gray.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/icons/eye.svg b/src/assets/icons/eye.svg
new file mode 100644
index 00000000..6bb63642
--- /dev/null
+++ b/src/assets/icons/eye.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/icons/filter.svg b/src/assets/icons/filter.svg
new file mode 100644
index 00000000..d6e0e9ab
--- /dev/null
+++ b/src/assets/icons/filter.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/icons/headset.svg b/src/assets/icons/headset.svg
new file mode 100644
index 00000000..e34e4b7b
--- /dev/null
+++ b/src/assets/icons/headset.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/assets/icons/keyboard.svg b/src/assets/icons/keyboard.svg
new file mode 100644
index 00000000..d32c507d
--- /dev/null
+++ b/src/assets/icons/keyboard.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/icons/laptop.svg b/src/assets/icons/laptop.svg
new file mode 100644
index 00000000..a458759d
--- /dev/null
+++ b/src/assets/icons/laptop.svg
@@ -0,0 +1,5 @@
+
diff --git a/src/assets/icons/lifestyle.svg b/src/assets/icons/lifestyle.svg
new file mode 100644
index 00000000..cc566031
--- /dev/null
+++ b/src/assets/icons/lifestyle.svg
@@ -0,0 +1,16 @@
+
diff --git a/src/assets/icons/logicevaluation.svg b/src/assets/icons/logicevaluation.svg
new file mode 100644
index 00000000..227db9f0
--- /dev/null
+++ b/src/assets/icons/logicevaluation.svg
@@ -0,0 +1,14 @@
+
diff --git a/src/assets/icons/more.svg b/src/assets/icons/more.svg
new file mode 100644
index 00000000..782dd196
--- /dev/null
+++ b/src/assets/icons/more.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/icons/mouse.svg b/src/assets/icons/mouse.svg
new file mode 100644
index 00000000..3cfda922
--- /dev/null
+++ b/src/assets/icons/mouse.svg
@@ -0,0 +1,5 @@
+
diff --git a/src/assets/icons/onboarding_lines.svg b/src/assets/icons/onboarding_lines.svg
new file mode 100644
index 00000000..09ecfb2c
--- /dev/null
+++ b/src/assets/icons/onboarding_lines.svg
@@ -0,0 +1,22 @@
+
diff --git a/src/assets/icons/phone.svg b/src/assets/icons/phone.svg
new file mode 100644
index 00000000..9e109cd7
--- /dev/null
+++ b/src/assets/icons/phone.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/assets/icons/plus.svg b/src/assets/icons/plus.svg
new file mode 100644
index 00000000..8d880e78
--- /dev/null
+++ b/src/assets/icons/plus.svg
@@ -0,0 +1,19 @@
+
diff --git a/src/assets/icons/portability.svg b/src/assets/icons/portability.svg
new file mode 100644
index 00000000..dedde9d2
--- /dev/null
+++ b/src/assets/icons/portability.svg
@@ -0,0 +1,11 @@
+
diff --git a/src/assets/icons/remove.svg b/src/assets/icons/remove.svg
new file mode 100644
index 00000000..43618974
--- /dev/null
+++ b/src/assets/icons/remove.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/assets/icons/save.svg b/src/assets/icons/save.svg
new file mode 100644
index 00000000..3e295e50
--- /dev/null
+++ b/src/assets/icons/save.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/icons/search.svg b/src/assets/icons/search.svg
new file mode 100644
index 00000000..30d2859d
--- /dev/null
+++ b/src/assets/icons/search.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/icons/setting.svg b/src/assets/icons/setting.svg
new file mode 100644
index 00000000..e16f3985
--- /dev/null
+++ b/src/assets/icons/setting.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/icons/settingmore.svg b/src/assets/icons/settingmore.svg
new file mode 100644
index 00000000..caac8cb4
--- /dev/null
+++ b/src/assets/icons/settingmore.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/icons/star.svg b/src/assets/icons/star.svg
new file mode 100644
index 00000000..33ccc802
--- /dev/null
+++ b/src/assets/icons/star.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/icons/starhover.svg b/src/assets/icons/starhover.svg
new file mode 100644
index 00000000..523883ff
--- /dev/null
+++ b/src/assets/icons/starhover.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/assets/icons/starx.svg b/src/assets/icons/starx.svg
new file mode 100644
index 00000000..5e0a0596
--- /dev/null
+++ b/src/assets/icons/starx.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/icons/support.svg b/src/assets/icons/support.svg
new file mode 100644
index 00000000..617bf8a5
--- /dev/null
+++ b/src/assets/icons/support.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/icons/tablet.svg b/src/assets/icons/tablet.svg
new file mode 100644
index 00000000..e299d2e1
--- /dev/null
+++ b/src/assets/icons/tablet.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/icons/top.svg b/src/assets/icons/top.svg
new file mode 100644
index 00000000..fdd32c2e
--- /dev/null
+++ b/src/assets/icons/top.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/assets/icons/trash.svg b/src/assets/icons/trash.svg
new file mode 100644
index 00000000..7fee4a0b
--- /dev/null
+++ b/src/assets/icons/trash.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/icons/userblack.svg b/src/assets/icons/userblack.svg
new file mode 100644
index 00000000..833f50bb
--- /dev/null
+++ b/src/assets/icons/userblack.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/icons/userblue500.svg b/src/assets/icons/userblue500.svg
new file mode 100644
index 00000000..66ed8a66
--- /dev/null
+++ b/src/assets/icons/userblue500.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/icons/userblue600.svg b/src/assets/icons/userblue600.svg
new file mode 100644
index 00000000..9ddc6dd8
--- /dev/null
+++ b/src/assets/icons/userblue600.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/icons/warning.svg b/src/assets/icons/warning.svg
new file mode 100644
index 00000000..e15b790e
--- /dev/null
+++ b/src/assets/icons/warning.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/icons/watch.svg b/src/assets/icons/watch.svg
new file mode 100644
index 00000000..03218491
--- /dev/null
+++ b/src/assets/icons/watch.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/images/combination/stage1.svg b/src/assets/images/combination/stage1.svg
new file mode 100644
index 00000000..b9cfdd63
--- /dev/null
+++ b/src/assets/images/combination/stage1.svg
@@ -0,0 +1,9 @@
+
diff --git a/src/assets/images/combination/stage2.svg b/src/assets/images/combination/stage2.svg
new file mode 100644
index 00000000..22855159
--- /dev/null
+++ b/src/assets/images/combination/stage2.svg
@@ -0,0 +1,9 @@
+
diff --git a/src/assets/images/combination/stage3.svg b/src/assets/images/combination/stage3.svg
new file mode 100644
index 00000000..63e9c345
--- /dev/null
+++ b/src/assets/images/combination/stage3.svg
@@ -0,0 +1,9 @@
+
diff --git a/src/assets/images/error/Error404.svg b/src/assets/images/error/Error404.svg
new file mode 100644
index 00000000..29ef0b07
--- /dev/null
+++ b/src/assets/images/error/Error404.svg
@@ -0,0 +1,564 @@
+
diff --git a/src/assets/images/home/HomeImage1.svg b/src/assets/images/home/HomeImage1.svg
new file mode 100644
index 00000000..955e527d
--- /dev/null
+++ b/src/assets/images/home/HomeImage1.svg
@@ -0,0 +1,9 @@
+
diff --git a/src/assets/images/home/HomeImage2.svg b/src/assets/images/home/HomeImage2.svg
new file mode 100644
index 00000000..cf052a90
--- /dev/null
+++ b/src/assets/images/home/HomeImage2.svg
@@ -0,0 +1,9 @@
+
diff --git a/src/assets/images/home/HomeImage3.svg b/src/assets/images/home/HomeImage3.svg
new file mode 100644
index 00000000..780fedd9
--- /dev/null
+++ b/src/assets/images/home/HomeImage3.svg
@@ -0,0 +1,9 @@
+