diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2072dc6..f4b5159 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -67,6 +67,34 @@ jobs: - name: Check code formatting run: cargo fmt --all -- --check + lint-frontend: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - uses: pnpm/action-setup@v4 + with: + version: 10 + run_install: false + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 22 + cache: 'pnpm' + cache-dependency-path: apps/frontend/pnpm-lock.yaml + + - name: Install frontend dependencies + run: | + cd apps/frontend + pnpm install + + - name: Run frontend linter + run: | + cd apps/frontend + pnpm lint + test-frontend: runs-on: ubuntu-latest steps: diff --git a/apps/frontend/eslint.config.ts b/apps/frontend/eslint.config.ts index 54d3c84..ec18c0f 100644 --- a/apps/frontend/eslint.config.ts +++ b/apps/frontend/eslint.config.ts @@ -21,9 +21,6 @@ export default tseslint.config( tsconfigRootDir: import.meta.dirname, }, }, - rules: { - // Add custom rules here - 'no-console': 'warn', - }, + rules: {}, } ); diff --git a/apps/frontend/package.json b/apps/frontend/package.json index 25b65b1..def6cce 100644 --- a/apps/frontend/package.json +++ b/apps/frontend/package.json @@ -15,14 +15,18 @@ "@radix-ui/themes": "^3.2.1", "@react-router/node": "^7.9.2", "@react-router/serve": "^7.9.2", + "@tanstack/react-form": "^1.27.5", "@tanstack/react-query": "^5.90.12", "axios": "^1.13.2", "globals": "^16.5.0", "isbot": "^5.1.31", + "lucide-react": "^0.562.0", "radix-ui": "^1.4.3", "react": "^19.1.1", "react-dom": "^19.1.1", - "react-router": "^7.9.2" + "react-router": "^7.9.2", + "react-toastify": "^11.0.5", + "valibot": "^1.2.0" }, "devDependencies": { "@eslint/js": "^9.39.2", diff --git a/apps/frontend/pnpm-lock.yaml b/apps/frontend/pnpm-lock.yaml index 613eeeb..2487cea 100644 --- a/apps/frontend/pnpm-lock.yaml +++ b/apps/frontend/pnpm-lock.yaml @@ -17,6 +17,9 @@ importers: '@react-router/serve': specifier: ^7.9.2 version: 7.9.6(react-router@7.9.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(typescript@5.9.3) + '@tanstack/react-form': + specifier: ^1.27.5 + version: 1.27.5(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@tanstack/react-query': specifier: ^5.90.12 version: 5.90.12(react@19.2.0) @@ -29,6 +32,9 @@ importers: isbot: specifier: ^5.1.31 version: 5.1.32 + lucide-react: + specifier: ^0.562.0 + version: 0.562.0(react@19.2.0) radix-ui: specifier: ^1.4.3 version: 1.4.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -41,6 +47,12 @@ importers: react-router: specifier: ^7.9.2 version: 7.9.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react-toastify: + specifier: ^11.0.5 + version: 11.0.5(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + valibot: + specifier: ^1.2.0 + version: 1.2.0(typescript@5.9.3) devDependencies: '@eslint/js': specifier: ^9.39.2 @@ -1482,14 +1494,46 @@ packages: peerDependencies: vite: ^5.2.0 || ^6 || ^7 + '@tanstack/devtools-event-client@0.4.0': + resolution: {integrity: sha512-RPfGuk2bDZgcu9bAJodvO2lnZeHuz4/71HjZ0bGb/SPg8+lyTA+RLSKQvo7fSmPSi8/vcH3aKQ8EM9ywf1olaw==} + engines: {node: '>=18'} + + '@tanstack/form-core@1.27.5': + resolution: {integrity: sha512-A8EriWfn+2QsxEbzt6AXn6CC6ILv3VPDXhBDAeE5LTiCHryy7xuj+zo1Q2JWBkhJxS1AuEgY1BZr5AP2mWiHQQ==} + + '@tanstack/pacer-lite@0.1.1': + resolution: {integrity: sha512-y/xtNPNt/YeyoVxE/JCx+T7yjEzpezmbb+toK8DDD1P4m7Kzs5YR956+7OKexG3f8aXgC3rLZl7b1V+yNUSy5w==} + engines: {node: '>=18'} + '@tanstack/query-core@5.90.12': resolution: {integrity: sha512-T1/8t5DhV/SisWjDnaiU2drl6ySvsHj1bHBCWNXd+/T+Hh1cf6JodyEYMd5sgwm+b/mETT4EV3H+zCVczCU5hg==} + '@tanstack/react-form@1.27.5': + resolution: {integrity: sha512-B0nSrlOh4+i/zq2U2ezyRYVz4+6vVzviVAFSZL3FCrJiwryEPM4/0E/RpwkbMZiY2UHp/4KHenPcBQZGhXS+tw==} + peerDependencies: + '@tanstack/react-start': '*' + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@tanstack/react-start': + optional: true + '@tanstack/react-query@5.90.12': resolution: {integrity: sha512-graRZspg7EoEaw0a8faiUASCyJrqjKPdqJ9EwuDRUF9mEYJ1YPczI9H+/agJ0mOJkPCJDk0lsz5QTrLZ/jQ2rg==} peerDependencies: react: ^18 || ^19 + '@tanstack/react-store@0.8.0': + resolution: {integrity: sha512-1vG9beLIuB7q69skxK9r5xiLN3ztzIPfSQSs0GfeqWGO2tGIyInZx0x1COhpx97RKaONSoAb8C3dxacWksm1ow==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + '@tanstack/store@0.7.7': + resolution: {integrity: sha512-xa6pTan1bcaqYDS9BDpSiS63qa6EoDkPN9RsRaxHuDdVDNntzq3xNwR5YKTU/V3SkSyC9T4YVOPh2zRQN0nhIQ==} + + '@tanstack/store@0.8.0': + resolution: {integrity: sha512-Om+BO0YfMZe//X2z0uLF2j+75nQga6TpTJgLJQBiq85aOyZNIhkCgleNcud2KQg4k4v9Y9l+Uhru3qWMPGTOzQ==} + '@types/eslint@8.56.12': resolution: {integrity: sha512-03ruubjWyOHlmljCVoxSuNDdmfZDzsrrz0P2LeJsOXr+ZwFQ+0yQIwNCwt/GYhV7Z31fgtXJTAEs+FYlEL851g==} @@ -1744,6 +1788,10 @@ packages: classnames@2.5.1: resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -2501,6 +2549,11 @@ packages: resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} engines: {node: '>=12'} + lucide-react@0.562.0: + resolution: {integrity: sha512-82hOAu7y0dbVuFfmO4bYF1XEwYk/mEbM5E+b1jgci/udUBEE/R7LF5Ip0CCEmXe8AybRM8L+04eP+LGZeDvkiw==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} @@ -2854,6 +2907,12 @@ packages: '@types/react': optional: true + react-toastify@11.0.5: + resolution: {integrity: sha512-EpqHBGvnSTtHYhCPLxML05NLY2ZX0JURbAdNYa6BUkk+amz4wbKBQvoKQAB0ardvSarUBuY4Q4s1sluAzZwkmA==} + peerDependencies: + react: ^18 || ^19 + react-dom: ^18 || ^19 + react@19.2.0: resolution: {integrity: sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==} engines: {node: '>=0.10.0'} @@ -4761,13 +4820,42 @@ snapshots: tailwindcss: 4.1.17 vite: 7.2.6(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.2) + '@tanstack/devtools-event-client@0.4.0': {} + + '@tanstack/form-core@1.27.5': + dependencies: + '@tanstack/devtools-event-client': 0.4.0 + '@tanstack/pacer-lite': 0.1.1 + '@tanstack/store': 0.7.7 + + '@tanstack/pacer-lite@0.1.1': {} + '@tanstack/query-core@5.90.12': {} + '@tanstack/react-form@1.27.5(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@tanstack/form-core': 1.27.5 + '@tanstack/react-store': 0.8.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 + transitivePeerDependencies: + - react-dom + '@tanstack/react-query@5.90.12(react@19.2.0)': dependencies: '@tanstack/query-core': 5.90.12 react: 19.2.0 + '@tanstack/react-store@0.8.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@tanstack/store': 0.8.0 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + use-sync-external-store: 1.6.0(react@19.2.0) + + '@tanstack/store@0.7.7': {} + + '@tanstack/store@0.8.0': {} + '@types/eslint@8.56.12': dependencies: '@types/estree': 1.0.8 @@ -5098,6 +5186,8 @@ snapshots: classnames@2.5.1: {} + clsx@2.1.1: {} + color-convert@2.0.1: dependencies: color-name: 1.1.4 @@ -5962,6 +6052,10 @@ snapshots: lru-cache@7.18.3: {} + lucide-react@0.562.0(react@19.2.0): + dependencies: + react: 19.2.0 + magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -6323,6 +6417,12 @@ snapshots: optionalDependencies: '@types/react': 19.2.7 + react-toastify@11.0.5(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + dependencies: + clsx: 2.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react@19.2.0: {} readdirp@4.1.2: {}