diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..ddb9fa4 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,48 @@ +{ + "env": { + "browser": true, + "es2021": true + }, + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:@typescript-eslint/stylistic", + "plugin:react/recommended", + "plugin:react-hooks/recommended", + "plugin:tailwindcss/recommended" + ], + "parserOptions": { + "ecmaFeatures": { + "jsx": true + }, + "ecmaVersion": 12, + "sourceType": "module" + }, + "plugins": [ + "react", + "react-hooks", + "tailwindcss" + ], + "rules": { + "no-undef": ["error", {"typeof": true}], + "react-hooks/exhaustive-deps": "off", + "react/react-in-jsx-scope": "off", + "react/require-default-props": "off", + "semi": [2, "never"], + "tailwindcss/no-custom-classname": ["warn", { + "cssFiles": ["resources/css/app.css"], + "whitelist": [] + }], + "tailwindcss/enforces-negative-arbitrary-values": "warn", + "tailwindcss/enforces-shorthand": "warn", + "tailwindcss/migration-from-tailwind-2": "warn", + // "tailwindcss/no-arbitrary-value": "off", + // "tailwindcss/no-arbitrary-value": "error", + "tailwindcss/no-contradicting-classname": "error" + }, + "settings": { + "react": { + "version": "18.2" + } + } +} diff --git a/app/Http/Controllers/ToDoController.php b/app/Http/Controllers/ToDoController.php index d1a0596..a7765ac 100644 --- a/app/Http/Controllers/ToDoController.php +++ b/app/Http/Controllers/ToDoController.php @@ -48,7 +48,7 @@ class ToDoController extends Controller $data['checked'] = $request->input('checked') ? now() : null; $todo->update($data); - if ($request->user()->currentTimeTracker->to_do_id === $todo->id) { + if ($request->user()->currentTimeTracker?->to_do_id === $todo->id) { $request->user()->stopCurrentTimeTracker(); } diff --git a/app/Http/Requests/ToDoRequest.php b/app/Http/Requests/ToDoRequest.php index bd52308..6f81076 100644 --- a/app/Http/Requests/ToDoRequest.php +++ b/app/Http/Requests/ToDoRequest.php @@ -23,7 +23,8 @@ class ToDoRequest extends FormRequest { return [ 'name' => ['string', 'min:3', 'max:255'], - 'checked' => ['boolean'], + 'description' => ['string', 'max:2000'], + 'checked' => ['boolean', 'nullable'], ]; } } diff --git a/app/Http/Resources/ToDoResource.php b/app/Http/Resources/ToDoResource.php index 8be4c9c..9826013 100644 --- a/app/Http/Resources/ToDoResource.php +++ b/app/Http/Resources/ToDoResource.php @@ -18,6 +18,7 @@ class ToDoResource extends JsonResource 'id' => $this->id, 'user_id' => $this->user_id, 'name' => $this->name, + 'description' => $this->description, 'checked' => $this->checked, 'duration' => $this->duration, ]; diff --git a/package.json b/package.json index ef1ffd0..8cc89d4 100644 --- a/package.json +++ b/package.json @@ -3,11 +3,15 @@ "type": "module", "scripts": { "dev": "vite", - "build": "vite build" + "build": "vite build", + "lint": "./node_modules/.bin/eslint resources/js/ --ext .js,.jsx,ts,tsx", + "lint-fix": "eslint ./ --fix" }, "devDependencies": { "@types/react": "^18.2.48", "@types/react-dom": "^18.2.18", + "@typescript-eslint/eslint-plugin": "^7.0.1", + "@typescript-eslint/parser": "^7.0.1", "@vitejs/plugin-react": "^4.2.1", "autoprefixer": "^10.4.17", "axios": "^1.6.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 44f9d7d..f4a2587 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -22,6 +22,12 @@ devDependencies: '@types/react-dom': specifier: ^18.2.18 version: 18.2.18 + '@typescript-eslint/eslint-plugin': + specifier: ^7.0.1 + version: 7.0.1(@typescript-eslint/parser@7.0.1)(eslint@8.56.0)(typescript@5.3.3) + '@typescript-eslint/parser': + specifier: ^7.0.1 + version: 7.0.1(eslint@8.56.0)(typescript@5.3.3) '@vitejs/plugin-react': specifier: ^4.2.1 version: 4.2.1(vite@5.0.12) @@ -771,6 +777,10 @@ packages: resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} dev: true + /@types/json-schema@7.0.15: + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + dev: true + /@types/prop-types@15.7.11: resolution: {integrity: sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==} dev: true @@ -793,6 +803,142 @@ packages: resolution: {integrity: sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==} dev: true + /@types/semver@7.5.7: + resolution: {integrity: sha512-/wdoPq1QqkSj9/QOeKkFquEuPzQbHTWAMPH/PaUMB+JuR31lXhlWXRZ52IpfDYVlDOUBvX09uBrPwxGT1hjNBg==} + dev: true + + /@typescript-eslint/eslint-plugin@7.0.1(@typescript-eslint/parser@7.0.1)(eslint@8.56.0)(typescript@5.3.3): + resolution: {integrity: sha512-OLvgeBv3vXlnnJGIAgCLYKjgMEU+wBGj07MQ/nxAaON+3mLzX7mJbhRYrVGiVvFiXtwFlkcBa/TtmglHy0UbzQ==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + '@typescript-eslint/parser': ^7.0.0 + eslint: ^8.56.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@eslint-community/regexpp': 4.10.0 + '@typescript-eslint/parser': 7.0.1(eslint@8.56.0)(typescript@5.3.3) + '@typescript-eslint/scope-manager': 7.0.1 + '@typescript-eslint/type-utils': 7.0.1(eslint@8.56.0)(typescript@5.3.3) + '@typescript-eslint/utils': 7.0.1(eslint@8.56.0)(typescript@5.3.3) + '@typescript-eslint/visitor-keys': 7.0.1 + debug: 4.3.4 + eslint: 8.56.0 + graphemer: 1.4.0 + ignore: 5.3.0 + natural-compare: 1.4.0 + semver: 7.6.0 + ts-api-utils: 1.2.1(typescript@5.3.3) + typescript: 5.3.3 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/parser@7.0.1(eslint@8.56.0)(typescript@5.3.3): + resolution: {integrity: sha512-8GcRRZNzaHxKzBPU3tKtFNing571/GwPBeCvmAUw0yBtfE2XVd0zFKJIMSWkHJcPQi0ekxjIts6L/rrZq5cxGQ==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^8.56.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/scope-manager': 7.0.1 + '@typescript-eslint/types': 7.0.1 + '@typescript-eslint/typescript-estree': 7.0.1(typescript@5.3.3) + '@typescript-eslint/visitor-keys': 7.0.1 + debug: 4.3.4 + eslint: 8.56.0 + typescript: 5.3.3 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/scope-manager@7.0.1: + resolution: {integrity: sha512-v7/T7As10g3bcWOOPAcbnMDuvctHzCFYCG/8R4bK4iYzdFqsZTbXGln0cZNVcwQcwewsYU2BJLay8j0/4zOk4w==} + engines: {node: ^16.0.0 || >=18.0.0} + dependencies: + '@typescript-eslint/types': 7.0.1 + '@typescript-eslint/visitor-keys': 7.0.1 + dev: true + + /@typescript-eslint/type-utils@7.0.1(eslint@8.56.0)(typescript@5.3.3): + resolution: {integrity: sha512-YtT9UcstTG5Yqy4xtLiClm1ZpM/pWVGFnkAa90UfdkkZsR1eP2mR/1jbHeYp8Ay1l1JHPyGvoUYR6o3On5Nhmw==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^8.56.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/typescript-estree': 7.0.1(typescript@5.3.3) + '@typescript-eslint/utils': 7.0.1(eslint@8.56.0)(typescript@5.3.3) + debug: 4.3.4 + eslint: 8.56.0 + ts-api-utils: 1.2.1(typescript@5.3.3) + typescript: 5.3.3 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/types@7.0.1: + resolution: {integrity: sha512-uJDfmirz4FHib6ENju/7cz9SdMSkeVvJDK3VcMFvf/hAShg8C74FW+06MaQPODHfDJp/z/zHfgawIJRjlu0RLg==} + engines: {node: ^16.0.0 || >=18.0.0} + dev: true + + /@typescript-eslint/typescript-estree@7.0.1(typescript@5.3.3): + resolution: {integrity: sha512-SO9wHb6ph0/FN5OJxH4MiPscGah5wjOd0RRpaLvuBv9g8565Fgu0uMySFEPqwPHiQU90yzJ2FjRYKGrAhS1xig==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 7.0.1 + '@typescript-eslint/visitor-keys': 7.0.1 + debug: 4.3.4 + globby: 11.1.0 + is-glob: 4.0.3 + minimatch: 9.0.3 + semver: 7.6.0 + ts-api-utils: 1.2.1(typescript@5.3.3) + typescript: 5.3.3 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/utils@7.0.1(eslint@8.56.0)(typescript@5.3.3): + resolution: {integrity: sha512-oe4his30JgPbnv+9Vef1h48jm0S6ft4mNwi9wj7bX10joGn07QRfqIqFHoMiajrtoU88cIhXf8ahwgrcbNLgPA==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^8.56.0 + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.56.0) + '@types/json-schema': 7.0.15 + '@types/semver': 7.5.7 + '@typescript-eslint/scope-manager': 7.0.1 + '@typescript-eslint/types': 7.0.1 + '@typescript-eslint/typescript-estree': 7.0.1(typescript@5.3.3) + eslint: 8.56.0 + semver: 7.6.0 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@typescript-eslint/visitor-keys@7.0.1: + resolution: {integrity: sha512-hwAgrOyk++RTXrP4KzCg7zB2U0xt7RUU0ZdMSCsqF3eKUwkdXUMyTb0qdCuji7VIbcpG62kKTU9M1J1c9UpFBw==} + engines: {node: ^16.0.0 || >=18.0.0} + dependencies: + '@typescript-eslint/types': 7.0.1 + eslint-visitor-keys: 3.4.3 + dev: true + /@ungap/structured-clone@1.2.0: resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} dev: true @@ -903,6 +1049,11 @@ packages: is-string: 1.0.7 dev: true + /array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + dev: true + /array.prototype.flat@1.3.2: resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} engines: {node: '>= 0.4'} @@ -1184,6 +1335,13 @@ packages: resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} dev: true + /dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + dependencies: + path-type: 4.0.0 + dev: true + /dlv@1.1.3: resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} dev: true @@ -1699,6 +1857,18 @@ packages: define-properties: 1.2.1 dev: true + /globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.2 + ignore: 5.3.0 + merge2: 1.4.1 + slash: 3.0.0 + dev: true + /gopd@1.0.1: resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} dependencies: @@ -2101,6 +2271,13 @@ packages: yallist: 3.1.1 dev: true + /lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + dependencies: + yallist: 4.0.0 + dev: true + /merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} @@ -2309,6 +2486,11 @@ packages: minipass: 7.0.4 dev: true + /path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + dev: true + /picocolors@1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} dev: true @@ -2601,6 +2783,14 @@ packages: hasBin: true dev: true + /semver@7.6.0: + resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==} + engines: {node: '>=10'} + hasBin: true + dependencies: + lru-cache: 6.0.0 + dev: true + /set-function-length@1.2.0: resolution: {integrity: sha512-4DBHDoyHlM1IRPGYcoxexgh67y4ueR53FKV1yyxwFMY7aCqcN/38M1+SwZ/qJQ8iLv7+ck385ot4CcisOAPT9w==} engines: {node: '>= 0.4'} @@ -2646,6 +2836,11 @@ packages: engines: {node: '>=14'} dev: true + /slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + dev: true + /source-map-js@1.0.2: resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} engines: {node: '>=0.10.0'} @@ -2820,6 +3015,15 @@ packages: is-number: 7.0.0 dev: true + /ts-api-utils@1.2.1(typescript@5.3.3): + resolution: {integrity: sha512-RIYA36cJn2WiH9Hy77hdF9r7oEwxAtB/TS9/S4Qd90Ap4z5FSiin5zEiTL44OII1Y3IIlEvxwxFUVgrHSZ/UpA==} + engines: {node: '>=16'} + peerDependencies: + typescript: '>=4.2.0' + dependencies: + typescript: 5.3.3 + dev: true + /ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} dev: true @@ -3034,6 +3238,10 @@ packages: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} dev: true + /yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + dev: true + /yaml@2.3.4: resolution: {integrity: sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==} engines: {node: '>= 14'} diff --git a/resources/js/app.tsx b/resources/js/app.tsx index 91abe26..794c3d0 100644 --- a/resources/js/app.tsx +++ b/resources/js/app.tsx @@ -1,7 +1,7 @@ -import React from 'react'; -import './bootstrap'; -import {createRoot} from "react-dom/client"; -import App from "./pages/App"; +import React from 'react' +import './bootstrap' +import {createRoot} from "react-dom/client" +import App from "./pages/App" import '../css/app.css' import './utilities/customProperties.ts' diff --git a/resources/js/bootstrap.js b/resources/js/bootstrap.js index 846d350..4f8b981 100644 --- a/resources/js/bootstrap.js +++ b/resources/js/bootstrap.js @@ -4,10 +4,10 @@ * CSRF token as a header based on the value of the "XSRF" token cookie. */ -import axios from 'axios'; -window.axios = axios; +import axios from 'axios' +window.axios = axios -window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; +window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest' /** * Echo exposes an expressive API for subscribing to channels and listening diff --git a/resources/js/components/Card.tsx b/resources/js/components/Card.tsx index c70b1d9..94f2fff 100644 --- a/resources/js/components/Card.tsx +++ b/resources/js/components/Card.tsx @@ -1,9 +1,9 @@ -import React, {FC} from "react"; -import {PropsWithChildren} from "react"; +import React, {FC} from "react" +import {PropsWithChildren} from "react" const Card: FC> = ({children, className = ''}) => { - return
+ return
{children}
} diff --git a/resources/js/components/Field.tsx b/resources/js/components/Field.tsx index 6267e8a..1916467 100644 --- a/resources/js/components/Field.tsx +++ b/resources/js/components/Field.tsx @@ -10,7 +10,7 @@ const Field: FC = ({children, type = 'text', className = '', classNa htmlFor={props.id ?? undefined}> {children} } -
@@ -24,7 +24,7 @@ interface FieldProps { type?: HTMLInputTypeAttribute, name: string, id?: string, - value: any, + value: string|number|undefined, placeholder?: string, autoFocus?: boolean, className?: string, @@ -32,3 +32,27 @@ interface FieldProps { step?: string, onChange: (event: React.ChangeEvent) => void, } + +export const TextArea: FC = ({children, name, value, className = '', classNameForm = '', ...props}) => { + + return
+ {children && } + +
+
+} + +interface TextAreaProps { + children?: ReactElement|string, + id?: string, + name: string, + value: string|undefined, + className?: string, + classNameForm?: string, + onChange: (event: React.ChangeEvent) => void, +} diff --git a/resources/js/components/Header.tsx b/resources/js/components/Header.tsx index 4f9aba1..0c1d205 100644 --- a/resources/js/components/Header.tsx +++ b/resources/js/components/Header.tsx @@ -1,7 +1,7 @@ import React from "react" import {Link, NavLink, useLocation} from "react-router-dom" -import useAuthUser from "../hooks/AuthUser"; -import Tracker from "./TimeTrackers/Tracker"; +import useAuthUser from "../hooks/AuthUser" +import Tracker from "./TimeTrackers/Tracker" const Header = () => { @@ -10,8 +10,8 @@ const Header = () => { console.log(authUser) - return
-
+ return
+
Ticcat
@@ -26,7 +26,7 @@ const Header = () => { {/*S'inscrire*/} }
-