diff --git a/global.d.ts b/global.d.ts new file mode 100644 index 0000000..02f8d6c --- /dev/null +++ b/global.d.ts @@ -0,0 +1,7 @@ +/// + +declare module "*.module.css" { + const classes: { readonly [key: string]: string }; + export default classes; +} +// permet à TS de reconnaître les fichiers modules.css diff --git a/package-lock.json b/package-lock.json index 4e66827..b742c04 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,8 +30,9 @@ "@storybook/addon-docs": "^10.0.6", "@storybook/addon-vitest": "^10.0.6", "@storybook/react-vite": "^10.0.6", - "@types/react": "^19.1.16", - "@types/react-dom": "^19.1.9", + "@types/node": "^25.0.10", + "@types/react": "^19.2.10", + "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^5.0.4", "@vitest/browser-playwright": "^4.0.8", "@vitest/coverage-v8": "^4.0.8", @@ -44,6 +45,7 @@ "playwright": "^1.56.1", "prop-types": "^15.8.1", "storybook": "^10.0.6", + "typescript": "^5.9.3", "vite": "^7.1.7", "vitest": "^4.0.8" } @@ -1743,6 +1745,16 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/node": { + "version": "25.0.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.10.tgz", + "integrity": "sha512-zWW5KPngR/yvakJgGOmZ5vTBemDoSqF3AcV/LrO5u5wTWyEAVVh+IT39G4gtyAkh3CtTZs8aX/yRM82OfzHJRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, "node_modules/@types/parse-json": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", @@ -1756,18 +1768,18 @@ "license": "MIT" }, "node_modules/@types/react": { - "version": "19.2.2", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz", - "integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==", + "version": "19.2.10", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.10.tgz", + "integrity": "sha512-WPigyYuGhgZ/cTPRXB2EwUw+XvsRA3GqHlsP4qteqrnnjDrApbS7MxcGr/hke5iUoeB7E/gQtrs9I37zAJ0Vjw==", "license": "MIT", "dependencies": { - "csstype": "^3.0.2" + "csstype": "^3.2.2" } }, "node_modules/@types/react-dom": { - "version": "19.2.2", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.2.tgz", - "integrity": "sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==", + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "dev": true, "license": "MIT", "peerDependencies": { @@ -2718,9 +2730,9 @@ "license": "MIT" }, "node_modules/csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", "license": "MIT" }, "node_modules/debug": { @@ -5335,7 +5347,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -5359,6 +5370,13 @@ "react": ">=15.0.0" } }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true, + "license": "MIT" + }, "node_modules/universalify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", diff --git a/package.json b/package.json index 02da846..5e98da4 100644 --- a/package.json +++ b/package.json @@ -35,8 +35,9 @@ "@storybook/addon-docs": "^10.0.6", "@storybook/addon-vitest": "^10.0.6", "@storybook/react-vite": "^10.0.6", - "@types/react": "^19.1.16", - "@types/react-dom": "^19.1.9", + "@types/node": "^25.0.10", + "@types/react": "^19.2.10", + "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^5.0.4", "@vitest/browser-playwright": "^4.0.8", "@vitest/coverage-v8": "^4.0.8", @@ -49,6 +50,7 @@ "playwright": "^1.56.1", "prop-types": "^15.8.1", "storybook": "^10.0.6", + "typescript": "^5.9.3", "vite": "^7.1.7", "vitest": "^4.0.8" } diff --git a/src/contexts/auth/AuthContext.js b/src/contexts/auth/AuthContext.js deleted file mode 100644 index 885fd0e..0000000 --- a/src/contexts/auth/AuthContext.js +++ /dev/null @@ -1,3 +0,0 @@ -import { createContext } from "react"; - -export const AuthContext = createContext(null); diff --git a/src/contexts/auth/AuthContext.ts b/src/contexts/auth/AuthContext.ts new file mode 100644 index 0000000..03e6786 --- /dev/null +++ b/src/contexts/auth/AuthContext.ts @@ -0,0 +1,27 @@ +import { createContext } from "react"; + + +export interface Task { + id: number; + title?: string; + completed?: boolean; + [key: string]: unknown; +} + +export interface User { + name: string; + lastname: string; + role: string; + email: string; + phone: string | null; + created_at: string; + tasks: Task[]; +} + +export interface AuthContextType { + user: User | null; + update: () => void; +} + +export const AuthContext = createContext(null); + diff --git a/src/pages/Profile/ProfilePage.jsx b/src/pages/Profile/ProfilePage.jsx deleted file mode 100644 index 101120d..0000000 --- a/src/pages/Profile/ProfilePage.jsx +++ /dev/null @@ -1,61 +0,0 @@ -import React, { useContext, useEffect } from "react"; -import styles from "./ProfilePage.module.css"; -import { AuthContext } from "../../contexts/auth/AuthContext.js"; -import formatDate from "../../utils/date/formatDate.js"; -import Task from "../../components/Task/Task"; -import SettingsModal from "./components/SettingsModal/SettingsModal.jsx"; - -function ProfilePage() { - - const { user, update } = useContext(AuthContext); - - useEffect(() => { - update(); - }, []) - - return ( -
-
-
-
- Photo de profil -
-
-
-

{user?.name} {user?.lastname}

-
-
-
-

Role : {user?.role}

-

Membre depuis : {user && formatDate(user.created_at)}

-
-
-

Mail : {user?.email}

-

Téléphone : {user?.phone === null ? "Pas de numéro enregistré" : user?.phone}

-
-
- -
-
- -

Tâches :

- {user && user.tasks.length > 0 ? ( - user.tasks.map((task, index) => ( - - )) - ) : ( -

Aucune tâche pour le moment.

- )} - -
-
-
-
- ); -} - -export default ProfilePage; diff --git a/src/pages/Profile/ProfilePage.tsx b/src/pages/Profile/ProfilePage.tsx new file mode 100644 index 0000000..2c4ec78 --- /dev/null +++ b/src/pages/Profile/ProfilePage.tsx @@ -0,0 +1,165 @@ +import { useContext, useEffect } from "react"; +import styles from "./ProfilePage.module.css"; + +import { AuthContext } from "../../contexts/auth/AuthContext"; +import formatDate from "../../utils/date/formatDate"; + +//import Task from "../../components/Task/Task"; +//import SettingsModal from "./components/SettingsModal/SettingsModal"; + +interface TaskType { + id: number; + title?: string; + completed?: boolean; + [key: string]: unknown; +} + +interface User { + name: string; + lastname: string; + role: string; + email: string; + phone: string | null; + created_at: string; + tasks: TaskType[]; +} + +interface AuthContextType { + user: User | null; + update: () => void; +} + + + +function ProfilePage(){ + const { user, update } = useContext(AuthContext) as AuthContextType; + + useEffect(() => { + update(); + }, [update]); + + return ( +
+
+
+
+ Photo de profil +
+ +
+
+

+ {user?.name} {user?.lastname} +

+
+ +
+
+

+ Role : {user?.role} +

+

+ Membre depuis :{" "} + {user && formatDate(user.created_at)} +

+
+ +
+

+ Mail : {user?.email} +

+

+ Téléphone :{" "} + {user?.phone ?? "Pas de numéro enregistré"} +

+
+ +
+ {/* */} +
+
+ +

Tâches :

+ + {/* {user && user.tasks.length > 0 ? ( + user.tasks.map((task) => ( + + )) + ) : ( +

Aucune tâche pour le moment.

+ )}*/} +
+
+
+
+ ); +} + +export default ProfilePage; + + +/*import React, { useContext, useEffect } from "react"; +import styles from "./ProfilePage.module.css"; +import { AuthContext } from "../../contexts/auth/AuthContext.js"; +import formatDate from "../../utils/date/formatDate.js"; +import Task from "../../components/Task/Task"; +import SettingsModal from "./components/SettingsModal/SettingsModal.jsx"; + +function ProfilePage() { + + const { user, update } = useContext(AuthContext); + + useEffect(() => { + update(); + }, []) + + return ( +
+
+
+
+ Photo de profil +
+
+
+

{user?.name} {user?.lastname}

+
+
+
+

Role : {user?.role}

+

Membre depuis : {user && formatDate(user.created_at)}

+
+
+

Mail : {user?.email}

+

Téléphone : {user?.phone === null ? "Pas de numéro enregistré" : user?.phone}

+
+
+ +
+
+ +

Tâches :

+ {user && user.tasks.length > 0 ? ( + user.tasks.map((task, index) => ( + + )) + ) : ( +

Aucune tâche pour le moment.

+ )} + +
+
+
+
+ ); +} + +export default ProfilePage;*/ \ No newline at end of file diff --git a/src/utils/date/formatDate.js b/src/utils/date/formatDate.js deleted file mode 100644 index 3fd1371..0000000 --- a/src/utils/date/formatDate.js +++ /dev/null @@ -1,9 +0,0 @@ -export default function formatDate(d) { - const date = new Date(d); - - const jj = String(date.getUTCDate()).padStart(2, '0'); - const mm = String(date.getUTCMonth() + 1).padStart(2, '0'); - const aaaa = date.getUTCFullYear(); - - return `${jj}/${mm}/${aaaa}`; -} \ No newline at end of file diff --git a/src/utils/date/formatDate.ts b/src/utils/date/formatDate.ts new file mode 100644 index 0000000..5a14daa --- /dev/null +++ b/src/utils/date/formatDate.ts @@ -0,0 +1,9 @@ +export default function formatDate(d: string | Date): string { + const date = d instanceof Date ? d : new Date(d); + + const jj = String(date.getUTCDate()).padStart(2, "0"); + const mm = String(date.getUTCMonth() + 1).padStart(2, "0"); + const aaaa = date.getUTCFullYear(); + + return `${jj}/${mm}/${aaaa}`; +} diff --git a/src/utils/date/formatDateLetter.js b/src/utils/date/formatDateLetter.js deleted file mode 100644 index 883b3c8..0000000 --- a/src/utils/date/formatDateLetter.js +++ /dev/null @@ -1,32 +0,0 @@ - - -export function formatDateLetter(d) { - if (!d) return "Date inconnue"; - - const dateObj = new Date(d); - if (isNaN(dateObj.getTime())) return "Date invalide"; - - const monthNames = [ - "Janvier", "Février", "Mars", "Avril", "Mai", "Juin", - "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre" - ]; - - const day = dateObj.getDate().toString().padStart(2, "0"); - const month = monthNames[dateObj.getMonth()]; - const year = dateObj.getFullYear(); - const hours = dateObj.getHours().toString().padStart(2, "0"); - const minutes = dateObj.getMinutes().toString().padStart(2, "0"); - - return `${day} ${month} ${year} à ${hours}:${minutes}`; -} - - -export function formatDateLetterJS(d) { - const monthNames = [ - "Janvier", "Février", "Mars", "Avril", "Mai", "Juin", - "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre" - ]; - const [year, month, day] = d.split('-'); - return `${day} ${monthNames[parseInt(month) - 1]} ${year}`; -} - diff --git a/src/utils/date/formatDateLetter.ts b/src/utils/date/formatDateLetter.ts new file mode 100644 index 0000000..f4c3f91 --- /dev/null +++ b/src/utils/date/formatDateLetter.ts @@ -0,0 +1,65 @@ + + +/*export function formatDateLetter(d) { + if (!d) return "Date inconnue"; + + const dateObj = new Date(d); + if (isNaN(dateObj.getTime())) return "Date invalide"; + + const monthNames = [ + "Janvier", "Février", "Mars", "Avril", "Mai", "Juin", + "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre" + ]; + + const day = dateObj.getDate().toString().padStart(2, "0"); + const month = monthNames[dateObj.getMonth()]; + const year = dateObj.getFullYear(); + const hours = dateObj.getHours().toString().padStart(2, "0"); + const minutes = dateObj.getMinutes().toString().padStart(2, "0"); + + return `${day} ${month} ${year} à ${hours}:${minutes}`; +} + + +export function formatDateLetterJS(d) { + const monthNames = [ + "Janvier", "Février", "Mars", "Avril", "Mai", "Juin", + "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre" + ]; + const [year, month, day] = d.split('-'); + return `${day} ${monthNames[parseInt(month) - 1]} ${year}`; +}*/ + +export function formatDateLetter(d: string | Date | null | undefined): string { + if (!d) return "Date inconnue"; + + const dateObj = d instanceof Date ? d : new Date(d); + if (isNaN(dateObj.getTime())) return "Date invalide"; + + const monthNames = [ + "Janvier", "Février", "Mars", "Avril", "Mai", "Juin", + "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre" + ]; + + const day = dateObj.getDate().toString().padStart(2, "0"); + const month = monthNames[dateObj.getMonth()]; + const year = dateObj.getFullYear(); + const hours = dateObj.getHours().toString().padStart(2, "0"); + const minutes = dateObj.getMinutes().toString().padStart(2, "0"); + + return `${day} ${month} ${year} à ${hours}:${minutes}`; +} + + +export function formatDateLetterJS(d: string): string { + const monthNames = [ + "Janvier", "Février", "Mars", "Avril", "Mai", "Juin", + "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre" + ]; + + const [year, month, day] = d.split("-"); + if (!year || !month || !day) return "Date invalide"; + + return `${day} ${monthNames[parseInt(month, 10) - 1]} ${year}`; +} + diff --git a/src/utils/date/formatTime.js b/src/utils/date/formatTime.js deleted file mode 100644 index 6012db2..0000000 --- a/src/utils/date/formatTime.js +++ /dev/null @@ -1,8 +0,0 @@ -export default function formatTime(d) { - const date = new Date(d); - - const hh = String(date.getUTCHours()).padStart(2, '0'); - const min = String(date.getUTCMinutes()).padStart(2, '0'); - - return `${hh}:${min}`; -} \ No newline at end of file diff --git a/src/utils/date/formatTime.ts b/src/utils/date/formatTime.ts new file mode 100644 index 0000000..93311b9 --- /dev/null +++ b/src/utils/date/formatTime.ts @@ -0,0 +1,12 @@ + +export default function formatTime(d: string | Date | null | undefined): string { + if (!d) return "Heure inconnue"; + + const date = d instanceof Date ? d : new Date(d); + if (isNaN(date.getTime())) return "Heure invalide"; + + const hh = String(date.getUTCHours()).padStart(2, "0"); + const min = String(date.getUTCMinutes()).padStart(2, "0"); + + return `${hh}:${min}`; +} diff --git a/src/utils/events/createEvent.js b/src/utils/events/createEvent.js index ba073fe..764d419 100644 --- a/src/utils/events/createEvent.js +++ b/src/utils/events/createEvent.js @@ -11,3 +11,4 @@ export default async function createEvent(name, description, start, end) { {"X-XSRF-TOKEN": csrfToken} ); } + diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..693c67f --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,62 @@ +{ + // Visit https://aka.ms/tsconfig to read more about this file + /*"compilerOptions": {*/ + // File Layout + // "rootDir": "./src", + // "outDir": "./dist", + + // Environment Settings + // See also https://aka.ms/tsconfig/module + /*"module": "nodenext", + "target": "esnext", + "types": [],*/ + // For nodejs: + // "lib": ["esnext"], + // "types": ["node"], + // and npm install -D @types/node + + // Other Outputs + /*"sourceMap": true, + "declaration": true, + "declarationMap": true,*/ + + // Stricter Typechecking Options + /*"noUncheckedIndexedAccess": true, + "exactOptionalPropertyTypes": true,*/ + + // Style Options + // "noImplicitReturns": true, + // "noImplicitOverride": true, + // "noUnusedLocals": true, + // "noUnusedParameters": true, + // "noFallthroughCasesInSwitch": true, + // "noPropertyAccessFromIndexSignature": true, + + // Recommended Options + /* "strict": true, + "jsx": "react-jsx", + "verbatimModuleSyntax": true, + "isolatedModules": true, + "noUncheckedSideEffectImports": true, + "moduleDetection": "force", + "skipLibCheck": true, + } +} + +{*/ + "compilerOptions": { + "target": "ESNext", + "lib": ["DOM", "DOM.Iterable", "ESNext"], + "module": "ESNext", + "moduleResolution": "bundler", + "jsx": "react-jsx", + "strict": true, + "isolatedModules": true, + + "noUncheckedIndexedAccess": true, + "exactOptionalPropertyTypes": true, + + "resolveJsonModule": true, + "skipLibCheck": true + } +}