diff --git a/.githooks/pre-commit b/.githooks/pre-commit
new file mode 100755
index 0000000..0284a7a
--- /dev/null
+++ b/.githooks/pre-commit
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+# some (*)nix distros dont have /bin/bash
+
+echo "Frontend linting"
+(cd vinvoor && pnpm --silent run precommit:lint)
+if [ $? -ne 0 ]; then
+ echo "Frontend linting failed. Please fix the errors before committing."
+ exit 1
+fi
+
+echo "Frontend typecheck"
+(cd vinvoor && pnpm --silent run precommit:typecheck)
+if [ $? -ne 0 ]; then
+ echo "Frontend type checking failed. Please fix the errors before committing."
+ exit 1
+fi
diff --git a/.githooks/vinvoor_format_lint b/.githooks/vinvoor_format_lint
deleted file mode 100644
index 41ecf78..0000000
--- a/.githooks/vinvoor_format_lint
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/usr/bin/env bash
-# some (*)nix distros dont have /bin/bash
-
-cd vinvoor/
-
-pnpm run format
-
-if [ $? -ne 0 ]; then
- echo "Error: code improperly formatted!"
- exit 1
-fi
-
-pnpm run lint
-
-if [ $? -ne 0 ]; then
- echo "Error: code improperly linted!"
- exit 1
-fi
-
-exit 0
diff --git a/.github/workflows/vinvoor_format_lint.yml b/.github/workflows/vinvoor.yml
similarity index 54%
rename from .github/workflows/vinvoor_format_lint.yml
rename to .github/workflows/vinvoor.yml
index 3195e8f..b740f45 100644
--- a/.github/workflows/vinvoor_format_lint.yml
+++ b/.github/workflows/vinvoor.yml
@@ -1,16 +1,10 @@
-name: Format and linting
+name: Vinvoor Format, Lint & Typecheck
on:
push:
branches:
- main
- paths:
- - .github/workflows/vinvoor_format_lint.yml
- - 'vinvoor/**'
pull_request:
- paths:
- - .github/workflows/vinvoor_format_lint.yml
- - 'vinvoor/**'
jobs:
format-and-lint:
@@ -20,10 +14,10 @@ jobs:
- name: Checkout code
uses: actions/checkout@v4
- - name: Set up Node.js
+ - name: Setup Node.js
uses: actions/setup-node@v3
with:
- node-version: 20.15.1
+ node-version: 22.8.0
- name: Install pnpm
run: npm install -g pnpm
@@ -32,10 +26,10 @@ jobs:
run: pnpm install
working-directory: vinvoor/
- - name: Run formatter
- run: pnpm prettier --check .
+ - name: Run format & lint
+ run: pnpm eslint .
working-directory: vinvoor/
- - name: Run Linter
- run: pnpm eslint . --max-warnings=0
+ - name: Run typecheck
+ run: pnpm tsc --noEmit
working-directory: vinvoor/
diff --git a/vinvoor/.eslintrc.cjs b/vinvoor/.eslintrc.cjs
deleted file mode 100644
index 6e8698b..0000000
--- a/vinvoor/.eslintrc.cjs
+++ /dev/null
@@ -1,18 +0,0 @@
-module.exports = {
- root: true,
- env: { browser: true, es2020: true },
- extends: [
- "eslint:recommended",
- "plugin:@typescript-eslint/recommended",
- "plugin:react-hooks/recommended",
- ],
- ignorePatterns: ["dist", ".eslintrc.cjs"],
- parser: "@typescript-eslint/parser",
- plugins: ["react-refresh"],
- rules: {
- "react-refresh/only-export-components": [
- "warn",
- { allowConstantExport: true },
- ],
- },
-};
diff --git a/vinvoor/.prettierrc b/vinvoor/.prettierrc
deleted file mode 100644
index aa7dddc..0000000
--- a/vinvoor/.prettierrc
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "tabWidth": 2,
- "arrowParens": "avoid"
-}
diff --git a/vinvoor/eslint.config.mjs b/vinvoor/eslint.config.mjs
index aadd73b..82a73a5 100644
--- a/vinvoor/eslint.config.mjs
+++ b/vinvoor/eslint.config.mjs
@@ -1,28 +1,24 @@
-import { includeIgnoreFile } from "@eslint/compat";
-import eslint from "@eslint/js";
-import eslintConfigPrettier from "eslint-config-prettier";
-import path, { dirname } from "node:path";
-import { fileURLToPath } from "node:url";
-import tseslint from "typescript-eslint";
+import antfu from "@antfu/eslint-config";
-const __dirname = dirname(fileURLToPath(import.meta.url));
-const gitignorePath = path.resolve(__dirname, ".gitignore");
-
-export default tseslint.config(
- eslint.configs.recommended,
- ...tseslint.configs.recommendedTypeChecked,
- ...tseslint.configs.stylisticTypeChecked,
- includeIgnoreFile(gitignorePath),
+export default antfu(
{
- languageOptions: {
- parserOptions: {
- projectService: true,
- tsconfigRootDir: __dirname,
- },
+ stylistic: {
+ quotes: "double",
+ semi: true,
+ },
+
+ react: true,
+
+ typescript: {
+ tsconfigPath: "./tsconfig.json",
+ },
+
+ formatters: true,
+
+ rules: {
+ "react-hooks/exhaustive-deps": "off",
+ "ts/switch-exhaustiveness-check": "off",
+ "ts/strict-boolean-expressions": "off",
},
},
- {
- ignores: ["eslint.config.mjs", ".eslintrc.cjs"],
- },
- eslintConfigPrettier,
);
diff --git a/vinvoor/package.json b/vinvoor/package.json
index 7380f4c..edac4b6 100644
--- a/vinvoor/package.json
+++ b/vinvoor/package.json
@@ -1,8 +1,8 @@
{
"name": "vinvoor",
- "private": true,
- "version": "0.0.0",
"type": "module",
+ "version": "0.0.0",
+ "private": true,
"scripts": {
"dev": "vite",
"host": "vite --host",
@@ -42,8 +42,6 @@
"@types/node": "^22.9.0",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
- "@typescript-eslint/eslint-plugin": "^7.18.0",
- "@typescript-eslint/parser": "^7.18.0",
"@vitejs/plugin-react-swc": "^3.7.1",
"eslint": "^9.15.0",
"eslint-config-prettier": "^9.1.0",
diff --git a/vinvoor/pnpm-lock.yaml b/vinvoor/pnpm-lock.yaml
index 8784dcb..fdd5c01 100644
--- a/vinvoor/pnpm-lock.yaml
+++ b/vinvoor/pnpm-lock.yaml
@@ -1120,6 +1120,10 @@ packages:
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true
+ builtin-modules@3.3.0:
+ resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==}
+ engines: {node: '>=6'}
+
callsites@3.1.0:
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
engines: {node: '>=6'}
@@ -1240,7 +1244,162 @@ packages:
resolution: {integrity: sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==}
engines: {node: '>=10'}
peerDependencies:
- eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0
+ eslint: '>=6.0.0'
+
+ eslint-compat-utils@0.6.3:
+ resolution: {integrity: sha512-9IDdksh5pUYP2ZLi7mOdROxVjLY8gY2qKxprmrJ/5Dyqud7M/IFKxF3o0VLlRhITm1pK6Fk7NiBxE39M/VlUcw==}
+ engines: {node: '>=12'}
+ peerDependencies:
+ eslint: '>=6.0.0'
+
+ eslint-config-flat-gitignore@0.3.0:
+ resolution: {integrity: sha512-0Ndxo4qGhcewjTzw52TK06Mc00aDtHNTdeeW2JfONgDcLkRO/n/BteMRzNVpLQYxdCC/dFEilfM9fjjpGIJ9Og==}
+ peerDependencies:
+ eslint: ^9.5.0
+
+ eslint-flat-config-utils@0.4.0:
+ resolution: {integrity: sha512-kfd5kQZC+BMO0YwTol6zxjKX1zAsk8JfSAopbKjKqmENTJcew+yBejuvccAg37cvOrN0Mh+DVbeyznuNWEjt4A==}
+
+ eslint-formatting-reporter@0.0.0:
+ resolution: {integrity: sha512-k9RdyTqxqN/wNYVaTk/ds5B5rA8lgoAmvceYN7bcZMBwU7TuXx5ntewJv81eF3pIL/CiJE+pJZm36llG8yhyyw==}
+ peerDependencies:
+ eslint: '>=8.40.0'
+
+ eslint-import-resolver-node@0.3.9:
+ resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==}
+
+ eslint-json-compat-utils@0.2.1:
+ resolution: {integrity: sha512-YzEodbDyW8DX8bImKhAcCeu/L31Dd/70Bidx2Qex9OFUtgzXLqtfWL4Hr5fM/aCCB8QUZLuJur0S9k6UfgFkfg==}
+ engines: {node: '>=12'}
+ peerDependencies:
+ '@eslint/json': '*'
+ eslint: '*'
+ jsonc-eslint-parser: ^2.4.0
+ peerDependenciesMeta:
+ '@eslint/json':
+ optional: true
+
+ eslint-merge-processors@0.1.0:
+ resolution: {integrity: sha512-IvRXXtEajLeyssvW4wJcZ2etxkR9mUf4zpNwgI+m/Uac9RfXHskuJefkHUcawVzePnd6xp24enp5jfgdHzjRdQ==}
+ peerDependencies:
+ eslint: '*'
+
+ eslint-parser-plain@0.1.0:
+ resolution: {integrity: sha512-oOeA6FWU0UJT/Rxc3XF5Cq0nbIZbylm7j8+plqq0CZoE6m4u32OXJrR+9iy4srGMmF6v6pmgvP1zPxSRIGh3sg==}
+
+ eslint-plugin-antfu@2.7.0:
+ resolution: {integrity: sha512-gZM3jq3ouqaoHmUNszb1Zo2Ux7RckSvkGksjLWz9ipBYGSv1EwwBETN6AdiUXn+RpVHXTbEMPAPlXJazcA6+iA==}
+ peerDependencies:
+ eslint: '*'
+
+ eslint-plugin-command@0.2.6:
+ resolution: {integrity: sha512-T0bHZ1oblW1xUHUVoBKZJR2osSNNGkfZuK4iqboNwuNS/M7tdp3pmURaJtTi/XDzitxaQ02lvOdFH0mUd5QLvQ==}
+ peerDependencies:
+ eslint: '*'
+
+ eslint-plugin-es-x@7.8.0:
+ resolution: {integrity: sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ==}
+ engines: {node: ^14.18.0 || >=16.0.0}
+ peerDependencies:
+ eslint: '>=8'
+
+ eslint-plugin-format@0.1.2:
+ resolution: {integrity: sha512-ZrcO3aiumgJ6ENAv65IWkPjtW77ML/5mp0YrRK0jdvvaZJb+4kKWbaQTMr/XbJo6CtELRmCApAziEKh7L2NbdQ==}
+ peerDependencies:
+ eslint: ^8.40.0 || ^9.0.0
+
+ eslint-plugin-import-x@4.4.2:
+ resolution: {integrity: sha512-mDRXPSLQ0UQZQw91QdG4/qZT6hgeW2MJTczAbgPseUZuPEtIjjdPOolXroRkulnOn3fzj6gNgvk+wchMJiHElg==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0
+
+ eslint-plugin-jsdoc@50.5.0:
+ resolution: {integrity: sha512-xTkshfZrUbiSHXBwZ/9d5ulZ2OcHXxSvm/NPo494H/hadLRJwOq5PMV0EUpMqsb9V+kQo+9BAgi6Z7aJtdBp2A==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ eslint: ^7.0.0 || ^8.0.0 || ^9.0.0
+
+ eslint-plugin-jsonc@2.18.2:
+ resolution: {integrity: sha512-SDhJiSsWt3nItl/UuIv+ti4g3m4gpGkmnUJS9UWR3TrpyNsIcnJoBRD7Kof6cM4Rk3L0wrmY5Tm3z7ZPjR2uGg==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ peerDependencies:
+ eslint: '>=6.0.0'
+
+ eslint-plugin-n@17.13.2:
+ resolution: {integrity: sha512-MhBAKkT01h8cOXcTBTlpuR7bxH5OBUNpUXefsvwSVEy46cY4m/Kzr2osUCQvA3zJFD6KuCeNNDv0+HDuWk/OcA==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ eslint: '>=8.23.0'
+
+ eslint-plugin-no-only-tests@3.3.0:
+ resolution: {integrity: sha512-brcKcxGnISN2CcVhXJ/kEQlNa0MEfGRtwKtWA16SkqXHKitaKIMrfemJKLKX1YqDU5C/5JY3PvZXd5jEW04e0Q==}
+ engines: {node: '>=5.0.0'}
+
+ eslint-plugin-perfectionist@3.9.1:
+ resolution: {integrity: sha512-9WRzf6XaAxF4Oi5t/3TqKP5zUjERhasHmLFHin2Yw6ZAp/EP/EVA2dr3BhQrrHWCm5SzTMZf0FcjDnBkO2xFkA==}
+ engines: {node: ^18.0.0 || >=20.0.0}
+ peerDependencies:
+ astro-eslint-parser: ^1.0.2
+ eslint: '>=8.0.0'
+ svelte: '>=3.0.0'
+ svelte-eslint-parser: ^0.41.1
+ vue-eslint-parser: '>=9.0.0'
+ peerDependenciesMeta:
+ astro-eslint-parser:
+ optional: true
+ svelte:
+ optional: true
+ svelte-eslint-parser:
+ optional: true
+ vue-eslint-parser:
+ optional: true
+
+ eslint-plugin-react-debug@1.16.1:
+ resolution: {integrity: sha512-AijumibZ+3hBYCGBEeD3GQse5TPnq9z6bX0qfsFwCwWjkW+siL2EEGvaxT7UZp2mcFMvoRJT3E4Jsemn6g0AGw==}
+ engines: {bun: '>=1.0.15', node: '>=18.18.0'}
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0
+ typescript: ^4.9.5 || ^5.3.3
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ eslint-plugin-react-dom@1.16.1:
+ resolution: {integrity: sha512-qJFfCR2Rofd5/V9/8EE4sg6a829HcI07DeK7qqTosYRPBYkwbfUUjvizzlTxneMAcPQuFfPZa1UMDTaejKStyg==}
+ engines: {bun: '>=1.0.15', node: '>=18.18.0'}
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0
+ typescript: ^4.9.5 || ^5.3.3
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ eslint-plugin-react-hooks-extra@1.16.1:
+ resolution: {integrity: sha512-OJ4RJZ7n25XnF6+NaFC9dzrec2C+/o4zb4Brs+v6fVVbvQQZirgWamKZMOJo+I1HsHdOULtBo1uwopLfnVBihQ==}
+ engines: {bun: '>=1.0.15', node: '>=18.18.0'}
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0
+ typescript: ^4.9.5 || ^5.3.3
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ eslint-plugin-react-hooks@5.1.0-beta-26f2496093-20240514:
+ resolution: {integrity: sha512-nCZD93/KYY5hNAWGhfvvrEXvLFIXJCMu2St7ciHeiWUp/lnS2RVgWawp2kNQamr9Y23C9lUA03TmDRNgbm05vg==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0
+
+ eslint-plugin-react-naming-convention@1.16.1:
+ resolution: {integrity: sha512-qyZ6YW82vLHHQEboc0LhE+9Uga2koCtwEV0XYEWxq3DI3Wg1SlwsfchPYQc7skRh2c/Jh9YG2gzRmNXG4Ul2Ww==}
+ engines: {bun: '>=1.0.15', node: '>=18.18.0'}
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0
+ typescript: ^4.9.5 || ^5.3.3
+ peerDependenciesMeta:
+ typescript:
+ optional: true
eslint-plugin-react-refresh@0.4.14:
resolution: {integrity: sha512-aXvzCTK7ZBv1e7fahFuR3Z/fyQQSIQ711yPgYRj+Oj64tyTgO4iQIDmYXDBqvSWQ/FA4OSCsXOStlF+noU0/NA==}
@@ -1367,6 +1526,9 @@ packages:
peerDependencies:
csstype: ^3.0.10
+ graceful-fs@4.2.11:
+ resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
+
graphemer@1.4.0:
resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
@@ -1448,6 +1610,10 @@ packages:
engines: {node: '>=6'}
hasBin: true
+ jsonc-eslint-parser@2.4.0:
+ resolution: {integrity: sha512-WYDyuc/uFcGp6YtM2H0uKmUwieOuzeE/5YocFJLnLfclZ4inf3mRn8ZVy1s7Hxji7Jxm6Ss8gqpexD/GlKoGgg==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+
keyv@4.5.4:
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
@@ -1482,6 +1648,39 @@ packages:
react: ^17.0.0 || ^18.0.0
react-dom: ^17.0.0 || ^18.0.0
+ mdast-util-find-and-replace@3.0.1:
+ resolution: {integrity: sha512-SG21kZHGC3XRTSUhtofZkBzZTJNM5ecCi0SK2IMKmSXR8vO3peL+kb1O0z7Zl83jKtutG4k5Wv/W7V3/YHvzPA==}
+
+ mdast-util-from-markdown@2.0.2:
+ resolution: {integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==}
+
+ mdast-util-gfm-autolink-literal@2.0.1:
+ resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==}
+
+ mdast-util-gfm-footnote@2.0.0:
+ resolution: {integrity: sha512-5jOT2boTSVkMnQ7LTrd6n/18kqwjmuYqo7JUPe+tRCY6O7dAuTFMtTPauYYrMPpox9hlN0uOx/FL8XvEfG9/mQ==}
+
+ mdast-util-gfm-strikethrough@2.0.0:
+ resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==}
+
+ mdast-util-gfm-table@2.0.0:
+ resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==}
+
+ mdast-util-gfm-task-list-item@2.0.0:
+ resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==}
+
+ mdast-util-gfm@3.0.0:
+ resolution: {integrity: sha512-dgQEX5Amaq+DuUqf26jJqSK9qgixgd6rYDHAv4aTBuA92cTknZlKpPfa86Z/s8Dj8xsAQpFfBmPUHWJBWqS4Bw==}
+
+ mdast-util-phrasing@4.1.0:
+ resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==}
+
+ mdast-util-to-markdown@2.1.2:
+ resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==}
+
+ mdast-util-to-string@4.0.0:
+ resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==}
+
mdi-material-ui@7.9.2:
resolution: {integrity: sha512-MZ5zxN7W6yqtHwNYtV/Ezt6nQtMPsA3UtHcNpHwSDbFdvWgspTKyxh4gS63G8e49qyJAPdq0JMjxV3SEnXu4yQ==}
peerDependencies:
@@ -1511,6 +1710,9 @@ packages:
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
+ natural-compare-lite@1.4.0:
+ resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==}
+
natural-compare@1.4.0:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
@@ -1527,6 +1729,9 @@ packages:
react: ^16.8.0 || ^17.0.0 || ^18.0.0
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
+ nth-check@2.1.1:
+ resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
+
object-assign@4.1.1:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'}
@@ -1791,6 +1996,9 @@ packages:
engines: {node: '>=14.17'}
hasBin: true
+ ufo@1.5.4:
+ resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==}
+
undici-types@6.19.8:
resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==}
@@ -1839,6 +2047,12 @@ packages:
terser:
optional: true
+ vue-eslint-parser@9.4.3:
+ resolution: {integrity: sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==}
+ engines: {node: ^14.17.0 || >=16.0.0}
+ peerDependencies:
+ eslint: '>=6.0.0'
+
which@2.0.2:
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
engines: {node: '>= 8'}
@@ -2730,7 +2944,6 @@ snapshots:
eslint: 9.15.0
transitivePeerDependencies:
- supports-color
- - typescript
'@typescript-eslint/utils@8.15.0(eslint@9.15.0)(typescript@5.6.3)':
dependencies:
@@ -2776,6 +2989,8 @@ snapshots:
json-schema-traverse: 0.4.1
uri-js: 4.4.1
+ ansi-regex@5.0.1: {}
+
ansi-styles@4.3.0:
dependencies:
color-convert: 2.0.1
@@ -2790,9 +3005,9 @@ snapshots:
svg.resize.js: 1.4.3
svg.select.js: 3.0.1
- argparse@2.0.1: {}
+ are-docs-informative@0.0.2: {}
- array-union@2.1.0: {}
+ argparse@2.0.1: {}
babel-plugin-macros@3.1.0:
dependencies:
@@ -2802,6 +3017,10 @@ snapshots:
balanced-match@1.0.2: {}
+ birecord@0.1.1: {}
+
+ boolbase@1.0.0: {}
+
brace-expansion@1.1.11:
dependencies:
balanced-match: 1.0.2
@@ -2822,6 +3041,8 @@ snapshots:
node-releases: 2.0.18
update-browserslist-db: 1.1.1(browserslist@4.24.2)
+ builtin-modules@3.3.0: {}
+
callsites@3.1.0: {}
camelcase@6.3.0: {}
@@ -2833,8 +3054,22 @@ snapshots:
ansi-styles: 4.3.0
supports-color: 7.2.0
+ character-entities@2.0.2: {}
+
+ ci-info@4.1.0: {}
+
classnames@2.5.1: {}
+ clean-regexp@1.0.0:
+ dependencies:
+ escape-string-regexp: 1.0.5
+
+ cliui@8.0.1:
+ dependencies:
+ string-width: 4.2.3
+ strip-ansi: 6.0.1
+ wrap-ansi: 7.0.0
+
clsx@1.2.1: {}
clsx@2.1.1: {}
@@ -2845,12 +3080,20 @@ snapshots:
color-name@1.1.4: {}
+ comment-parser@1.4.1: {}
+
concat-map@0.0.1: {}
+ confbox@0.1.8: {}
+
convert-source-map@1.9.0: {}
convert-source-map@2.0.0: {}
+ core-js-compat@3.39.0:
+ dependencies:
+ browserslist: 4.24.2
+
cosmiconfig@7.1.0:
dependencies:
'@types/parse-json': 4.0.2
@@ -2874,19 +3117,35 @@ snapshots:
shebang-command: 2.0.0
which: 2.0.2
+ cssesc@3.0.0: {}
+
csstype@3.1.3: {}
dayjs@1.11.13: {}
+ debug@3.2.7:
+ dependencies:
+ ms: 2.1.3
+
debug@4.3.7:
dependencies:
ms: 2.1.3
+ decode-named-character-reference@1.0.2:
+ dependencies:
+ character-entities: 2.0.2
+
deep-is@0.1.4: {}
- dir-glob@3.0.1:
+ dequal@2.0.3: {}
+
+ devlop@1.1.0:
dependencies:
- path-type: 4.0.0
+ dequal: 2.0.3
+
+ doctrine@3.0.0:
+ dependencies:
+ esutils: 2.0.3
dom-helpers@5.2.1:
dependencies:
@@ -2906,6 +3165,8 @@ snapshots:
dependencies:
is-arrayish: 0.2.1
+ es-module-lexer@1.5.4: {}
+
esbuild@0.21.5:
optionalDependencies:
'@esbuild/aix-ppc64': 0.21.5
@@ -2934,6 +3195,8 @@ snapshots:
escalade@3.2.0: {}
+ escape-string-regexp@1.0.5: {}
+
escape-string-regexp@4.0.0: {}
eslint-config-prettier@9.1.0(eslint@9.15.0):
@@ -3018,6 +3281,8 @@ snapshots:
fast-deep-equal@3.1.3: {}
+ fast-diff@1.3.0: {}
+
fast-glob@3.3.2:
dependencies:
'@nodelib/fs.stat': 2.0.5
@@ -3044,6 +3309,13 @@ snapshots:
find-root@1.1.0: {}
+ find-up-simple@1.0.0: {}
+
+ find-up@4.1.0:
+ dependencies:
+ locate-path: 5.0.0
+ path-exists: 4.0.0
+
find-up@5.0.0:
dependencies:
locate-path: 6.0.0
@@ -3063,6 +3335,12 @@ snapshots:
gensync@1.0.0-beta.2: {}
+ get-caller-file@2.0.5: {}
+
+ get-tsconfig@4.8.1:
+ dependencies:
+ resolve-pkg-maps: 1.0.0
+
glob-parent@5.1.2:
dependencies:
is-glob: 4.0.3
@@ -3073,21 +3351,20 @@ snapshots:
globals@11.12.0: {}
+ globals@13.24.0:
+ dependencies:
+ type-fest: 0.20.2
+
globals@14.0.0: {}
- globby@11.1.0:
- dependencies:
- array-union: 2.1.0
- dir-glob: 3.0.1
- fast-glob: 3.3.2
- ignore: 5.3.2
- merge2: 1.4.1
- slash: 3.0.0
+ globals@15.12.0: {}
goober@2.1.16(csstype@3.1.3):
dependencies:
csstype: 3.1.3
+ graceful-fs@4.2.11: {}
+
graphemer@1.4.0: {}
has-flag@4.0.0: {}
@@ -3100,6 +3377,8 @@ snapshots:
dependencies:
react-is: 16.13.1
+ hosted-git-info@2.8.9: {}
+
ignore@5.3.2: {}
import-fresh@3.3.0:
@@ -3109,18 +3388,36 @@ snapshots:
imurmurhash@0.1.4: {}
+ indent-string@4.0.0: {}
+
is-arrayish@0.2.1: {}
+ is-builtin-module@3.2.1:
+ dependencies:
+ builtin-modules: 3.3.0
+
is-core-module@2.15.1:
dependencies:
hasown: 2.0.2
is-extglob@2.1.1: {}
+ is-fullwidth-code-point@3.0.0: {}
+
is-glob@4.0.3:
dependencies:
is-extglob: 2.1.1
+ is-immutable-type@5.0.0(eslint@9.15.0)(typescript@5.6.3):
+ dependencies:
+ '@typescript-eslint/type-utils': 8.15.0(eslint@9.15.0)(typescript@5.6.3)
+ eslint: 9.15.0
+ ts-api-utils: 1.4.0(typescript@5.6.3)
+ ts-declaration-location: 1.0.4(typescript@5.6.3)
+ typescript: 5.6.3
+ transitivePeerDependencies:
+ - supports-color
+
is-number@7.0.0: {}
isexe@2.0.0: {}
@@ -3133,6 +3430,10 @@ snapshots:
dependencies:
argparse: 2.0.1
+ jsdoc-type-pratt-parser@4.1.0: {}
+
+ jsesc@0.5.0: {}
+
jsesc@3.0.2: {}
json-buffer@3.0.1: {}
@@ -3145,6 +3446,13 @@ snapshots:
json5@2.2.3: {}
+ jsonc-eslint-parser@2.4.0:
+ dependencies:
+ acorn: 8.14.0
+ eslint-visitor-keys: 3.4.3
+ espree: 9.6.1
+ semver: 7.6.3
+
keyv@4.5.4:
dependencies:
json-buffer: 3.0.1
@@ -3156,12 +3464,25 @@ snapshots:
lines-and-columns@1.2.4: {}
+ local-pkg@0.5.1:
+ dependencies:
+ mlly: 1.7.3
+ pkg-types: 1.2.1
+
+ locate-path@5.0.0:
+ dependencies:
+ p-locate: 4.1.0
+
locate-path@6.0.0:
dependencies:
p-locate: 5.0.0
lodash.merge@4.6.2: {}
+ lodash@4.17.21: {}
+
+ longest-streak@3.1.0: {}
+
loose-envify@1.4.0:
dependencies:
js-tokens: 4.0.0
@@ -3174,12 +3495,120 @@ snapshots:
dependencies:
yallist: 3.1.1
+ magic-string@0.30.13:
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.5.0
+
+ markdown-table@3.0.4: {}
+
material-ui-confirm@3.0.16(@mui/material@5.16.7(@emotion/react@11.13.3(@types/react@18.3.12)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.12)(react@18.3.1))(@types/react@18.3.12)(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
'@mui/material': 5.16.7(@emotion/react@11.13.3(@types/react@18.3.12)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.12)(react@18.3.1))(@types/react@18.3.12)(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
+ mdast-util-find-and-replace@3.0.1:
+ dependencies:
+ '@types/mdast': 4.0.4
+ escape-string-regexp: 5.0.0
+ unist-util-is: 6.0.0
+ unist-util-visit-parents: 6.0.1
+
+ mdast-util-from-markdown@2.0.2:
+ dependencies:
+ '@types/mdast': 4.0.4
+ '@types/unist': 3.0.3
+ decode-named-character-reference: 1.0.2
+ devlop: 1.1.0
+ mdast-util-to-string: 4.0.0
+ micromark: 4.0.1
+ micromark-util-decode-numeric-character-reference: 2.0.2
+ micromark-util-decode-string: 2.0.1
+ micromark-util-normalize-identifier: 2.0.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.1
+ unist-util-stringify-position: 4.0.0
+ transitivePeerDependencies:
+ - supports-color
+
+ mdast-util-gfm-autolink-literal@2.0.1:
+ dependencies:
+ '@types/mdast': 4.0.4
+ ccount: 2.0.1
+ devlop: 1.1.0
+ mdast-util-find-and-replace: 3.0.1
+ micromark-util-character: 2.1.1
+
+ mdast-util-gfm-footnote@2.0.0:
+ dependencies:
+ '@types/mdast': 4.0.4
+ devlop: 1.1.0
+ mdast-util-from-markdown: 2.0.2
+ mdast-util-to-markdown: 2.1.2
+ micromark-util-normalize-identifier: 2.0.1
+ transitivePeerDependencies:
+ - supports-color
+
+ mdast-util-gfm-strikethrough@2.0.0:
+ dependencies:
+ '@types/mdast': 4.0.4
+ mdast-util-from-markdown: 2.0.2
+ mdast-util-to-markdown: 2.1.2
+ transitivePeerDependencies:
+ - supports-color
+
+ mdast-util-gfm-table@2.0.0:
+ dependencies:
+ '@types/mdast': 4.0.4
+ devlop: 1.1.0
+ markdown-table: 3.0.4
+ mdast-util-from-markdown: 2.0.2
+ mdast-util-to-markdown: 2.1.2
+ transitivePeerDependencies:
+ - supports-color
+
+ mdast-util-gfm-task-list-item@2.0.0:
+ dependencies:
+ '@types/mdast': 4.0.4
+ devlop: 1.1.0
+ mdast-util-from-markdown: 2.0.2
+ mdast-util-to-markdown: 2.1.2
+ transitivePeerDependencies:
+ - supports-color
+
+ mdast-util-gfm@3.0.0:
+ dependencies:
+ mdast-util-from-markdown: 2.0.2
+ mdast-util-gfm-autolink-literal: 2.0.1
+ mdast-util-gfm-footnote: 2.0.0
+ mdast-util-gfm-strikethrough: 2.0.0
+ mdast-util-gfm-table: 2.0.0
+ mdast-util-gfm-task-list-item: 2.0.0
+ mdast-util-to-markdown: 2.1.2
+ transitivePeerDependencies:
+ - supports-color
+
+ mdast-util-phrasing@4.1.0:
+ dependencies:
+ '@types/mdast': 4.0.4
+ unist-util-is: 6.0.0
+
+ mdast-util-to-markdown@2.1.2:
+ dependencies:
+ '@types/mdast': 4.0.4
+ '@types/unist': 3.0.3
+ longest-streak: 3.1.0
+ mdast-util-phrasing: 4.1.0
+ mdast-util-to-string: 4.0.0
+ micromark-util-classify-character: 2.0.1
+ micromark-util-decode-string: 2.0.1
+ unist-util-visit: 5.0.0
+ zwitch: 2.0.4
+
+ mdast-util-to-string@4.0.0:
+ dependencies:
+ '@types/mdast': 4.0.4
+
mdi-material-ui@7.9.2(@mui/material@5.16.7(@emotion/react@11.13.3(@types/react@18.3.12)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.12)(react@18.3.1))(@types/react@18.3.12)(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1):
dependencies:
'@mui/material': 5.16.7(@emotion/react@11.13.3(@types/react@18.3.12)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.12)(react@18.3.1))(@types/react@18.3.12)(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -3187,11 +3616,208 @@ snapshots:
merge2@1.4.1: {}
+ micromark-core-commonmark@2.0.2:
+ dependencies:
+ decode-named-character-reference: 1.0.2
+ devlop: 1.1.0
+ micromark-factory-destination: 2.0.1
+ micromark-factory-label: 2.0.1
+ micromark-factory-space: 2.0.1
+ micromark-factory-title: 2.0.1
+ micromark-factory-whitespace: 2.0.1
+ micromark-util-character: 2.1.1
+ micromark-util-chunked: 2.0.1
+ micromark-util-classify-character: 2.0.1
+ micromark-util-html-tag-name: 2.0.1
+ micromark-util-normalize-identifier: 2.0.1
+ micromark-util-resolve-all: 2.0.1
+ micromark-util-subtokenize: 2.0.2
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.1
+
+ micromark-extension-gfm-autolink-literal@2.1.0:
+ dependencies:
+ micromark-util-character: 2.1.1
+ micromark-util-sanitize-uri: 2.0.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.1
+
+ micromark-extension-gfm-footnote@2.1.0:
+ dependencies:
+ devlop: 1.1.0
+ micromark-core-commonmark: 2.0.2
+ micromark-factory-space: 2.0.1
+ micromark-util-character: 2.1.1
+ micromark-util-normalize-identifier: 2.0.1
+ micromark-util-sanitize-uri: 2.0.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.1
+
+ micromark-extension-gfm-strikethrough@2.1.0:
+ dependencies:
+ devlop: 1.1.0
+ micromark-util-chunked: 2.0.1
+ micromark-util-classify-character: 2.0.1
+ micromark-util-resolve-all: 2.0.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.1
+
+ micromark-extension-gfm-table@2.1.0:
+ dependencies:
+ devlop: 1.1.0
+ micromark-factory-space: 2.0.1
+ micromark-util-character: 2.1.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.1
+
+ micromark-extension-gfm-tagfilter@2.0.0:
+ dependencies:
+ micromark-util-types: 2.0.1
+
+ micromark-extension-gfm-task-list-item@2.1.0:
+ dependencies:
+ devlop: 1.1.0
+ micromark-factory-space: 2.0.1
+ micromark-util-character: 2.1.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.1
+
+ micromark-extension-gfm@3.0.0:
+ dependencies:
+ micromark-extension-gfm-autolink-literal: 2.1.0
+ micromark-extension-gfm-footnote: 2.1.0
+ micromark-extension-gfm-strikethrough: 2.1.0
+ micromark-extension-gfm-table: 2.1.0
+ micromark-extension-gfm-tagfilter: 2.0.0
+ micromark-extension-gfm-task-list-item: 2.1.0
+ micromark-util-combine-extensions: 2.0.1
+ micromark-util-types: 2.0.1
+
+ micromark-factory-destination@2.0.1:
+ dependencies:
+ micromark-util-character: 2.1.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.1
+
+ micromark-factory-label@2.0.1:
+ dependencies:
+ devlop: 1.1.0
+ micromark-util-character: 2.1.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.1
+
+ micromark-factory-space@2.0.1:
+ dependencies:
+ micromark-util-character: 2.1.1
+ micromark-util-types: 2.0.1
+
+ micromark-factory-title@2.0.1:
+ dependencies:
+ micromark-factory-space: 2.0.1
+ micromark-util-character: 2.1.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.1
+
+ micromark-factory-whitespace@2.0.1:
+ dependencies:
+ micromark-factory-space: 2.0.1
+ micromark-util-character: 2.1.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.1
+
+ micromark-util-character@2.1.1:
+ dependencies:
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.1
+
+ micromark-util-chunked@2.0.1:
+ dependencies:
+ micromark-util-symbol: 2.0.1
+
+ micromark-util-classify-character@2.0.1:
+ dependencies:
+ micromark-util-character: 2.1.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.1
+
+ micromark-util-combine-extensions@2.0.1:
+ dependencies:
+ micromark-util-chunked: 2.0.1
+ micromark-util-types: 2.0.1
+
+ micromark-util-decode-numeric-character-reference@2.0.2:
+ dependencies:
+ micromark-util-symbol: 2.0.1
+
+ micromark-util-decode-string@2.0.1:
+ dependencies:
+ decode-named-character-reference: 1.0.2
+ micromark-util-character: 2.1.1
+ micromark-util-decode-numeric-character-reference: 2.0.2
+ micromark-util-symbol: 2.0.1
+
+ micromark-util-encode@2.0.1: {}
+
+ micromark-util-html-tag-name@2.0.1: {}
+
+ micromark-util-normalize-identifier@2.0.1:
+ dependencies:
+ micromark-util-symbol: 2.0.1
+
+ micromark-util-resolve-all@2.0.1:
+ dependencies:
+ micromark-util-types: 2.0.1
+
+ micromark-util-sanitize-uri@2.0.1:
+ dependencies:
+ micromark-util-character: 2.1.1
+ micromark-util-encode: 2.0.1
+ micromark-util-symbol: 2.0.1
+
+ micromark-util-subtokenize@2.0.2:
+ dependencies:
+ devlop: 1.1.0
+ micromark-util-chunked: 2.0.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.1
+
+ micromark-util-symbol@2.0.1: {}
+
+ micromark-util-types@2.0.1: {}
+
+ micromark@4.0.1:
+ dependencies:
+ '@types/debug': 4.1.12
+ debug: 4.3.7
+ decode-named-character-reference: 1.0.2
+ devlop: 1.1.0
+ micromark-core-commonmark: 2.0.2
+ micromark-factory-space: 2.0.1
+ micromark-util-character: 2.1.1
+ micromark-util-chunked: 2.0.1
+ micromark-util-combine-extensions: 2.0.1
+ micromark-util-decode-numeric-character-reference: 2.0.2
+ micromark-util-encode: 2.0.1
+ micromark-util-normalize-identifier: 2.0.1
+ micromark-util-resolve-all: 2.0.1
+ micromark-util-sanitize-uri: 2.0.1
+ micromark-util-subtokenize: 2.0.2
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.1
+ transitivePeerDependencies:
+ - supports-color
+
micromatch@4.0.8:
dependencies:
braces: 3.0.3
picomatch: 2.3.1
+ min-indent@1.0.1: {}
+
+ minimatch@10.0.1:
+ dependencies:
+ brace-expansion: 2.0.1
+
minimatch@3.1.2:
dependencies:
brace-expansion: 1.1.11
@@ -3200,10 +3826,19 @@ snapshots:
dependencies:
brace-expansion: 2.0.1
+ mlly@1.7.3:
+ dependencies:
+ acorn: 8.14.0
+ pathe: 1.1.2
+ pkg-types: 1.2.1
+ ufo: 1.5.4
+
ms@2.1.3: {}
nanoid@3.3.7: {}
+ natural-compare-lite@1.4.0: {}
+
natural-compare@1.4.0: {}
no-case@3.0.4:
@@ -3213,6 +3848,13 @@ snapshots:
node-releases@2.0.18: {}
+ normalize-package-data@2.5.0:
+ dependencies:
+ hosted-git-info: 2.8.9
+ resolve: 1.22.8
+ semver: 5.7.2
+ validate-npm-package-license: 3.0.4
+
notistack@3.0.1(csstype@3.1.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
clsx: 1.2.1
@@ -3222,6 +3864,10 @@ snapshots:
transitivePeerDependencies:
- csstype
+ nth-check@2.1.1:
+ dependencies:
+ boolbase: 1.0.0
+
object-assign@4.1.1: {}
optionator@0.9.4:
@@ -3233,18 +3879,37 @@ snapshots:
type-check: 0.4.0
word-wrap: 1.2.5
+ p-limit@2.3.0:
+ dependencies:
+ p-try: 2.2.0
+
p-limit@3.1.0:
dependencies:
yocto-queue: 0.1.0
+ p-locate@4.1.0:
+ dependencies:
+ p-limit: 2.3.0
+
p-locate@5.0.0:
dependencies:
p-limit: 3.1.0
+ p-try@2.2.0: {}
+
+ package-manager-detector@0.2.4: {}
+
parent-module@1.0.1:
dependencies:
callsites: 3.1.0
+ parse-gitignore@2.0.0: {}
+
+ parse-imports@2.2.1:
+ dependencies:
+ es-module-lexer: 1.5.4
+ slashes: 3.0.12
+
parse-json@5.2.0:
dependencies:
'@babel/code-frame': 7.26.2
@@ -3260,6 +3925,8 @@ snapshots:
path-type@4.0.0: {}
+ pathe@1.1.2: {}
+
picocolors@1.1.1: {}
picomatch@2.3.1: {}
@@ -3274,6 +3941,10 @@ snapshots:
prelude-ls@1.2.1: {}
+ prettier-linter-helpers@1.0.0:
+ dependencies:
+ fast-diff: 1.3.0
+
prettier@3.3.3: {}
prop-types@15.8.1:
@@ -3340,10 +4011,42 @@ snapshots:
dependencies:
loose-envify: 1.4.0
+ read-pkg-up@7.0.1:
+ dependencies:
+ find-up: 4.1.0
+ read-pkg: 5.2.0
+ type-fest: 0.8.1
+
+ read-pkg@5.2.0:
+ dependencies:
+ '@types/normalize-package-data': 2.4.4
+ normalize-package-data: 2.5.0
+ parse-json: 5.2.0
+ type-fest: 0.6.0
+
+ refa@0.12.1:
+ dependencies:
+ '@eslint-community/regexpp': 4.12.1
+
regenerator-runtime@0.14.1: {}
+ regexp-ast-analysis@0.7.1:
+ dependencies:
+ '@eslint-community/regexpp': 4.12.1
+ refa: 0.12.1
+
+ regexp-tree@0.1.27: {}
+
+ regjsparser@0.10.0:
+ dependencies:
+ jsesc: 0.5.0
+
+ require-directory@2.1.1: {}
+
resolve-from@4.0.0: {}
+ resolve-pkg-maps@1.0.0: {}
+
resolve@1.22.8:
dependencies:
is-core-module: 2.15.1
@@ -3384,6 +4087,14 @@ snapshots:
dependencies:
loose-envify: 1.4.0
+ scslre@0.3.0:
+ dependencies:
+ '@eslint-community/regexpp': 4.12.1
+ refa: 0.12.1
+ regexp-ast-analysis: 0.7.1
+
+ semver@5.7.2: {}
+
semver@6.3.1: {}
semver@7.6.3: {}
@@ -3405,6 +4116,43 @@ snapshots:
source-map@0.5.7: {}
+ spdx-correct@3.2.0:
+ dependencies:
+ spdx-expression-parse: 3.0.1
+ spdx-license-ids: 3.0.20
+
+ spdx-exceptions@2.5.0: {}
+
+ spdx-expression-parse@3.0.1:
+ dependencies:
+ spdx-exceptions: 2.5.0
+ spdx-license-ids: 3.0.20
+
+ spdx-expression-parse@4.0.0:
+ dependencies:
+ spdx-exceptions: 2.5.0
+ spdx-license-ids: 3.0.20
+
+ spdx-license-ids@3.0.20: {}
+
+ stable-hash@0.0.4: {}
+
+ string-ts@2.2.0: {}
+
+ string-width@4.2.3:
+ dependencies:
+ emoji-regex: 8.0.0
+ is-fullwidth-code-point: 3.0.0
+ strip-ansi: 6.0.1
+
+ strip-ansi@6.0.1:
+ dependencies:
+ ansi-regex: 5.0.1
+
+ strip-indent@3.0.0:
+ dependencies:
+ min-indent: 1.0.1
+
strip-json-comments@3.1.1: {}
stylis@4.2.0: {}
@@ -3475,8 +4223,29 @@ snapshots:
typescript@5.6.3: {}
+ ufo@1.5.4: {}
+
undici-types@6.19.8: {}
+ unist-util-is@6.0.0:
+ dependencies:
+ '@types/unist': 3.0.3
+
+ unist-util-stringify-position@4.0.0:
+ dependencies:
+ '@types/unist': 3.0.3
+
+ unist-util-visit-parents@6.0.1:
+ dependencies:
+ '@types/unist': 3.0.3
+ unist-util-is: 6.0.0
+
+ unist-util-visit@5.0.0:
+ dependencies:
+ '@types/unist': 3.0.3
+ unist-util-is: 6.0.0
+ unist-util-visit-parents: 6.0.1
+
update-browserslist-db@1.1.1(browserslist@4.24.2):
dependencies:
browserslist: 4.24.2
@@ -3507,14 +4276,59 @@ snapshots:
'@types/node': 22.9.0
fsevents: 2.3.3
+ vue-eslint-parser@9.4.3(eslint@9.15.0):
+ dependencies:
+ debug: 4.3.7
+ eslint: 9.15.0
+ eslint-scope: 7.2.2
+ eslint-visitor-keys: 3.4.3
+ espree: 9.6.1
+ esquery: 1.6.0
+ lodash: 4.17.21
+ semver: 7.6.3
+ transitivePeerDependencies:
+ - supports-color
+
which@2.0.2:
dependencies:
isexe: 2.0.0
word-wrap@1.2.5: {}
+ wrap-ansi@7.0.0:
+ dependencies:
+ ansi-styles: 4.3.0
+ string-width: 4.2.3
+ strip-ansi: 6.0.1
+
+ xml-name-validator@4.0.0: {}
+
+ y18n@5.0.8: {}
+
yallist@3.1.1: {}
+ yaml-eslint-parser@1.2.3:
+ dependencies:
+ eslint-visitor-keys: 3.4.3
+ lodash: 4.17.21
+ yaml: 2.6.0
+
yaml@1.10.2: {}
+ yaml@2.6.0: {}
+
+ yargs-parser@21.1.1: {}
+
+ yargs@17.7.2:
+ dependencies:
+ cliui: 8.0.1
+ escalade: 3.2.0
+ get-caller-file: 2.0.5
+ require-directory: 2.1.1
+ string-width: 4.2.3
+ y18n: 5.0.8
+ yargs-parser: 21.1.1
+
yocto-queue@0.1.0: {}
+
+ zwitch@2.0.4: {}
diff --git a/vinvoor/src/App.tsx b/vinvoor/src/App.tsx
index 27477c6..d667b00 100644
--- a/vinvoor/src/App.tsx
+++ b/vinvoor/src/App.tsx
@@ -6,11 +6,11 @@ import { Footer } from "./footer/Footer";
import { useUser } from "./hooks/useUser";
import { NavBar } from "./navbar/NavBar";
import { Overview } from "./overview/Overview";
-import "./themes/background.css";
import { randomInt } from "./util/util";
import { WelcomePage } from "./WelcomePage";
+import "./themes/background.css";
-export const App = () => {
+export function App() {
const userQuery = useUser();
const outlet = useOutlet();
@@ -34,18 +34,22 @@ export const App = () => {
}}
>
- {Object.keys(userQuery.data ?? {}).length > 0 ? (
- outlet !== null ? (
-
- ) : (
-
- )
- ) : (
- <>
-
-
- >
- )}
+ {Object.keys(userQuery.data ?? {}).length > 0
+ ? (
+ outlet !== null
+ ? (
+
+ )
+ : (
+
+ )
+ )
+ : (
+ <>
+
+
+ >
+ )}
@@ -53,4 +57,4 @@ export const App = () => {
);
-};
+}
diff --git a/vinvoor/src/WelcomePage.tsx b/vinvoor/src/WelcomePage.tsx
index 2113ed7..52efd46 100644
--- a/vinvoor/src/WelcomePage.tsx
+++ b/vinvoor/src/WelcomePage.tsx
@@ -1,8 +1,8 @@
import { GitHub } from "@mui/icons-material";
import { Box, Button, Typography } from "@mui/material";
import { ShakerOutline } from "mdi-material-ui";
-import { TypographyG } from "./components/TypographyG";
import { Login } from "./auth/Login";
+import { TypographyG } from "./components/TypographyG";
declare module "@mui/material/Button" {
interface ButtonPropsColorOverrides {
@@ -10,7 +10,7 @@ declare module "@mui/material/Button" {
}
}
-export const WelcomePage = () => {
+export function WelcomePage() {
const handleClick = () => {
window.location.replace("https://github.com/ZeusWPI/ZeSS");
};
@@ -46,4 +46,4 @@ export const WelcomePage = () => {
);
-};
+}
diff --git a/vinvoor/src/auth/Login.tsx b/vinvoor/src/auth/Login.tsx
index d8a48e9..591ea76 100644
--- a/vinvoor/src/auth/Login.tsx
+++ b/vinvoor/src/auth/Login.tsx
@@ -1,7 +1,8 @@
-import { Button, ButtonProps } from "@mui/material";
-import { FC } from "react";
+import type { ButtonProps } from "@mui/material";
+import type { FC } from "react";
+import { Button } from "@mui/material";
-export const Login: FC = props => {
+export const Login: FC = (props) => {
const url = import.meta.env.VITE_BACKEND_URL as string;
const handleClick = () => {
diff --git a/vinvoor/src/auth/Logout.tsx b/vinvoor/src/auth/Logout.tsx
index c5fb8c3..c3a3b3c 100644
--- a/vinvoor/src/auth/Logout.tsx
+++ b/vinvoor/src/auth/Logout.tsx
@@ -1,8 +1,9 @@
-import { Button, ButtonProps } from "@mui/material";
-import { FC } from "react";
+import type { ButtonProps } from "@mui/material";
+import type { FC } from "react";
+import { Button } from "@mui/material";
import { useLogout } from "../hooks/useUser";
-export const Logout: FC = props => {
+export const Logout: FC = (props) => {
const logout = useLogout();
const handleClick = () => {
logout.mutate();
diff --git a/vinvoor/src/cards/Cards.tsx b/vinvoor/src/cards/Cards.tsx
index f46cdf6..8083d4c 100644
--- a/vinvoor/src/cards/Cards.tsx
+++ b/vinvoor/src/cards/Cards.tsx
@@ -3,7 +3,7 @@ import { useCards } from "../hooks/useCard";
import { CardsEmpty } from "./CardsEmpty";
import { CardsTable } from "./CardsTable";
-export const Cards = () => {
+export function Cards() {
const cardsQuery = useCards();
return (
@@ -11,4 +11,4 @@ export const Cards = () => {
{cardsQuery.data?.length ? : }
);
-};
+}
diff --git a/vinvoor/src/cards/CardsAdd.tsx b/vinvoor/src/cards/CardsAdd.tsx
index 36826c2..b070df3 100644
--- a/vinvoor/src/cards/CardsAdd.tsx
+++ b/vinvoor/src/cards/CardsAdd.tsx
@@ -1,24 +1,28 @@
+import type {
+ CardGetRegisterResponse,
+ CardGetRegisterResponseJSON,
+ CardPostResponse,
+ CardPostResponseJSON,
+} from "../types/cards";
+import type { Optional } from "../types/general";
+import type {
+ CircularTimeProgressProps,
+} from "./CircularTimeProgress";
import { Add } from "@mui/icons-material";
import { Button, Typography } from "@mui/material";
import { useConfirm } from "material-ui-confirm";
import { useSnackbar } from "notistack";
import { useEffect, useState } from "react";
+import { useCards } from "../hooks/useCard";
import {
- CardGetRegisterResponse,
- CardGetRegisterResponseJSON,
- CardPostResponse,
- CardPostResponseJSON,
convertCardGetRegisterResponseJSON,
convertCardPostResponseJSON,
} from "../types/cards";
-import { Optional } from "../types/general";
import { getApi, isResponseNot200Error, postApi } from "../util/fetch";
import { randomInt } from "../util/util";
import {
CircularTimeProgress,
- CircularTimeProgressProps,
} from "./CircularTimeProgress";
-import { useCards } from "../hooks/useCard";
const CHECK_INTERVAL = 1000;
const REGISTER_TIME = 60000;
@@ -37,19 +41,19 @@ const confirmContent = `
const requestSuccess = "Register your card by holding it to vinscant";
const requestYou = "You are already registering a card!";
-const requestOther =
- "Failed to start the card registering process because another user is already registering a card. Please try again later.";
-const requestFail =
- "Failed to start the card registration process. Please try again later or contact a sysadmin";
+const requestOther
+ = "Failed to start the card registering process because another user is already registering a card. Please try again later.";
+const requestFail
+ = "Failed to start the card registration process. Please try again later or contact a sysadmin";
const registerSucces = "Card registered successfully";
const registerFail = "Failed to register card";
-export const CardsAdd = () => {
+export function CardsAdd() {
const { refetch } = useCards();
const [registering, setRegistering] = useState(false);
- const [progressProps, setProgressProps] =
- useState(defaultProgressProps);
+ const [progressProps, setProgressProps]
+ = useState(defaultProgressProps);
const confirm = useConfirm();
const { enqueueSnackbar, closeSnackbar } = useSnackbar();
@@ -78,7 +82,7 @@ export const CardsAdd = () => {
REGISTER_ENDPOINT,
convertCardGetRegisterResponseJSON,
)
- .then(async response => {
+ .then(async (response) => {
let started = false;
if (!response.registering && start) {
await postApi(
@@ -87,25 +91,31 @@ export const CardsAdd = () => {
convertCardPostResponseJSON,
)
.then(() => (started = true))
- .catch(error => {
+ .catch((error) => {
if (isResponseNot200Error(error)) {
void error.response
.json()
.then((response: CardPostResponse) => {
- if (response.isCurrentUser)
+ if (response.isCurrentUser) {
enqueueSnackbar(requestYou, {
variant: "warning",
});
- else
+ }
+ else {
enqueueSnackbar(requestOther, {
variant: "error",
});
+ }
});
- } else throw new Error(error as string);
+ }
+ else {
+ throw new Error(error as string);
+ }
});
}
- if (response.registering && response.isCurrentUser) started = true;
+ if (response.registering && response.isCurrentUser)
+ started = true;
if (started) {
setRegistering(true);
@@ -121,9 +131,9 @@ export const CardsAdd = () => {
}
void checkCardsChange()
- .then(scanned => {
+ .then((scanned) => {
setRegistering(false);
- if (id) {
+ if (id !== undefined) {
closeSnackbar(id);
if (scanned) {
@@ -131,10 +141,12 @@ export const CardsAdd = () => {
variant: "success",
});
void refetch();
- } else
+ }
+ else {
enqueueSnackbar(registerFail, {
variant: "error",
});
+ }
}
})
.finally(() => setProgressProps(defaultProgressProps));
@@ -170,4 +182,4 @@ export const CardsAdd = () => {
Register new card
);
-};
+}
diff --git a/vinvoor/src/cards/CardsDelete.tsx b/vinvoor/src/cards/CardsDelete.tsx
index e16520a..0ee8ac5 100644
--- a/vinvoor/src/cards/CardsDelete.tsx
+++ b/vinvoor/src/cards/CardsDelete.tsx
@@ -1,8 +1,8 @@
+import type { FC } from "react";
import DeleteIcon from "@mui/icons-material/Delete";
import { IconButton, Link, Tooltip, Typography } from "@mui/material";
import { useConfirm } from "material-ui-confirm";
import { useSnackbar } from "notistack";
-import { FC } from "react";
interface CardDeleteProps {
selected: readonly string[];
@@ -18,16 +18,22 @@ export const CardsDelete: FC = ({ selected }) => {
const title = `Delete card${numSelected > 1 ? "s" : ""}`;
const content = (
- Are you sure you want to delete {numSelected} card
- {numSelected > 1 ? "s" : ""}? Unfortunately, this feature isn't available
- yet. Let's convince Hannes to add this feature by signing this{" "}
+ Are you sure you want to delete
+ {" "}
+ {numSelected}
+ {" "}
+ card
+ {numSelected > 1 ? "s" : ""}
+ ? Unfortunately, this feature isn't available
+ yet. Let's convince Hannes to add this feature by signing this
+ {" "}
petition!
);
const handleClick = () => {
void confirm({
- title: title,
+ title,
description: content,
confirmationText: "Delete",
}).then(() => enqueueSnackbar(deletePressed, { variant: "error" }));
diff --git a/vinvoor/src/cards/CardsEmpty.tsx b/vinvoor/src/cards/CardsEmpty.tsx
index d936b52..6048cac 100644
--- a/vinvoor/src/cards/CardsEmpty.tsx
+++ b/vinvoor/src/cards/CardsEmpty.tsx
@@ -2,7 +2,7 @@ import { Paper } from "@mui/material";
import { TypographyG } from "../components/TypographyG";
import { CardsAdd } from "./CardsAdd";
-export const CardsEmpty = () => {
+export function CardsEmpty() {
return (
{
);
-};
+}
diff --git a/vinvoor/src/cards/CardsTable.tsx b/vinvoor/src/cards/CardsTable.tsx
index 8f6c158..26efe70 100644
--- a/vinvoor/src/cards/CardsTable.tsx
+++ b/vinvoor/src/cards/CardsTable.tsx
@@ -1,37 +1,34 @@
+import type { ChangeEvent, MouseEvent } from "react";
+import type { Card } from "../types/cards";
+import type { TableOrder } from "../types/general";
import { Paper, Table, TableContainer, TablePagination } from "@mui/material";
-import { ChangeEvent, MouseEvent, useMemo, useState } from "react";
-import { Card } from "../types/cards";
-import { TableOrder } from "../types/general";
+import { useMemo, useState } from "react";
+import { useCards } from "../hooks/useCard";
import { CardsTableBody } from "./CardsTableBody";
import { CardsTableHead } from "./CardsTableHead";
import { CardsTableToolbar } from "./CardsTableToolbar";
-import { useCards } from "../hooks/useCard";
const rowsPerPageOptions = [10, 25, 50];
-const descendingComparator = (a: T, b: T, orderBy: keyof T) => {
- if (b[orderBy] < a[orderBy]) return -1;
- if (b[orderBy] > a[orderBy]) return 1;
+function descendingComparator(a: T, b: T, orderBy: keyof T) {
+ if (b[orderBy] < a[orderBy])
+ return -1;
+ if (b[orderBy] > a[orderBy])
+ return 1;
return 0;
-};
+}
-const getComparator = (
- order: TableOrder,
- orderBy: Key,
-): ((
+function getComparator(order: TableOrder, orderBy: Key): ((
a: Record,
b: Record,
-) => number) => {
+) => number) {
return order === "desc"
? (a, b) => descendingComparator(a, b, orderBy)
: (a, b) => -descendingComparator(a, b, orderBy);
-};
+}
-const stableSort = (
- array: readonly T[],
- comparator: (a: T, b: T) => number,
-) => {
+function stableSort(array: readonly T[], comparator: (a: T, b: T) => number) {
const stabilized = array.map((el, index) => [el, index] as [T, number]);
stabilized.sort((a, b) => {
const order = comparator(a[0], b[0]);
@@ -41,11 +38,10 @@ const stableSort = (
return a[1] - b[1];
});
return stabilized.map(el => el[0]);
-};
+}
-export const CardsTable = () => {
+export function CardsTable() {
const { data: cards } = useCards();
- if (!cards) return null; // Can never happen
const [order, setOrder] = useState("asc");
const [orderBy, setOrderBy] = useState("serial");
@@ -53,6 +49,18 @@ export const CardsTable = () => {
const [page, setPage] = useState(0);
const [rowsPerPage, setRowsPerPage] = useState(10);
+ const visibleRows = useMemo(
+ () =>
+ stableSort(cards ?? [], getComparator(order, orderBy)).slice(
+ page * rowsPerPage,
+ page * rowsPerPage + rowsPerPage,
+ ),
+ [cards, order, orderBy, page, rowsPerPage],
+ );
+
+ if (!cards)
+ return null; // Can never happen
+
const handleRequestSort = (
_: MouseEvent,
property: keyof Card,
@@ -106,23 +114,14 @@ export const CardsTable = () => {
) => setPage(newPage);
const handleChangeRowsPerPage = (event: ChangeEvent) => {
- setRowsPerPage(parseInt(event.target.value, 10));
+ setRowsPerPage(Number.parseInt(event.target.value, 10));
setPage(0);
};
const isSelected = (serial: string) => selected.includes(serial);
- const emptyRows =
- page > 0 ? Math.max(0, (1 + page) * rowsPerPage - cards.length) : 0;
-
- const visibleRows = useMemo(
- () =>
- stableSort(cards, getComparator(order, orderBy)).slice(
- page * rowsPerPage,
- page * rowsPerPage + rowsPerPage,
- ),
- [cards, order, orderBy, page, rowsPerPage],
- );
+ const emptyRows
+ = page > 0 ? Math.max(0, (1 + page) * rowsPerPage - cards.length) : 0;
return (
@@ -156,4 +155,4 @@ export const CardsTable = () => {
/>
);
-};
+}
diff --git a/vinvoor/src/cards/CardsTableBody.tsx b/vinvoor/src/cards/CardsTableBody.tsx
index 1dfd2e4..2440e8b 100644
--- a/vinvoor/src/cards/CardsTableBody.tsx
+++ b/vinvoor/src/cards/CardsTableBody.tsx
@@ -1,3 +1,5 @@
+import type { ChangeEvent, FC, MouseEvent } from "react";
+import type { Card } from "../types/cards";
import { EditOutlined } from "@mui/icons-material";
import {
Checkbox,
@@ -10,9 +12,8 @@ import {
} from "@mui/material";
import { useConfirm } from "material-ui-confirm";
import { useSnackbar } from "notistack";
-import { ChangeEvent, FC, MouseEvent } from "react";
-import { Card, cardsHeadCells } from "../types/cards";
import { useCards, usePatchCards } from "../hooks/useCard";
+import { cardsHeadCells } from "../types/cards";
interface CardsTableBodyProps {
rows: readonly Card[];
@@ -47,9 +48,9 @@ export const CardsTableBody: FC = ({
variant="standard"
defaultValue={name}
onChange={(event: ChangeEvent) =>
- (newName = event.target.value)
- }
- >
+ (newName = event.target.value)}
+ >
+
),
confirmationText: "Save",
})
@@ -60,7 +61,7 @@ export const CardsTableBody: FC = ({
}
patchCard.mutate(
- { id: id, newName: newName },
+ { id, newName },
{
onSuccess: () => {
enqueueSnackbar(nameSaveSuccess, {
@@ -86,7 +87,7 @@ export const CardsTableBody: FC = ({
return (
- {rows.map(row => {
+ {rows.map((row) => {
const isSelected = isRowSelected(row.serial);
return (
diff --git a/vinvoor/src/cards/CardsTableHead.tsx b/vinvoor/src/cards/CardsTableHead.tsx
index 7a6fb8d..2eed412 100644
--- a/vinvoor/src/cards/CardsTableHead.tsx
+++ b/vinvoor/src/cards/CardsTableHead.tsx
@@ -1,3 +1,6 @@
+import type { ChangeEvent, FC, MouseEvent } from "react";
+import type { Card } from "../types/cards";
+import type { TableOrder } from "../types/general";
import {
Checkbox,
TableCell,
@@ -6,9 +9,7 @@ import {
TableSortLabel,
Typography,
} from "@mui/material";
-import { ChangeEvent, FC, MouseEvent } from "react";
-import { Card, cardsHeadCells } from "../types/cards";
-import { TableOrder } from "../types/general";
+import { cardsHeadCells } from "../types/cards";
interface CardTableHeadProps {
numSelected: number;
@@ -30,8 +31,8 @@ export const CardsTableHead: FC = ({
orderBy,
rowCount,
}) => {
- const createSortHandler =
- (property: keyof Card) => (event: MouseEvent) =>
+ const createSortHandler
+ = (property: keyof Card) => (event: MouseEvent) =>
onRequestSort(event, property);
return (
diff --git a/vinvoor/src/cards/CardsTableToolbar.tsx b/vinvoor/src/cards/CardsTableToolbar.tsx
index 85413a3..ab98f5c 100644
--- a/vinvoor/src/cards/CardsTableToolbar.tsx
+++ b/vinvoor/src/cards/CardsTableToolbar.tsx
@@ -1,6 +1,6 @@
+import type { FC } from "react";
import { Toolbar, Typography } from "@mui/material";
import { alpha } from "@mui/material/styles";
-import { FC } from "react";
import { CardsAdd } from "./CardsAdd";
import { CardsDelete } from "./CardsDelete";
@@ -24,25 +24,29 @@ export const CardsTableToolbar: FC = ({ selected }) => {
}),
}}
>
- {numSelected > 0 ? (
- <>
-
- {numSelected} selected
-
-
- >
- ) : (
- <>
-
- Cards
-
-
- >
- )}
+ {numSelected > 0
+ ? (
+ <>
+
+ {numSelected}
+ {" "}
+ selected
+
+
+ >
+ )
+ : (
+ <>
+
+ Cards
+
+
+ >
+ )}
);
};
diff --git a/vinvoor/src/cards/CircularTimeProgress.tsx b/vinvoor/src/cards/CircularTimeProgress.tsx
index 6f274cc..fe0e39c 100644
--- a/vinvoor/src/cards/CircularTimeProgress.tsx
+++ b/vinvoor/src/cards/CircularTimeProgress.tsx
@@ -1,5 +1,5 @@
+import type { FC } from "react";
import { Box, CircularProgress, Typography } from "@mui/material";
-import { FC } from "react";
export interface CircularTimeProgressProps {
time: number;
diff --git a/vinvoor/src/components/BrowserView.tsx b/vinvoor/src/components/BrowserView.tsx
index bf97481..a77e53f 100644
--- a/vinvoor/src/components/BrowserView.tsx
+++ b/vinvoor/src/components/BrowserView.tsx
@@ -1,5 +1,6 @@
+import type { FC } from "react";
import { useMediaQuery, useTheme } from "@mui/material";
-import { FC, useEffect } from "react";
+import { useEffect } from "react";
interface BrowserViewProps {
onMobileView?: () => void;
@@ -16,11 +17,13 @@ export const BrowserView: FC = ({
const isMobileView = useMediaQuery(theme.breakpoints.down("md"));
useEffect(() => {
- if (isMobileView) onMobileView?.();
+ if (isMobileView)
+ onMobileView?.();
else onBrowserView?.();
}, [isMobileView]);
- if (isMobileView) return null;
+ if (isMobileView)
+ return null;
return isMobileView ? null : children;
};
diff --git a/vinvoor/src/components/DarkModeToggle.tsx b/vinvoor/src/components/DarkModeToggle.tsx
index 65858dc..13b9c30 100644
--- a/vinvoor/src/components/DarkModeToggle.tsx
+++ b/vinvoor/src/components/DarkModeToggle.tsx
@@ -3,7 +3,7 @@ import { IconButton, Tooltip } from "@mui/material";
import { useContext } from "react";
import { ThemeContext } from "../providers/ThemeProvider";
-export const DarkModeToggle = () => {
+export function DarkModeToggle() {
const { themeMode, setTheme } = useContext(ThemeContext);
const handleThemeChange = () =>
@@ -19,4 +19,4 @@ export const DarkModeToggle = () => {
);
-};
+}
diff --git a/vinvoor/src/components/LoadingSkeleton.tsx b/vinvoor/src/components/LoadingSkeleton.tsx
index ff2a7fa..c1bdcae 100644
--- a/vinvoor/src/components/LoadingSkeleton.tsx
+++ b/vinvoor/src/components/LoadingSkeleton.tsx
@@ -1,6 +1,7 @@
-import { Skeleton, SkeletonProps } from "@mui/material";
-import { UseQueryResult } from "@tanstack/react-query";
-import { FC, ReactNode } from "react";
+import type { SkeletonProps } from "@mui/material";
+import type { UseQueryResult } from "@tanstack/react-query";
+import type { FC, ReactNode } from "react";
+import { Skeleton } from "@mui/material";
import { isResponseNot200Error } from "../util/fetch";
interface LoadingSkeletonProps extends SkeletonProps {
@@ -14,11 +15,12 @@ export const LoadingSkeleton: FC = ({
...props
}) => {
const isError = queries.some(query => query.isError);
- if (isError)
+ if (isError) {
throw (
- queries.find(query => isResponseNot200Error(query.error))?.error ??
- new Error("Error fetching data, unable to reach the server")
+ queries.find(query => isResponseNot200Error(query.error))?.error
+ ?? new Error("Error fetching data, unable to reach the server")
);
+ }
const isLoading = queries.some(query => query.isLoading);
diff --git a/vinvoor/src/components/ProtectedRoute.tsx b/vinvoor/src/components/ProtectedRoute.tsx
index 5400de4..8783e63 100644
--- a/vinvoor/src/components/ProtectedRoute.tsx
+++ b/vinvoor/src/components/ProtectedRoute.tsx
@@ -1,4 +1,4 @@
-import { FC, ReactNode } from "react";
+import type { FC, ReactNode } from "react";
import { Navigate } from "react-router-dom";
import { useUser } from "../hooks/useUser";
@@ -9,7 +9,8 @@ interface ProtectedRouteProps {
export const ProtectedRoute: FC = ({ children }) => {
const { data: user } = useUser();
- if (!user?.admin) return ;
+ if (!user?.admin)
+ return ;
return children;
};
diff --git a/vinvoor/src/components/TypographyG.tsx b/vinvoor/src/components/TypographyG.tsx
index 8d166f7..e223b57 100644
--- a/vinvoor/src/components/TypographyG.tsx
+++ b/vinvoor/src/components/TypographyG.tsx
@@ -1,6 +1,7 @@
-import { Typography, TypographyProps } from "@mui/material";
-import { FC } from "react";
+import type { TypographyProps } from "@mui/material";
+import type { FC } from "react";
+import { Typography } from "@mui/material";
-export const TypographyG: FC = props => {
+export const TypographyG: FC = (props) => {
return ;
};
diff --git a/vinvoor/src/components/UnstyledLink.tsx b/vinvoor/src/components/UnstyledLink.tsx
index 7891e70..a42a3f1 100644
--- a/vinvoor/src/components/UnstyledLink.tsx
+++ b/vinvoor/src/components/UnstyledLink.tsx
@@ -1,7 +1,8 @@
-import { FC } from "react";
-import { Link, LinkProps } from "react-router-dom";
+import type { FC } from "react";
+import type { LinkProps } from "react-router-dom";
+import { Link } from "react-router-dom";
-export const UnstyledLink: FC = props => {
+export const UnstyledLink: FC = (props) => {
return (
);
diff --git a/vinvoor/src/errors/ErrorPage.tsx b/vinvoor/src/errors/ErrorPage.tsx
index 29fd06d..2c5c941 100644
--- a/vinvoor/src/errors/ErrorPage.tsx
+++ b/vinvoor/src/errors/ErrorPage.tsx
@@ -2,20 +2,23 @@ import { Box, Typography } from "@mui/material";
import { isRouteErrorResponse, useRouteError } from "react-router-dom";
import CursesSob from "/cursed_sob.png";
-const get_error = (error: unknown) => {
+function get_error(error: unknown) {
if (isRouteErrorResponse(error)) {
return `${error.status} ${error.statusText}`;
- } else if (error instanceof Error) {
+ }
+ else if (error instanceof Error) {
return error.message;
- } else if (typeof error === "string") {
+ }
+ else if (typeof error === "string") {
return error;
- } else {
+ }
+ else {
console.error(error);
return "Unknown error";
}
-};
+}
-export const ErrorPage = () => {
+export function ErrorPage() {
const error = useRouteError();
return (
@@ -42,4 +45,4 @@ export const ErrorPage = () => {
);
-};
+}
diff --git a/vinvoor/src/footer/Footer.tsx b/vinvoor/src/footer/Footer.tsx
index 3336c34..17090ab 100644
--- a/vinvoor/src/footer/Footer.tsx
+++ b/vinvoor/src/footer/Footer.tsx
@@ -3,7 +3,7 @@ import { TypographyG } from "../components/TypographyG";
import { useVersion } from "../hooks/useVersion";
import ZeusIcon from "/zeus.svg";
-export const Footer = () => {
+export function Footer() {
const { data: version } = useVersion();
return (
@@ -14,7 +14,10 @@ export const Footer = () => {
alignItems: "center",
}}
>
- v {version?.version ?? ""}
+
+ v
+ {version?.version ?? ""}
+
{
);
-};
+}
diff --git a/vinvoor/src/hooks/admin/useAdminDays.ts b/vinvoor/src/hooks/admin/useAdminDays.ts
index 2f0afa7..931df69 100644
--- a/vinvoor/src/hooks/admin/useAdminDays.ts
+++ b/vinvoor/src/hooks/admin/useAdminDays.ts
@@ -1,27 +1,31 @@
+import type { Dayjs } from "dayjs";
+import type { Day, DayJSON } from "../../types/days";
import { useMutation, useQuery } from "@tanstack/react-query";
-import { convertDayJSON, Day, DayJSON } from "../../types/days";
+import { convertDayJSON } from "../../types/days";
import { deleteAPI, getApi, postApi } from "../../util/fetch";
-import { Dayjs } from "dayjs";
const ENDPOINT = "admin/days";
-export const useAdminDays = () =>
- useQuery({
+export function useAdminDays() {
+ return useQuery({
queryKey: ["adminDays"],
- queryFn: () => getApi(ENDPOINT, convertDayJSON),
+ queryFn: async () => getApi(ENDPOINT, convertDayJSON),
retry: 1,
});
+}
-export const useAdminAddDay = () =>
- useMutation({
- mutationFn: (args: { startDate: Dayjs; endDate: Dayjs }) =>
+export function useAdminAddDay() {
+ return useMutation({
+ mutationFn: async (args: { startDate: Dayjs; endDate: Dayjs }) =>
postApi(ENDPOINT, {
start_date: args.startDate.format("YYYY-MM-DD"),
end_date: args.endDate.format("YYYY-MM-DD"),
}),
});
+}
-export const useAdminDeleteDay = () =>
- useMutation({
- mutationFn: (id: number) => deleteAPI(`${ENDPOINT}/${id}`),
+export function useAdminDeleteDay() {
+ return useMutation({
+ mutationFn: async (id: number) => deleteAPI(`${ENDPOINT}/${id}`),
});
+}
diff --git a/vinvoor/src/hooks/admin/useAdminSeason.ts b/vinvoor/src/hooks/admin/useAdminSeason.ts
index bc6fbab..0231aed 100644
--- a/vinvoor/src/hooks/admin/useAdminSeason.ts
+++ b/vinvoor/src/hooks/admin/useAdminSeason.ts
@@ -1,29 +1,32 @@
+import type { Dayjs } from "dayjs";
+import type { Season, SeasonJSON } from "../../types/seasons";
import { useMutation, useQuery } from "@tanstack/react-query";
+import { convertSeasonJSON } from "../../types/seasons";
import { deleteAPI, getApi, postApi } from "../../util/fetch";
-import { Dayjs } from "dayjs";
-import { convertSeasonJSON, Season, SeasonJSON } from "../../types/seasons";
const ENDPOINT = "admin/seasons";
-export const useAdminSeasons = () => {
+export function useAdminSeasons() {
return useQuery({
queryKey: ["adminSeasons"],
- queryFn: () => getApi(ENDPOINT, convertSeasonJSON),
+ queryFn: async () => getApi(ENDPOINT, convertSeasonJSON),
retry: 1,
});
-};
+}
-export const useAdminAddSeason = () =>
- useMutation({
- mutationFn: (args: { name: string; startDate: Dayjs; endDate: Dayjs }) =>
+export function useAdminAddSeason() {
+ return useMutation({
+ mutationFn: async (args: { name: string; startDate: Dayjs; endDate: Dayjs }) =>
postApi(ENDPOINT, {
name: args.name,
start: args.startDate.format("YYYY-MM-DD"),
end: args.endDate.format("YYYY-MM-DD"),
}),
});
+}
-export const useAdminDeleteSeason = () =>
- useMutation({
- mutationFn: (id: number) => deleteAPI(`${ENDPOINT}/${id}`),
+export function useAdminDeleteSeason() {
+ return useMutation({
+ mutationFn: async (id: number) => deleteAPI(`${ENDPOINT}/${id}`),
});
+}
diff --git a/vinvoor/src/hooks/useCard.ts b/vinvoor/src/hooks/useCard.ts
index d9e0574..a098f2a 100644
--- a/vinvoor/src/hooks/useCard.ts
+++ b/vinvoor/src/hooks/useCard.ts
@@ -1,21 +1,23 @@
+import type { Card, CardJSON } from "../types/cards";
import { useMutation, useQuery } from "@tanstack/react-query";
-import { Card, CardJSON, convertCardJSON } from "../types/cards";
+import { convertCardJSON } from "../types/cards";
import { getApi, patchApi } from "../util/fetch";
const ENDPOINT = "cards";
-export const useCards = () =>
- useQuery({
+export function useCards() {
+ return useQuery({
queryKey: ["cards"],
- queryFn: () => getApi(ENDPOINT, convertCardJSON),
+ queryFn: async () => getApi(ENDPOINT, convertCardJSON),
retry: 1,
});
+}
-export const usePatchCards = () => {
+export function usePatchCards() {
return useMutation({
- mutationFn: (args: { id: number; newName: string }) =>
+ mutationFn: async (args: { id: number; newName: string }) =>
patchApi(`${ENDPOINT}/${args.id}`, {
name: args.newName,
}),
});
-};
+}
diff --git a/vinvoor/src/hooks/useLeaderboard.ts b/vinvoor/src/hooks/useLeaderboard.ts
index 5301b0f..a1cb9f8 100644
--- a/vinvoor/src/hooks/useLeaderboard.ts
+++ b/vinvoor/src/hooks/useLeaderboard.ts
@@ -1,20 +1,23 @@
+import type {
+ LeaderboardItem,
+ LeaderboardItemJSON,
+} from "../types/leaderboard";
import { useQuery } from "@tanstack/react-query";
-import { getApi } from "../util/fetch";
import {
convertLeaderboardItemJSON,
- LeaderboardItem,
- LeaderboardItemJSON,
} from "../types/leaderboard";
+import { getApi } from "../util/fetch";
const ENDPOINT = "leaderboard";
-export const useLeaderboardItems = () =>
- useQuery({
+export function useLeaderboardItems() {
+ return useQuery({
queryKey: ["leaderboard"],
- queryFn: () =>
+ queryFn: async () =>
getApi(
ENDPOINT,
convertLeaderboardItemJSON,
),
retry: 1,
});
+}
diff --git a/vinvoor/src/hooks/useScan.ts b/vinvoor/src/hooks/useScan.ts
index 24ca8b7..4f18f55 100644
--- a/vinvoor/src/hooks/useScan.ts
+++ b/vinvoor/src/hooks/useScan.ts
@@ -1,12 +1,14 @@
+import type { Scan, ScanJSON } from "../types/scans";
import { useQuery } from "@tanstack/react-query";
+import { convertScanJSON } from "../types/scans";
import { getApi } from "../util/fetch";
-import { convertScanJSON, Scan, ScanJSON } from "../types/scans";
const ENDPOINT = "scans";
-export const useScans = () =>
- useQuery({
+export function useScans() {
+ return useQuery({
queryKey: ["scans"],
- queryFn: () => getApi(ENDPOINT, convertScanJSON),
+ queryFn: async () => getApi(ENDPOINT, convertScanJSON),
retry: 1,
});
+}
diff --git a/vinvoor/src/hooks/useSeasons.ts b/vinvoor/src/hooks/useSeasons.ts
index f5221a7..e573f1b 100644
--- a/vinvoor/src/hooks/useSeasons.ts
+++ b/vinvoor/src/hooks/useSeasons.ts
@@ -1,19 +1,21 @@
-import { MutateOptions, useQuery } from "@tanstack/react-query";
+import type { MutateOptions } from "@tanstack/react-query";
+import type { Season, SeasonJSON } from "../types/seasons";
+import { useQuery } from "@tanstack/react-query";
+import { convertSeasonJSON } from "../types/seasons";
import { getApi } from "../util/fetch";
-import { convertSeasonJSON, Season, SeasonJSON } from "../types/seasons";
import { usePatchSettings } from "./useSettings";
const ENDPOINT = "seasons";
-export const useSeasons = () => {
+export function useSeasons() {
return useQuery({
queryKey: ["seasons"],
- queryFn: () => getApi(ENDPOINT, convertSeasonJSON),
+ queryFn: async () => getApi(ENDPOINT, convertSeasonJSON),
retry: 1,
});
-};
+}
-export const useSetSeason = () => {
+export function useSetSeason() {
const { mutate, ...other } = usePatchSettings();
const setSeason = (
@@ -27,4 +29,4 @@ export const useSetSeason = () => {
) => mutate({ season: id }, options);
return { setSeason, ...other };
-};
+}
diff --git a/vinvoor/src/hooks/useSettings.ts b/vinvoor/src/hooks/useSettings.ts
index 3432b31..0346cef 100644
--- a/vinvoor/src/hooks/useSettings.ts
+++ b/vinvoor/src/hooks/useSettings.ts
@@ -1,25 +1,27 @@
+import type { Settings, SettingsJSON } from "../types/settings";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
+import { converSettingsJSON } from "../types/settings";
import { getApi, patchApi } from "../util/fetch";
-import { converSettingsJSON, Settings, SettingsJSON } from "../types/settings";
const ENDPOINT = "settings";
-export const useSettings = () =>
- useQuery({
+export function useSettings() {
+ return useQuery({
queryKey: ["settings"],
- queryFn: () => getApi(ENDPOINT, converSettingsJSON),
+ queryFn: async () => getApi(ENDPOINT, converSettingsJSON),
retry: 1,
});
+}
-export const usePatchSettings = () => {
+export function usePatchSettings() {
const queryClient = useQueryClient();
return useMutation({
- mutationFn: (args: Record) =>
+ mutationFn: async (args: Record) =>
patchApi(ENDPOINT, args),
- onSuccess: () =>
+ onSuccess: async () =>
queryClient.invalidateQueries({
predicate: query => query.queryKey[0] !== "settings",
}),
});
-};
+}
diff --git a/vinvoor/src/hooks/useUser.ts b/vinvoor/src/hooks/useUser.ts
index db25b63..52ffaab 100644
--- a/vinvoor/src/hooks/useUser.ts
+++ b/vinvoor/src/hooks/useUser.ts
@@ -1,18 +1,20 @@
+import type { User, UserJSON } from "../types/user";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
+import { convertUserJSON } from "../types/user";
import { getApi, isResponseNot200Error, postApi } from "../util/fetch";
-import { convertUserJSON, User, UserJSON } from "../types/user";
const ENDPOINT = "user";
-export const useUser = () =>
- useQuery({
+export function useUser() {
+ return useQuery({
queryKey: ["user"],
queryFn: async () => {
let user = {} as User;
try {
user = await getApi(ENDPOINT, convertUserJSON);
- } catch (error) {
+ }
+ catch (error) {
if (!isResponseNot200Error(error))
throw new Error("Failed to fetch user");
}
@@ -21,15 +23,16 @@ export const useUser = () =>
},
retry: 1,
});
+}
-export const useLogout = () => {
+export function useLogout() {
const queryClient = useQueryClient();
return useMutation({
- mutationFn: () => postApi("logout"),
- onSuccess: () =>
+ mutationFn: async () => postApi("logout"),
+ onSuccess: async () =>
queryClient.invalidateQueries({
queryKey: ["user"],
}),
});
-};
+}
diff --git a/vinvoor/src/hooks/useVersion.ts b/vinvoor/src/hooks/useVersion.ts
index b1087ec..8deec45 100644
--- a/vinvoor/src/hooks/useVersion.ts
+++ b/vinvoor/src/hooks/useVersion.ts
@@ -1,12 +1,14 @@
+import type { Version, VersionJSON } from "../types/version";
import { useQuery } from "@tanstack/react-query";
-import { convertVersionJSON, Version, VersionJSON } from "../types/version";
+import { convertVersionJSON } from "../types/version";
import { getApi } from "../util/fetch";
const ENDPOINT = "version";
-export const useVersion = () =>
- useQuery({
+export function useVersion() {
+ return useQuery({
queryKey: ["version"],
- queryFn: () => getApi(ENDPOINT, convertVersionJSON),
+ queryFn: async () => getApi(ENDPOINT, convertVersionJSON),
retry: 1,
});
+}
diff --git a/vinvoor/src/leaderboard/Leaderboard.tsx b/vinvoor/src/leaderboard/Leaderboard.tsx
index e69385d..3f083ac 100644
--- a/vinvoor/src/leaderboard/Leaderboard.tsx
+++ b/vinvoor/src/leaderboard/Leaderboard.tsx
@@ -1,10 +1,10 @@
import { Divider, Paper, Table, TableContainer } from "@mui/material";
import { LoadingSkeleton } from "../components/LoadingSkeleton";
+import { useLeaderboardItems } from "../hooks/useLeaderboard";
import { LeaderboardTableBody } from "./LeaderboardTableBody";
import { LeaderboardTableToolbar } from "./LeaderboardTableToolbar";
-import { useLeaderboardItems } from "../hooks/useLeaderboard";
-export const Leaderboard = () => {
+export function Leaderboard() {
const leaderboardQuery = useLeaderboardItems();
return (
@@ -20,4 +20,4 @@ export const Leaderboard = () => {
);
-};
+}
diff --git a/vinvoor/src/leaderboard/LeaderboardTableBody.tsx b/vinvoor/src/leaderboard/LeaderboardTableBody.tsx
index 2057208..eaaa2e7 100644
--- a/vinvoor/src/leaderboard/LeaderboardTableBody.tsx
+++ b/vinvoor/src/leaderboard/LeaderboardTableBody.tsx
@@ -1,3 +1,6 @@
+import type { Theme } from "@mui/material/styles";
+import type { TableHeadCell } from "../types/general";
+import type { LeaderboardItem } from "../types/leaderboard";
import {
Icon,
TableBody,
@@ -5,11 +8,10 @@ import {
TableRow,
Typography,
} from "@mui/material";
-import { alpha, Theme, useTheme } from "@mui/material/styles";
+import { alpha, useTheme } from "@mui/material/styles";
import { useLeaderboardItems } from "../hooks/useLeaderboard";
import { useUser } from "../hooks/useUser";
-import { TableHeadCell } from "../types/general";
-import { leaderboardHeadCells, LeaderboardItem } from "../types/leaderboard";
+import { leaderboardHeadCells } from "../types/leaderboard";
import FirstPlaceIcon from "/first_place.svg";
import SecondPlaceIcon from "/second_place.svg";
import ThirdPlaceIcon from "/third_place.svg";
@@ -26,21 +28,23 @@ const leaderboardText = [
{ fontSize: "18px", fontWeight: "bold" },
];
-const getLeaderboardColor = (index: number, theme: Theme) =>
- leaderboardColors[index]
+function getLeaderboardColor(index: number, theme: Theme) {
+ return leaderboardColors[index]
? { backgroundColor: leaderboardColors[index](theme) }
: {};
+}
const getLeaderboardText = (index: number) => leaderboardText[index] || {};
-const getPositionChange = (positionChange: number) => {
+function getPositionChange(positionChange: number) {
let color = "text.primary";
let prefix = "";
if (positionChange > 0) {
color = "success.light";
prefix = "+";
- } else if (positionChange < 0) {
+ }
+ else if (positionChange < 0) {
color = "error.light";
}
@@ -50,9 +54,9 @@ const getPositionChange = (positionChange: number) => {
{positionChange !== 0 && positionChange}
);
-};
+}
-const getPosition = (position: number) => {
+function getPosition(position: number) {
switch (position) {
case 1:
return (
@@ -75,12 +79,9 @@ const getPosition = (position: number) => {
default:
return {position};
}
-};
+}
-const getCell = (
- row: LeaderboardItem,
- headCell: TableHeadCell,
-) => {
+function getCell(row: LeaderboardItem, headCell: TableHeadCell) {
switch (headCell.id) {
case "positionChange":
return getPositionChange(row[headCell.id]);
@@ -97,15 +98,16 @@ const getCell = (
);
}
-};
+}
-export const LeaderboardTableBody = () => {
+export function LeaderboardTableBody() {
const { data: rows } = useLeaderboardItems();
- if (!rows) return null; // Can never happen
-
const theme = useTheme();
const { data: user } = useUser();
+ if (!rows)
+ return null; // Can never happen
+
return (
{rows.map((row, index) => {
@@ -141,4 +143,4 @@ export const LeaderboardTableBody = () => {
})}
);
-};
+}
diff --git a/vinvoor/src/leaderboard/LeaderboardTableToolbar.tsx b/vinvoor/src/leaderboard/LeaderboardTableToolbar.tsx
index 2987440..5db2e9b 100644
--- a/vinvoor/src/leaderboard/LeaderboardTableToolbar.tsx
+++ b/vinvoor/src/leaderboard/LeaderboardTableToolbar.tsx
@@ -3,7 +3,7 @@ import { Button, Toolbar, Typography } from "@mui/material";
import { HashLink } from "react-router-hash-link";
import { useUser } from "../hooks/useUser";
-export const LeaderboardTableToolbar = () => {
+export function LeaderboardTableToolbar() {
const { data: user } = useUser();
return (
@@ -19,4 +19,4 @@ export const LeaderboardTableToolbar = () => {
);
-};
+}
diff --git a/vinvoor/src/main.tsx b/vinvoor/src/main.tsx
index ba5b187..359b98d 100644
--- a/vinvoor/src/main.tsx
+++ b/vinvoor/src/main.tsx
@@ -1,27 +1,27 @@
-import "@fontsource/roboto/300.css";
-import "@fontsource/roboto/400.css";
-import "@fontsource/roboto/500.css";
-import "@fontsource/roboto/700.css";
import { CssBaseline } from "@mui/material";
+import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ConfirmProvider } from "material-ui-confirm";
import React from "react";
import ReactDOM from "react-dom/client";
import { createBrowserRouter, RouterProvider } from "react-router-dom";
-import "react-tooltip/dist/react-tooltip.css";
import { App } from "./App.tsx";
+import { Login } from "./auth/Login.tsx";
+import { Logout } from "./auth/Logout.tsx";
import { Cards } from "./cards/Cards.tsx";
import { ProtectedRoute } from "./components/ProtectedRoute.tsx";
import { ErrorPage } from "./errors/ErrorPage.tsx";
import { Leaderboard } from "./leaderboard/Leaderboard.tsx";
+import { NavBar } from "./navbar/NavBar.tsx";
import { CustomSnackbarProvider } from "./providers/CustomSnackbarProvider.tsx";
import { ThemeProvider } from "./providers/ThemeProvider.tsx";
import { Scans } from "./scans/Scans.tsx";
import { Admin } from "./settings/admin/Admin.tsx";
import { SettingsOverview } from "./settings/SettingsOverview.tsx";
-import { Login } from "./auth/Login.tsx";
-import { Logout } from "./auth/Logout.tsx";
-import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
-import { NavBar } from "./navbar/NavBar.tsx";
+import "@fontsource/roboto/300.css";
+import "@fontsource/roboto/400.css";
+import "@fontsource/roboto/500.css";
+import "@fontsource/roboto/700.css";
+import "react-tooltip/dist/react-tooltip.css";
const queryClient = new QueryClient();
diff --git a/vinvoor/src/navbar/NavBar.tsx b/vinvoor/src/navbar/NavBar.tsx
index 176382f..7d8ca7a 100644
--- a/vinvoor/src/navbar/NavBar.tsx
+++ b/vinvoor/src/navbar/NavBar.tsx
@@ -30,7 +30,7 @@ const userMenuPages: PageIcon[] = [
{ page: "Settings", icon: },
];
-export const NavBar = () => {
+export function NavBar() {
const { data: user } = useUser();
const [selectedPage, setSelectedPage] = useState("");
const showSeasons = useMediaQuery("(min-width:400px)");
@@ -110,4 +110,4 @@ export const NavBar = () => {
);
-};
+}
diff --git a/vinvoor/src/navbar/NavBarLogo.tsx b/vinvoor/src/navbar/NavBarLogo.tsx
index 7b953fe..c59aed2 100644
--- a/vinvoor/src/navbar/NavBarLogo.tsx
+++ b/vinvoor/src/navbar/NavBarLogo.tsx
@@ -1,6 +1,8 @@
-import { Box, Button, SxProps, Theme, Typography } from "@mui/material";
+import type { SxProps, Theme } from "@mui/material";
+import type { FC } from "react";
+import { Box, Button, Typography } from "@mui/material";
import { HexagonSlice6 } from "mdi-material-ui";
-import { FC, useContext } from "react";
+import { useContext } from "react";
import { UnstyledLink } from "../components/UnstyledLink";
import { ThemeContext } from "../providers/ThemeProvider";
@@ -23,18 +25,21 @@ export const NavBarLogo: FC = ({
}) => {
const { setTheme } = useContext(ThemeContext);
const handleClick = () => {
- if (handleSelectedPage) handleSelectedPage("home");
+ if (handleSelectedPage)
+ handleSelectedPage("home");
if (pressedAmount < CLICK_AMOUNT) {
- if (pressedAmount === 0) startTimePress = Date.now();
+ if (pressedAmount === 0)
+ startTimePress = Date.now();
pressedAmount++;
if (
- pressedAmount === CLICK_AMOUNT &&
- Date.now() - startTimePress <= CLICK_TIME_MS
- )
+ pressedAmount === CLICK_AMOUNT
+ && Date.now() - startTimePress <= CLICK_TIME_MS
+ ) {
setTheme("kak");
+ }
}
};
diff --git a/vinvoor/src/navbar/NavBarPages.tsx b/vinvoor/src/navbar/NavBarPages.tsx
index 1d626c1..fb4c660 100644
--- a/vinvoor/src/navbar/NavBarPages.tsx
+++ b/vinvoor/src/navbar/NavBarPages.tsx
@@ -1,7 +1,8 @@
-import { Box, Button, SxProps, Theme, Typography } from "@mui/material";
-import { FC } from "react";
+import type { SxProps, Theme } from "@mui/material";
+import type { FC } from "react";
+import type { PageIcon } from "./NavBar";
+import { Box, Button, Typography } from "@mui/material";
import { UnstyledLink } from "../components/UnstyledLink";
-import { PageIcon } from "./NavBar";
interface NavBarPagesProps {
pageIcons: readonly PageIcon[];
diff --git a/vinvoor/src/navbar/NavBarSandwich.tsx b/vinvoor/src/navbar/NavBarSandwich.tsx
index 2c6b18f..ba9571c 100644
--- a/vinvoor/src/navbar/NavBarSandwich.tsx
+++ b/vinvoor/src/navbar/NavBarSandwich.tsx
@@ -1,16 +1,19 @@
+import type {
+ SxProps,
+ Theme,
+} from "@mui/material";
+import type { FC, MouseEvent } from "react";
+import type { PageIcon } from "./NavBar";
import MenuIcon from "@mui/icons-material/Menu";
import {
Box,
IconButton,
Menu,
MenuItem,
- SxProps,
- Theme,
Typography,
} from "@mui/material";
-import { FC, MouseEvent, useState } from "react";
+import { useState } from "react";
import { UnstyledLink } from "../components/UnstyledLink";
-import { PageIcon } from "./NavBar";
interface NavBarSandwichProps {
pageIcons: readonly PageIcon[];
diff --git a/vinvoor/src/navbar/NavBarSeasons.tsx b/vinvoor/src/navbar/NavBarSeasons.tsx
index 85c776b..bb096ed 100644
--- a/vinvoor/src/navbar/NavBarSeasons.tsx
+++ b/vinvoor/src/navbar/NavBarSeasons.tsx
@@ -1,10 +1,11 @@
-import { useState, MouseEvent } from "react";
+import type { MouseEvent } from "react";
+import { ArrowDropDown, Refresh } from "@mui/icons-material";
+import { Button, IconButton, Menu, MenuItem, Typography } from "@mui/material";
+import { useState } from "react";
import { useSeasons, useSetSeason } from "../hooks/useSeasons";
import { useSettings } from "../hooks/useSettings";
-import { Button, IconButton, Menu, MenuItem, Typography } from "@mui/material";
-import { ArrowDropDown, Refresh } from "@mui/icons-material";
-export const NavBarSeasons = () => {
+export function NavBarSeasons() {
const { data: seasons } = useSeasons();
const { data: settings, refetch } = useSettings();
const { setSeason } = useSetSeason();
@@ -89,4 +90,4 @@ export const NavBarSeasons = () => {
)}
>
);
-};
+}
diff --git a/vinvoor/src/navbar/NavBarUserMenu.tsx b/vinvoor/src/navbar/NavBarUserMenu.tsx
index 78c493c..6ffc464 100644
--- a/vinvoor/src/navbar/NavBarUserMenu.tsx
+++ b/vinvoor/src/navbar/NavBarUserMenu.tsx
@@ -1,3 +1,5 @@
+import type { FC, MouseEvent } from "react";
+import type { PageIcon } from "./NavBar";
import {
Button,
Divider,
@@ -8,13 +10,12 @@ import {
} from "@mui/material";
import { useTheme } from "@mui/material/styles";
import { Cow, ExitRun, ShieldAccountOutline } from "mdi-material-ui";
-import { FC, MouseEvent, useState } from "react";
+import { useState } from "react";
import { Login } from "../auth/Login";
import { Logout } from "../auth/Logout";
import { BrowserView } from "../components/BrowserView";
import { UnstyledLink } from "../components/UnstyledLink";
import { useUser } from "../hooks/useUser";
-import { PageIcon } from "./NavBar";
interface NavBarUserMenuProps {
pageIcons: readonly PageIcon[];
@@ -44,105 +45,109 @@ export const NavBarUserMenu: FC = ({
return (
<>
- {user ? (
- <>
-
-
- >
- ) : (
-
- Login
-
- )}
+
+ >
+ )
+ : (
+
+ Login
+
+ )}
>
);
};
diff --git a/vinvoor/src/overview/Overview.tsx b/vinvoor/src/overview/Overview.tsx
index ce60813..c3b0e5f 100644
--- a/vinvoor/src/overview/Overview.tsx
+++ b/vinvoor/src/overview/Overview.tsx
@@ -4,16 +4,16 @@ import { useEffect, useLayoutEffect, useRef, useState } from "react";
import { Tooltip } from "react-tooltip";
import { BrowserView } from "../components/BrowserView";
import { LoadingSkeleton } from "../components/LoadingSkeleton";
+import { useScans } from "../hooks/useScan";
+import { useSeasons } from "../hooks/useSeasons";
+import { useSettings } from "../hooks/useSettings";
import { CheckIn } from "./checkin/CheckIn";
import { Days } from "./days/Days";
import { Heatmap } from "./heatmap/Heatmap";
import { HeatmapVariant } from "./heatmap/types";
import { Streak } from "./streak/Streak";
-import { useScans } from "../hooks/useScan";
-import { useSeasons } from "../hooks/useSeasons";
-import { useSettings } from "../hooks/useSettings";
-export const Overview = () => {
+export function Overview() {
const scansQuery = useScans();
const seasonsQuery = useSeasons();
const settingsQuery = useSettings();
@@ -47,7 +47,8 @@ export const Overview = () => {
seasons.length > 1 ? seasons[1].start : seasons[0].start,
new Date(),
]);
- } else {
+ }
+ else {
setHeatmapDates([currentSeason.start, currentSeason.end]);
}
}
@@ -55,71 +56,73 @@ export const Overview = () => {
return (
- {scansQuery.data?.length ? (
-
-
-
-
-
-
-
-
-
-
- setChecked(false)}>
-
- Months
-
- Days
+ {scansQuery.data?.length
+ ? (
+
+
+
+
+
+
+
+
+
+
+ setChecked(false)}>
+
+ Months
+
+ Days
+
+
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+ )
+ : (
+
+
+
+ You don't have any scans.
+
+
+ Start scanning to see some data!
+
+
-
-
- ) : (
-
-
-
- You don't have any scans.
-
-
- Start scanning to see some data!
-
-
-
- )}
+ )}
);
-};
+}
diff --git a/vinvoor/src/overview/checkin/CheckIn.tsx b/vinvoor/src/overview/checkin/CheckIn.tsx
index 83bc60b..bf3578d 100644
--- a/vinvoor/src/overview/checkin/CheckIn.tsx
+++ b/vinvoor/src/overview/checkin/CheckIn.tsx
@@ -1,31 +1,34 @@
import { Alert, AlertTitle } from "@mui/material";
import { EmoticonExcitedOutline, EmoticonFrownOutline } from "mdi-material-ui";
-import { isTheSameDay } from "../../util/util";
import { useScans } from "../../hooks/useScan";
+import { isTheSameDay } from "../../util/util";
-export const CheckIn = () => {
+export function CheckIn() {
const { data: scans } = useScans();
- if (!scans) return null; // Can never happen
+ if (!scans)
+ return null; // Can never happen
const checkedIn = isTheSameDay(scans[scans.length - 1].scanTime, new Date());
- return checkedIn ? (
- }
- >
- Checked in
- Nice of you to stop by !
-
- ) : (
- }
- >
- Not checked in
- We miss you !
-
- );
-};
+ return checkedIn
+ ? (
+ }
+ >
+ Checked in
+ Nice of you to stop by !
+
+ )
+ : (
+ }
+ >
+ Not checked in
+ We miss you !
+
+ );
+}
diff --git a/vinvoor/src/overview/days/Days.tsx b/vinvoor/src/overview/days/Days.tsx
index 4167946..43bb6a1 100644
--- a/vinvoor/src/overview/days/Days.tsx
+++ b/vinvoor/src/overview/days/Days.tsx
@@ -1,21 +1,22 @@
+import type { ApexOptions } from "apexcharts";
+import type { Scan } from "../../types/scans";
import { useTheme } from "@mui/material";
-import { ApexOptions } from "apexcharts";
import Chart from "react-apexcharts";
-import { Scan } from "../../types/scans";
import { useScans } from "../../hooks/useScan";
-const getDayCount = (scans: readonly Scan[]) => {
+function getDayCount(scans: readonly Scan[]) {
const days = [0, 0, 0, 0, 0, 0, 0];
- scans.forEach(scan => {
+ scans.forEach((scan) => {
days[scan.scanTime.getDay() - 1]++;
});
return days.slice(0, -2) as ApexNonAxisChartSeries;
-};
+}
-export const Days = () => {
+export function Days() {
const theme = useTheme();
const { data: scans } = useScans();
- if (!scans) return null; // Can never happen
+ if (!scans)
+ return null; // Can never happen
const state = {
options: {
@@ -65,4 +66,4 @@ export const Days = () => {
return (
);
-};
+}
diff --git a/vinvoor/src/overview/heatmap/Day.tsx b/vinvoor/src/overview/heatmap/Day.tsx
index 4732712..df596e6 100644
--- a/vinvoor/src/overview/heatmap/Day.tsx
+++ b/vinvoor/src/overview/heatmap/Day.tsx
@@ -1,8 +1,9 @@
+import type { FC } from "react";
+import type { DayData, HeatmapVariant } from "./types";
import { useTheme } from "@mui/material";
-import { FC, useMemo } from "react";
-import "./heatmap.css";
+import { useMemo } from "react";
+import { useScans } from "../../hooks/useScan";
import { Rect } from "./Rect";
-import { DayData, HeatmapVariant } from "./types";
import {
DATE_FORMATTER,
DAYS_IN_WEEK,
@@ -14,7 +15,7 @@ import {
styleMonth,
WEEKS_IN_MONTH,
} from "./utils";
-import { useScans } from "../../hooks/useScan";
+import "./heatmap.css";
interface DayProps {
startDate: Date;
@@ -35,17 +36,16 @@ export const Day: FC = ({
}) => {
const theme = useTheme();
const { data: scans } = useScans();
- if (!scans) return null; // Can never happen
const data = useMemo(() => {
- const normalizedScans = [...scans];
+ const normalizedScans = [...scans ?? []];
// normalizedScans.forEach(scan => scan.scanTime.setHours(0, 0, 0, 0));
const formattedScans = formatData(normalizedScans);
const start = new Date(
- startDate.getTime() -
- startDate.getDay() * MILLISECONDS_IN_DAY +
- MILLISECONDS_IN_DAY,
+ startDate.getTime()
+ - startDate.getDay() * MILLISECONDS_IN_DAY
+ + MILLISECONDS_IN_DAY,
);
const startDates = Array.from(
@@ -58,7 +58,8 @@ export const Day: FC = ({
while (newStartDate.getDay() !== 1) {
newStartDate.setDate(newStartDate.getDate() - 1);
}
- } else {
+ }
+ else {
newStartDate.setMonth(newStartDate.getMonth() + idx);
newStartDate.setDate(1);
while (newStartDate.getDay() !== 1) {
@@ -71,9 +72,9 @@ export const Day: FC = ({
);
const endWeek = new Date(
- endDate.getTime() +
- MILLISECONDS_IN_DAY *
- (DAYS_IN_WEEK - (getMondayIndexedDay(endDate) % DAYS_IN_WEEK)),
+ endDate.getTime()
+ + MILLISECONDS_IN_DAY
+ * (DAYS_IN_WEEK - (getMondayIndexedDay(endDate) % DAYS_IN_WEEK)),
);
return {
@@ -84,6 +85,9 @@ export const Day: FC = ({
};
}, [scans, startDate, endDate]);
+ if (!scans)
+ return null; // Can never happen
+
return (
{Array.from({ length: columnCount }, (_, idx) => {
@@ -91,79 +95,82 @@ export const Day: FC = ({
{isDayVariant(variant)
? Array.from({ length: DAYS_IN_WEEK }, (_, cidx) => {
- const currentDate = new Date(
- data.start.getTime() +
- MILLISECONDS_IN_DAY * (idx * DAYS_IN_WEEK + cidx),
- );
-
- if (currentDate.getTime() < startDate.getTime()) return null;
-
- if (currentDate.getTime() > endDate.getTime()) return null;
-
- let colors = theme.heatmap.colorInActive;
- if (data.data[currentDate.getTime()])
- colors = theme.heatmap.colorActive;
-
- const dataTooltipContent = `${
- data.data[currentDate.getTime()] ? "Present" : "Absent"
- } on ${DATE_FORMATTER.format(currentDate)}`;
-
- return (
-
- );
- })
+ const currentDate = new Date(
+ data.start.getTime()
+ + MILLISECONDS_IN_DAY * (idx * DAYS_IN_WEEK + cidx),
+ );
+
+ if (currentDate.getTime() < startDate.getTime())
+ return null;
+
+ if (currentDate.getTime() > endDate.getTime())
+ return null;
+
+ let colors = theme.heatmap.colorInActive;
+ if (data.data[currentDate.getTime()])
+ colors = theme.heatmap.colorActive;
+
+ const dataTooltipContent = `${
+ data.data[currentDate.getTime()] ? "Present" : "Absent"
+ } on ${DATE_FORMATTER.format(currentDate)}`;
+
+ return (
+
+ );
+ })
: Array.from({ length: WEEKS_IN_MONTH }, (_, cidx) => {
- const currentDate = new Date(
- data.startDates[idx].getTime() +
- MILLISECONDS_IN_DAY * cidx * DAYS_IN_WEEK,
- );
-
- // Week is no longer in the month
- if (
- currentDate.getMonth() > startDate.getMonth() + idx &&
- getMondayIndexedDay(currentDate) <=
- currentDate.getDate() - 1
- )
- return null;
-
- // Week is after end date
- if (currentDate.getTime() >= data.endWeek.getTime())
- return null;
-
- const count = Array.from(
- { length: DAYS_IN_WEEK },
- (_, i) =>
- new Date(currentDate.getTime() + i * MILLISECONDS_IN_DAY),
- ).filter(
- date =>
- date.getTime() <= endDate.getTime() &&
- data.data[date.getTime()],
- ).length;
-
- const colors = styleMonth[Math.min(count, 5)](theme); // Can be higher than 5 if multiple scans in a day or scanned during the weekend
-
- const dataTooltipContent = `${count} scan${
- count !== 1 ? "s" : ""
- } in the week of ${DATE_FORMATTER.format(currentDate)}`;
-
- return (
-
- );
- })}
+ const currentDate = new Date(
+ data.startDates[idx].getTime()
+ + MILLISECONDS_IN_DAY * cidx * DAYS_IN_WEEK,
+ );
+
+ // Week is no longer in the month
+ if (
+ currentDate.getMonth() > startDate.getMonth() + idx
+ && getMondayIndexedDay(currentDate)
+ <= currentDate.getDate() - 1
+ ) {
+ return null;
+ }
+
+ // Week is after end date
+ if (currentDate.getTime() >= data.endWeek.getTime())
+ return null;
+
+ const count = Array.from(
+ { length: DAYS_IN_WEEK },
+ (_, i) =>
+ new Date(currentDate.getTime() + i * MILLISECONDS_IN_DAY),
+ ).filter(
+ date =>
+ date.getTime() <= endDate.getTime()
+ && data.data[date.getTime()],
+ ).length;
+
+ const colors = styleMonth[Math.min(count, 5)](theme); // Can be higher than 5 if multiple scans in a day or scanned during the weekend
+
+ const dataTooltipContent = `${count} scan${
+ count !== 1 ? "s" : ""
+ } in the week of ${DATE_FORMATTER.format(currentDate)}`;
+
+ return (
+
+ );
+ })}
);
})}
diff --git a/vinvoor/src/overview/heatmap/Heatmap.tsx b/vinvoor/src/overview/heatmap/Heatmap.tsx
index fe1ae27..351805d 100644
--- a/vinvoor/src/overview/heatmap/Heatmap.tsx
+++ b/vinvoor/src/overview/heatmap/Heatmap.tsx
@@ -1,8 +1,8 @@
+import type { FC } from "react";
+import type { HeatmapVariant } from "./types";
import { useMediaQuery, useTheme } from "@mui/material";
-import { FC } from "react";
import { Day } from "./Day";
import { LabelsMonth } from "./LabelsMonth";
-import { HeatmapVariant } from "./types";
import {
DAYS_IN_WEEK,
getColumnCountDays,
@@ -35,12 +35,12 @@ export const Heatmap: FC = ({ startDate, endDate, variant }) => {
return (