From 115d597a09637b88b072e67310831851f00fa632 Mon Sep 17 00:00:00 2001 From: Romulus21 Date: Wed, 6 Mar 2024 09:42:12 +0100 Subject: [PATCH] add lint js --- .eslintrc.json | 38 ++-- package.json | 2 + pnpm-lock.yaml | 184 ++++++++++++++++++ resources/js/components/Card.tsx | 6 +- resources/js/components/Field.tsx | 4 +- resources/js/components/Header.tsx | 2 +- resources/js/components/Img.tsx | 2 +- .../js/components/rainfall/AddRainfall.tsx | 14 +- .../js/components/rainfall/LastFiveMesure.tsx | 16 +- .../components/rainfall/RainFallEcharts.tsx | 122 ++++++++++++ .../js/components/rainfall/RainfallGraph.tsx | 8 +- resources/js/customPrototypes.ts | 1 + resources/js/hooks/AuthUser.tsx | 8 +- resources/js/hooks/AxiosTools.tsx | 24 +-- resources/js/hooks/DimensionHook.tsx | 3 +- resources/js/pages/Auth/ForgotPassword.tsx | 19 +- resources/js/pages/Auth/Login.tsx | 23 ++- resources/js/pages/Auth/Profile.tsx | 12 +- resources/js/pages/Auth/Register.tsx | 24 +-- resources/js/pages/Auth/Reset.tsx | 22 +-- resources/js/pages/Rainfall.tsx | 41 ++-- resources/js/pages/Rainfall/RainfallIndex.tsx | 16 +- resources/js/pages/Router.tsx | 3 +- resources/js/pages/Weather.tsx | 23 ++- resources/js/types.ts | 4 - resources/js/utilities/form.ts | 21 +- 26 files changed, 479 insertions(+), 163 deletions(-) create mode 100644 resources/js/components/rainfall/RainFallEcharts.tsx diff --git a/.eslintrc.json b/.eslintrc.json index ef23d49..ddb9fa4 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -4,7 +4,12 @@ "es2021": true }, "extends": [ - "plugin:react/recommended" + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:@typescript-eslint/stylistic", + "plugin:react/recommended", + "plugin:react-hooks/recommended", + "plugin:tailwindcss/recommended" ], "parserOptions": { "ecmaFeatures": { @@ -19,30 +24,25 @@ "tailwindcss" ], "rules": { - "react-hooks/rules-of-hooks": "error", + "no-undef": ["error", {"typeof": true}], + "react-hooks/exhaustive-deps": "off", "react/react-in-jsx-scope": "off", - "react/button-has-type": "error", - "react/prop-types": "error", "react/require-default-props": "off", - "react/no-array-index-key": "error", - "react/jsx-uses-react": "error", - "react/display-name": "error", - "react/no-danger-with-children": "error", - // "react-hooks/exhaustive-deps": "warn", - // "react/jsx-no-bind": "error", - "react/jsx-uses-vars": "error", - "no-restricted-syntax": ["warn", { - "selector": "CallExpression[callee.object.name='console'][callee.property.name!=/^(warn|info)$/]", - "message": "Unexpected property on console object was called" - }], "semi": [2, "never"], - "tailwindcss/classnames-order": "warn", + "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": "off", + // "tailwindcss/no-arbitrary-value": "error", "tailwindcss/no-contradicting-classname": "error" + }, + "settings": { + "react": { + "version": "18.2" + } } } - -// https://dev.to/logrocket/12-essential-eslint-rules-for-react-5doc diff --git a/package.json b/package.json index 9008a72..0d0fce3 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "@types/d3": "^7.4.3", "@types/react": "^18.2.58", "@types/react-dom": "^18.2.19", + "@typescript-eslint/eslint-plugin": "^7.1.1", "@vite-pwa/assets-generator": "^0.0.11", "@vitejs/plugin-react": "^4.2.1", "autoprefixer": "^10.4.17", @@ -34,6 +35,7 @@ }, "dependencies": { "d3": "^7.8.5", + "echarts": "^5.5.0", "react-router-dom": "^6.22.1", "vite-plugin-pwa": "^0.17.5" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 24971d9..91a6e3a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,9 @@ dependencies: d3: specifier: ^7.8.5 version: 7.8.5 + echarts: + specifier: ^5.5.0 + version: 5.5.0 react-router-dom: specifier: ^6.22.1 version: 6.22.1(react-dom@18.2.0)(react@18.2.0) @@ -28,6 +31,9 @@ devDependencies: '@types/react-dom': specifier: ^18.2.19 version: 18.2.19 + '@typescript-eslint/eslint-plugin': + specifier: ^7.1.1 + version: 7.1.1(@typescript-eslint/parser@7.1.1)(eslint@8.57.0)(typescript@5.3.3) '@vite-pwa/assets-generator': specifier: ^0.0.11 version: 0.0.11 @@ -1887,6 +1893,10 @@ packages: '@types/node': 20.11.20 dev: true + /@types/json-schema@7.0.15: + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + dev: true + /@types/minimatch@5.1.2: resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} dev: true @@ -1924,10 +1934,146 @@ packages: resolution: {integrity: sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==} dev: true + /@types/semver@7.5.8: + resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} + dev: true + /@types/trusted-types@2.0.7: resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} dev: false + /@typescript-eslint/eslint-plugin@7.1.1(@typescript-eslint/parser@7.1.1)(eslint@8.57.0)(typescript@5.3.3): + resolution: {integrity: sha512-zioDz623d0RHNhvx0eesUmGfIjzrk18nSBC8xewepKXbBvN/7c1qImV7Hg8TI1URTxKax7/zxfxj3Uph8Chcuw==} + 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.1.1(eslint@8.57.0)(typescript@5.3.3) + '@typescript-eslint/scope-manager': 7.1.1 + '@typescript-eslint/type-utils': 7.1.1(eslint@8.57.0)(typescript@5.3.3) + '@typescript-eslint/utils': 7.1.1(eslint@8.57.0)(typescript@5.3.3) + '@typescript-eslint/visitor-keys': 7.1.1 + debug: 4.3.4 + eslint: 8.57.0 + graphemer: 1.4.0 + ignore: 5.3.1 + 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.1.1(eslint@8.57.0)(typescript@5.3.3): + resolution: {integrity: sha512-ZWUFyL0z04R1nAEgr9e79YtV5LbafdOtN7yapNbn1ansMyaegl2D4bL7vHoJ4HPSc4CaLwuCVas8CVuneKzplQ==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^8.56.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/scope-manager': 7.1.1 + '@typescript-eslint/types': 7.1.1 + '@typescript-eslint/typescript-estree': 7.1.1(typescript@5.3.3) + '@typescript-eslint/visitor-keys': 7.1.1 + debug: 4.3.4 + eslint: 8.57.0 + typescript: 5.3.3 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/scope-manager@7.1.1: + resolution: {integrity: sha512-cirZpA8bJMRb4WZ+rO6+mnOJrGFDd38WoXCEI57+CYBqta8Yc8aJym2i7vyqLL1vVYljgw0X27axkUXz32T8TA==} + engines: {node: ^16.0.0 || >=18.0.0} + dependencies: + '@typescript-eslint/types': 7.1.1 + '@typescript-eslint/visitor-keys': 7.1.1 + dev: true + + /@typescript-eslint/type-utils@7.1.1(eslint@8.57.0)(typescript@5.3.3): + resolution: {integrity: sha512-5r4RKze6XHEEhlZnJtR3GYeCh1IueUHdbrukV2KSlLXaTjuSfeVF8mZUVPLovidCuZfbVjfhi4c0DNSa/Rdg5g==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^8.56.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/typescript-estree': 7.1.1(typescript@5.3.3) + '@typescript-eslint/utils': 7.1.1(eslint@8.57.0)(typescript@5.3.3) + debug: 4.3.4 + eslint: 8.57.0 + ts-api-utils: 1.2.1(typescript@5.3.3) + typescript: 5.3.3 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/types@7.1.1: + resolution: {integrity: sha512-KhewzrlRMrgeKm1U9bh2z5aoL4s7K3tK5DwHDn8MHv0yQfWFz/0ZR6trrIHHa5CsF83j/GgHqzdbzCXJ3crx0Q==} + engines: {node: ^16.0.0 || >=18.0.0} + dev: true + + /@typescript-eslint/typescript-estree@7.1.1(typescript@5.3.3): + resolution: {integrity: sha512-9ZOncVSfr+sMXVxxca2OJOPagRwT0u/UHikM2Rd6L/aB+kL/QAuTnsv6MeXtjzCJYb8PzrXarypSGIPx3Jemxw==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 7.1.1 + '@typescript-eslint/visitor-keys': 7.1.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.1.1(eslint@8.57.0)(typescript@5.3.3): + resolution: {integrity: sha512-thOXM89xA03xAE0lW7alstvnyoBUbBX38YtY+zAUcpRPcq9EIhXPuJ0YTv948MbzmKh6e1AUszn5cBFK49Umqg==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^8.56.0 + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@types/json-schema': 7.0.15 + '@types/semver': 7.5.8 + '@typescript-eslint/scope-manager': 7.1.1 + '@typescript-eslint/types': 7.1.1 + '@typescript-eslint/typescript-estree': 7.1.1(typescript@5.3.3) + eslint: 8.57.0 + semver: 7.6.0 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@typescript-eslint/visitor-keys@7.1.1: + resolution: {integrity: sha512-yTdHDQxY7cSoCcAtiBzVzxleJhkGB9NncSIyMYe2+OGON1ZsP9zOPws/Pqgopa65jvknOjlk/w7ulPlZ78PiLQ==} + engines: {node: ^16.0.0 || >=18.0.0} + dependencies: + '@typescript-eslint/types': 7.1.1 + eslint-visitor-keys: 3.4.3 + dev: true + /@ungap/structured-clone@1.2.0: resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} dev: true @@ -2825,6 +2971,13 @@ packages: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} dev: true + /echarts@5.5.0: + resolution: {integrity: sha512-rNYnNCzqDAPCr4m/fqyUFv7fD9qIsd50S6GDFgO1DxZhncCsNsG7IfUlAlvZe5oSEQxtsjnHiUuppzccry93Xw==} + dependencies: + tslib: 2.3.0 + zrender: 5.5.0 + dev: false + /ejs@3.1.9: resolution: {integrity: sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==} engines: {node: '>=0.10.0'} @@ -3386,6 +3539,18 @@ packages: slash: 3.0.0 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.1 + merge2: 1.4.1 + slash: 3.0.0 + dev: true + /gopd@1.0.1: resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} dependencies: @@ -4993,10 +5158,23 @@ packages: punycode: 2.3.1 dev: false + /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 + /tslib@2.3.0: + resolution: {integrity: sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==} + dev: false + /tunnel-agent@0.6.0: resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} dependencies: @@ -5462,3 +5640,9 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} dev: true + + /zrender@5.5.0: + resolution: {integrity: sha512-O3MilSi/9mwoovx77m6ROZM7sXShR/O/JIanvzTwjN3FORfLSr81PsUGd7jlaYOeds9d8tw82oP44+3YucVo+w==} + dependencies: + tslib: 2.3.0 + dev: false 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 9270dbf..8c4e584 100644 --- a/resources/js/components/Field.tsx +++ b/resources/js/components/Field.tsx @@ -10,7 +10,7 @@ const Field: FC = ({children, type = 'text', className = '', ...prop 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, diff --git a/resources/js/components/Header.tsx b/resources/js/components/Header.tsx index da13c4d..55c7138 100644 --- a/resources/js/components/Header.tsx +++ b/resources/js/components/Header.tsx @@ -7,7 +7,7 @@ const Header = () => { const {authUser} = useAuthUser() const location = useLocation() - return
+ return
Bermite
diff --git a/resources/js/components/Img.tsx b/resources/js/components/Img.tsx index 2d4a6c4..79559a4 100644 --- a/resources/js/components/Img.tsx +++ b/resources/js/components/Img.tsx @@ -1,4 +1,4 @@ -import React, {FC} from "react"; +import React, {FC} from "react" const Img: FC<{src: string, alt: string, width: string}> = ({src, alt, width, ...props}) => { diff --git a/resources/js/components/rainfall/AddRainfall.tsx b/resources/js/components/rainfall/AddRainfall.tsx index acf30d7..e54ed8c 100644 --- a/resources/js/components/rainfall/AddRainfall.tsx +++ b/resources/js/components/rainfall/AddRainfall.tsx @@ -1,7 +1,7 @@ import React, {Dispatch, FC, FormEvent, SetStateAction, useState} from "react" -import useAxiosTools from "../../hooks/AxiosTools"; -import Field from "../Field"; -import Card from "../Card"; +import useAxiosTools from "../../hooks/AxiosTools" +import Field from "../Field" +import Card from "../Card" const AddRainfall: FC = ({reload}) => { @@ -23,12 +23,12 @@ const AddRainfall: FC = ({reload}) => { } } - return -

- Ajout d'une mesure + return +

+ Ajout d'une mesure

{errorLabel()} -
+ = ({loadedAt}) => { @@ -27,14 +27,14 @@ const LastFiveMesure: FC = ({loadedAt}) => { } } - return -

5 dernières mesures

+ return +

5 dernières mesures

{errorLabel()} {data.map(line => - + )}
{(new Date(line.date)).toLocaleDateString()}{line.value}{line.value}
diff --git a/resources/js/components/rainfall/RainFallEcharts.tsx b/resources/js/components/rainfall/RainFallEcharts.tsx new file mode 100644 index 0000000..816833b --- /dev/null +++ b/resources/js/components/rainfall/RainFallEcharts.tsx @@ -0,0 +1,122 @@ +import React, {FC, useEffect, useRef, useState} from "react" +import {rainfallGraphData} from "../../types" +import {init, getInstanceByDom} from 'echarts' +import type {ECharts } from "echarts" + +const RainFallEcharts: FC = ({width, height, data, loading}) => { + + // https://dev.to/manufac/using-apache-echarts-with-react-and-typescript-353k + const chartRef = useRef(null) + const [option, setOption] = useState({ + tooltip: { + trigger: 'axis', + axisPointer: { + type: 'shadow' + } + }, + grid: { + left: '3%', + right: '4%', + bottom: '3%', + containLabel: true + }, + label: { + show: true, + }, + xAxis: [ + { + type: 'category', + data: data.map(d => d.label), + axisTick: { + alignWithLabel: true + } + } + ], + yAxis: [ + { + type: 'value' + } + ], + series: [ + { + name: 'Pluviométrie', + type: 'bar', + color: ['steelblue'], + barWidth: '80%', + data: data.map(d => d.value) + } + ] + }) + + useEffect(() => { + let chart: ECharts | undefined + console.log('in', width, height) + if (chartRef.current !== null) { + chart = init(chartRef.current) + } + + function resizeChart() { + chart?.resize() + } + window.addEventListener("resize", resizeChart) + + return () => { + chart?.dispose() + window.removeEventListener("resize", resizeChart) + } + }, []) + + useEffect(() => { + console.log('data') + if (chartRef.current !== null) { + console.log('data', data) + const chart = getInstanceByDom(chartRef.current) + chart?.setOption(option) + } + }, [option, data]) + + useEffect(() => { + setOption({...option, + xAxis: [ + { + type: 'category', + data: data.map(d => d.label), + axisTick: { + alignWithLabel: true + } + } + ], + series: [ + { + name: 'Pluviométrie', + type: 'bar', + color: ['steelblue'], + barWidth: '80%', + data: data.map(d => d.value) + } + ] + }) + }, [data]) + + useEffect(() => { + if (chartRef.current !== null) { + const chart = getInstanceByDom(chartRef.current) + // eslint-disable-next-line @typescript-eslint/no-unused-expressions + loading === true ? chart?.showLoading() : chart?.hideLoading() + } + }, [loading]) + + return
+
+
+
+} + +export default RainFallEcharts + +interface RainFallEchartsProps { + width: number, + height: number, + data: rainfallGraphData[], + loading: boolean, +} diff --git a/resources/js/components/rainfall/RainfallGraph.tsx b/resources/js/components/rainfall/RainfallGraph.tsx index 077ce55..9e19c29 100644 --- a/resources/js/components/rainfall/RainfallGraph.tsx +++ b/resources/js/components/rainfall/RainfallGraph.tsx @@ -1,6 +1,6 @@ import * as d3 from "d3" -import React, {FC, LegacyRef, useEffect, useRef} from "react" -import {rainfall, rainfallGraphData} from "../../types"; +import React, {FC, useEffect, useRef} from "react" +import {rainfallGraphData} from "../../types" const RainfallGraph: FC = ({width, height, data, start_date, end_date}) => { @@ -50,7 +50,7 @@ const RainfallGraph: FC = ({width, height, data, start_date, .call(d3.axisBottom(x) .ticks(8) .tickFormat( - // @ts-ignore + // @ts-expect-error change time format d3.timeFormat("%d/%m/%Y") ) , 0) @@ -101,7 +101,7 @@ const RainfallGraph: FC = ({width, height, data, start_date, return
-
+
} diff --git a/resources/js/customPrototypes.ts b/resources/js/customPrototypes.ts index f013e05..4c2cbcc 100644 --- a/resources/js/customPrototypes.ts +++ b/resources/js/customPrototypes.ts @@ -1,5 +1,6 @@ const weekDays = ['dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi'] +// eslint-disable-next-line @typescript-eslint/no-unused-vars interface Date { getWeekDay(): string, toSQLDate(): string, diff --git a/resources/js/hooks/AuthUser.tsx b/resources/js/hooks/AuthUser.tsx index 54f7ca0..4898372 100644 --- a/resources/js/hooks/AuthUser.tsx +++ b/resources/js/hooks/AuthUser.tsx @@ -6,8 +6,8 @@ import React, { useContext, useEffect, useState -} from "react"; -import axios from "axios"; +} from "react" +import axios from "axios" const AuthUserContext = createContext(undefined) @@ -28,7 +28,7 @@ export const AuthUserProvider = ({children}: PropsWithChildren) => { const res = await axios.get('/api/user') setAuthUser(res.data) } catch (e) { - // @ts-ignore + // @ts-expect-error check axios response status if (e.response.status === 401) { console.info('no user login') if (window.location.pathname !== '/connexion') { @@ -44,7 +44,7 @@ export const AuthUserProvider = ({children}: PropsWithChildren) => { const logout = async () => { try { setLoadingAuthUser(false) - const res = await axios.delete('/api/logout') + await axios.delete('/api/logout') setAuthUser(null) window.location.replace('/') } catch (e) { diff --git a/resources/js/hooks/AxiosTools.tsx b/resources/js/hooks/AxiosTools.tsx index fe7e929..e0504de 100644 --- a/resources/js/hooks/AxiosTools.tsx +++ b/resources/js/hooks/AxiosTools.tsx @@ -1,29 +1,31 @@ -import {useState} from "react"; -import axios from "axios"; -import React from "react"; -import {cleanErrorsForm, displayFormErrors} from "../utilities/form"; +import {useState} from "react" +import axios, {AxiosError} from "axios" +import React from "react" +import {cleanErrorsForm, displayFormErrors, ValidationErrors} from "../utilities/form" const useAxiosTools = () => { const [loading, setLoading] = useState(false) - const [error, setError] = useState(null) + const [error, setError] = useState(null) const axiosGet = axios.get const axiosPost = axios.post const axiosPut = axios.put const axiosDelete = axios.delete - const errorCatch = (error: any) => { - if (error.response && error.response.status === 422) { - displayFormErrors(error) - } else { - setError(error.response?.data.message || error.message) + const errorCatch = (error: Error|AxiosError|unknown) => { + if (axios.isAxiosError(error)) { + (error.response?.status === 422) + ? displayFormErrors(error) + : setError(error.response?.data.message || error.message) + } else if (error instanceof Error) { + setError(error.message) } } const errorLabel = () => { - return error ?
{error}
: null + return error ?
{error}
: null } const cleanErrors = () => { diff --git a/resources/js/hooks/DimensionHook.tsx b/resources/js/hooks/DimensionHook.tsx index a60942c..a9e7ded 100644 --- a/resources/js/hooks/DimensionHook.tsx +++ b/resources/js/hooks/DimensionHook.tsx @@ -4,12 +4,13 @@ const useDimension = () => { const RESET_TIMEOUT = 300 let movement_timer: number|undefined = undefined - const targetRef = useRef() + const targetRef = useRef() const [dimensions, setDimensions] = useState({ width:0, height: 0 }) useEffect(() => { window.addEventListener('resize', ()=>{ clearInterval(movement_timer) + // @ts-expect-error setTimeout defined in var movement_timer = setTimeout(testDimensions, RESET_TIMEOUT) }) }) diff --git a/resources/js/pages/Auth/ForgotPassword.tsx b/resources/js/pages/Auth/ForgotPassword.tsx index 0134261..3bc79c9 100644 --- a/resources/js/pages/Auth/ForgotPassword.tsx +++ b/resources/js/pages/Auth/ForgotPassword.tsx @@ -1,9 +1,6 @@ -import React, {FormEvent, SyntheticEvent, useState} from "react" -import Field from "../../components/Field"; -import axios from "axios"; -import {useNavigate} from "react-router-dom"; -import useAuthUser from "../../hooks/AuthUser"; -import useAxiosTools from "../../hooks/AxiosTools"; +import React, {FormEvent, useState} from "react" +import Field from "../../components/Field" +import useAxiosTools from "../../hooks/AxiosTools" const ForgotPassword = () => { @@ -16,15 +13,15 @@ const ForgotPassword = () => { try { cleanErrors() await axiosGet('/sanctum/csrf-cookie') - const res = await axiosPost('/api/forgot', {email}) + await axiosPost('/api/forgot', {email}) setMessage(true) - } catch (e) { - errorCatch(e) + } catch (error) { + errorCatch(error) } } return
- +

Mot de passe oublié

{message &&

Un email vous a été envoyé pour modifier le mot de passe.

} @@ -37,7 +34,7 @@ const ForgotPassword = () => { value={email} onChange={event => setEmail(event.target.value)} autoFocus>Email - +
} diff --git a/resources/js/pages/Auth/Login.tsx b/resources/js/pages/Auth/Login.tsx index 4c3c80c..8ef075d 100644 --- a/resources/js/pages/Auth/Login.tsx +++ b/resources/js/pages/Auth/Login.tsx @@ -1,10 +1,9 @@ -import React, {FormEvent, SyntheticEvent, useState} from "react" -import Field from "../../components/Field"; -import axios from "axios"; -import {Link, useNavigate} from "react-router-dom"; -import useAuthUser from "../../hooks/AuthUser"; -import Card from "../../components/Card"; -import useAxiosTools from "../../hooks/AxiosTools"; +import React, {FormEvent, useState} from "react" +import Field from "../../components/Field" +import {Link, useNavigate} from "react-router-dom" +import useAuthUser from "../../hooks/AuthUser" +import Card from "../../components/Card" +import useAxiosTools from "../../hooks/AxiosTools" const Login = () => { @@ -22,15 +21,15 @@ const Login = () => { const res = await axiosPost('/api/login', {email, password}) setAuthUser(res.data.user) navigate('/') - } catch (e) { - errorCatch(e) + } catch (error) { + errorCatch(error) } } return
- +
-

+

Connexion

{errorLabel()} @@ -46,7 +45,7 @@ const Login = () => { placeholder="******" value={password} onChange={event => setPassword(event.target.value)}>Mot de passe - + Mot de passe oublié ?
diff --git a/resources/js/pages/Auth/Profile.tsx b/resources/js/pages/Auth/Profile.tsx index 3b7b6d6..76754ea 100644 --- a/resources/js/pages/Auth/Profile.tsx +++ b/resources/js/pages/Auth/Profile.tsx @@ -1,9 +1,9 @@ import React, {FormEvent, useState} from "react" import useAuthUser from "../../hooks/AuthUser" import PageLayout from "../../components/PageLayout" -import Card from "../../components/Card"; -import Field from "../../components/Field"; -import useAxiosTools from "../../hooks/AxiosTools"; +import Card from "../../components/Card" +import Field from "../../components/Field" +import useAxiosTools from "../../hooks/AxiosTools" const Profile = () => { @@ -18,8 +18,8 @@ const Profile = () => { try { const res = await axiosPost(`/api/locations`, {latitude, longitude}) setAuthUser(res.data) - } catch (e) { - errorCatch(e) + } catch (error) { + errorCatch(error) } } @@ -65,7 +65,7 @@ const Profile = () => { Longitude
- +
} diff --git a/resources/js/pages/Auth/Register.tsx b/resources/js/pages/Auth/Register.tsx index 5d8c71e..88ebe0f 100644 --- a/resources/js/pages/Auth/Register.tsx +++ b/resources/js/pages/Auth/Register.tsx @@ -1,8 +1,8 @@ -import React, {ChangeEvent, FormEvent, SyntheticEvent, useState} from "react" -import Field from "../../components/Field"; -import axios from "axios"; -import {useNavigate} from "react-router-dom"; -import Card from "../../components/Card"; +import React, {FormEvent, useState} from "react" +import Field from "../../components/Field" +import axios from "axios" +import {useNavigate} from "react-router-dom" +import Card from "../../components/Card" const Register = () => { @@ -15,18 +15,18 @@ const Register = () => { event.preventDefault() try { await axios.get('/sanctum/csrf-cookie') - const res = await axios.post('/api/register', {name, email, password}) + await axios.post('/api/register', {name, email, password}) navigate('/') - } catch (e) { - console.error(e) + } catch (error) { + console.error(error) } } return
- +
-

- S'inscrire +

+ S'inscrire

{ value={password} onChange={event => setPassword(event.target.value)} autoFocus>Mot de passe - +
diff --git a/resources/js/pages/Auth/Reset.tsx b/resources/js/pages/Auth/Reset.tsx index ce4283f..bfc2693 100644 --- a/resources/js/pages/Auth/Reset.tsx +++ b/resources/js/pages/Auth/Reset.tsx @@ -1,14 +1,12 @@ -import PageLayout from "../../components/PageLayout"; -import Field from "../../components/Field"; -import React, {FormEvent, useState} from "react"; -import {useNavigate, useParams} from "react-router-dom"; -import useAuthUser from "../../hooks/AuthUser"; -import axios from "axios"; -import useAxiosTools from "../../hooks/AxiosTools"; +import Field from "../../components/Field" +import React, {FormEvent, useState} from "react" +import {useNavigate, useParams} from "react-router-dom" +import useAuthUser from "../../hooks/AuthUser" +import useAxiosTools from "../../hooks/AxiosTools" const Reset = () => { - let {token} = useParams() + const {token} = useParams() const navigate = useNavigate() const {setAuthUser} = useAuthUser() const [email, setEmail] = useState('') @@ -24,13 +22,13 @@ const Reset = () => { const res = await axiosPost('/api/reset', {email, token, password, samePassword}) setAuthUser(res.data.user) navigate('/connexion') - } catch (e) { - errorCatch(e) + } catch (error) { + errorCatch(error) } } return
-
+

Modifier voter mot de passe

{errorLabel()} @@ -51,7 +49,7 @@ const Reset = () => { placeholder="******" value={samePassword} onChange={event => setSamePassword(event.target.value)}>Confirmation du mot de passe - +
} diff --git a/resources/js/pages/Rainfall.tsx b/resources/js/pages/Rainfall.tsx index 41a9e7a..a5576c9 100644 --- a/resources/js/pages/Rainfall.tsx +++ b/resources/js/pages/Rainfall.tsx @@ -1,12 +1,12 @@ import React, {useEffect, useState} from "react" -import PageLayout from "../components/PageLayout"; -import LastFiveMesure from "../components/rainfall/LastFiveMesure"; -import AddRainfall from "../components/rainfall/AddRainfall"; -import RainfallGraph from "../components/rainfall/RainfallGraph"; -import useAxiosTools from "../hooks/AxiosTools"; -import {rainfall, rainfallGraphData} from "../types"; -import Field from "../components/Field"; -import useDimension from "../hooks/DimensionHook"; +import PageLayout from "../components/PageLayout" +import LastFiveMesure from "../components/rainfall/LastFiveMesure" +import AddRainfall from "../components/rainfall/AddRainfall" +import useAxiosTools from "../hooks/AxiosTools" +import {rainfallGraphData} from "../types" +import Field from "../components/Field" +import useDimension from "../hooks/DimensionHook" +import RainFallEcharts from "../components/rainfall/RainFallEcharts" const Rainfall = () => { @@ -17,7 +17,7 @@ const Rainfall = () => { end_date: (new Date()).toSQLDate(), period: 'day', }) - const {errorCatch, errorLabel, axiosGet} = useAxiosTools() + const {loading, setLoading, errorCatch, errorLabel, axiosGet} = useAxiosTools() const {targetRef, dimensions} = useDimension() useEffect(() => { @@ -26,22 +26,25 @@ const Rainfall = () => { const fetchGraphData = async () => { try { + setLoading(true) const params = `start=${graphDetails.start_date}&end=${graphDetails.end_date}&period=${graphDetails.period}` const res = await axiosGet(`/api/rainfalls/graph?${params}`) setGraphData(res.data) } catch (error) { errorCatch(error) + } finally { + setLoading(false) } } return -
+
{errorLabel()} -
+ { value={graphDetails.end_date} onChange={e => setGraphDetails({...graphDetails, end_date: (new Date(e.target.value)).toSQLDate()})} />
-
-
- +
+ + {/**/}
} diff --git a/resources/js/pages/Rainfall/RainfallIndex.tsx b/resources/js/pages/Rainfall/RainfallIndex.tsx index 3ab7daf..a078a8b 100644 --- a/resources/js/pages/Rainfall/RainfallIndex.tsx +++ b/resources/js/pages/Rainfall/RainfallIndex.tsx @@ -1,7 +1,7 @@ -import React, {useEffect, useState} from "react"; -import PageLayout from "../../components/PageLayout"; -import useAxiosTools from "../../hooks/AxiosTools"; -import {rainfall} from "../../types"; +import React, {useEffect, useState} from "react" +import PageLayout from "../../components/PageLayout" +import useAxiosTools from "../../hooks/AxiosTools" +import {rainfall} from "../../types" const RainfallIndex = () => { @@ -24,13 +24,9 @@ const RainfallIndex = () => { } } - const handleEdit = (rainfall: rainfall) => { - console.log(rainfall) - } - const handleDelete = async (rainfall: rainfall) => { try { - const res = await axiosDelete(`/api/rainfalls/${rainfall.id}`) + await axiosDelete(`/api/rainfalls/${rainfall.id}`) setRainfalls(rainfalls.filter(r => r.id !== rainfall.id)) } catch (error) { errorCatch(error) @@ -39,7 +35,7 @@ const RainfallIndex = () => { return {errorLabel()} - +
diff --git a/resources/js/pages/Router.tsx b/resources/js/pages/Router.tsx index 1f30351..7855b26 100644 --- a/resources/js/pages/Router.tsx +++ b/resources/js/pages/Router.tsx @@ -8,14 +8,13 @@ const ForgotPassword = lazy(() => import('./Auth/ForgotPassword')) const Home = lazy(() => import('./Home')) const Login = lazy(() => import('./Auth/Login')) const Profile = lazy(() => import('./Auth/Profile')) -const Register = lazy(() => import('./Auth/Register')) const Reset = lazy(() => import('./Auth/Reset')) const Rainfall = lazy(() => import('./Rainfall')) const RainfallIndex = lazy(() => import('./Rainfall/RainfallIndex')) const Router = () => { - const {authUser, loadingAuthUser, logout} = useAuthUser() + const {loadingAuthUser} = useAuthUser() return <> {loadingAuthUser ? '...loading' diff --git a/resources/js/pages/Weather.tsx b/resources/js/pages/Weather.tsx index 81aaaaf..ebfeefd 100644 --- a/resources/js/pages/Weather.tsx +++ b/resources/js/pages/Weather.tsx @@ -9,7 +9,6 @@ const Weather = () => { const [currentWeather, setCurrentWeather] = useState(null) const [fetchTime, setFetchTime] = useState(0) - const [count, setCount] = useState(0) const [weatherDays, setWeatherDays] = useState<[string, WeatherValue[]][]|null>(null) const {loading, setLoading, errorLabel, errorCatch, cleanErrors, axiosGet} = useAxiosTools() @@ -31,9 +30,9 @@ const Weather = () => { const res = await axiosGet(`/api/weather`) const currentWeather = res.data.list[0] - let weatherDays: [string, WeatherValue[]][] = [] + const weatherDays: [string, WeatherValue[]][] = [] let objectEntries = {index: -1, date: ''} - res.data.list.forEach((item: WeatherValue, index: number) => { + res.data.list.forEach((item: WeatherValue) => { const date = item.dt_txt.split(' ')[0] if (date === (new Date).toSQLDate()) { @@ -70,7 +69,7 @@ const Weather = () => { {errorLabel()} -
+
{currentWeather?.main.temp.toFixed()} °C {currentWeather?.weather[0].description}
@@ -81,9 +80,9 @@ const Weather = () => { {currentWeather && {currentWeather?.weather[0].main}}
-
- {currentWeather?.main.temp_max.toFixed()} °C - {currentWeather?.main.temp_min.toFixed()} °C +
+ {currentWeather?.main.temp_max.toFixed()} °C + {currentWeather?.main.temp_min.toFixed()} °C
@@ -108,7 +107,7 @@ const WeatherCard: FC<{date: string, values: WeatherValue[]}> = ({date, values= icon: '', description: '', } - const result: {[k: string]: number} = {} + const result: Record = {} values.forEach(value => { if (value.main.temp_min < weatherState.min) { weatherState.min = value.main.temp_min @@ -144,17 +143,17 @@ const WeatherCard: FC<{date: string, values: WeatherValue[]}> = ({date, values= }, []) return
-
- {(new Date(date)).getWeekDay()} +
+ {(new Date(date)).getWeekDay()} {weatherState?.description}
-
+
{weatherState?.main
-
+
{weatherState?.max.toFixed()} °C {weatherState?.min.toFixed()} °C
diff --git a/resources/js/types.ts b/resources/js/types.ts index 90fbb97..32798eb 100644 --- a/resources/js/types.ts +++ b/resources/js/types.ts @@ -38,7 +38,3 @@ export interface WeatherTime { icon: string, main: 'Rain', } - -export interface WeatherCompilation { - [k: string]: WeatherValue[] -} diff --git a/resources/js/utilities/form.ts b/resources/js/utilities/form.ts index 7fbd562..8259717 100644 --- a/resources/js/utilities/form.ts +++ b/resources/js/utilities/form.ts @@ -1,14 +1,27 @@ +import {AxiosError} from "axios" -export function displayFormErrors(error: any, form: HTMLElement|null = null) { +export function displayFormErrors(error: AxiosError, form: HTMLElement|null = null) { if (error.response && error.response.status === 422) { - let errors = error.response.data.errors + // @ts-expect-error test axios error + const errors = error.response.data.errors const formBase = (form) ? form : document.body - Object.keys(errors).forEach(key => { - displayError(key, errors[key], formBase) + Object.entries(errors).forEach(([key, value]) => { + displayError(key, value, formBase) }) } } +export interface ValidationErrors { + response: { + status: number, + data: { + errors: object + message?: string, + } + }, + message?: string, +} + export function displayError(key: string, message: string, form: HTMLElement|null = null) { const formBase = (form) ? form : document const input = formBase.querySelector(`input[name="${key}"], select[name="${key}"], textarea[name="${key}"]`)
Date