+
+
+

+
- setProfileUser(res.data);
- } else {
- setProfileUser(user)
- }
- })()
- }, [user, id]);
-
- return (
-
-
-
-
-

-
-
-
-
-
- {profileUser?.name} {profileUser?.lastname}
-
- {(user?.isAdmin && profileUser && !isOwnProfile) && (
-
- )}
-
-
-
-
-
- Role : {profileUser?.role}
-
-
- Membre depuis :{" "}
- {profileUser && formatDate(profileUser.created_at)}
-
-
-
-
-
- Mail : {profileUser?.email}
-
-
- Téléphone :{" "}
- {profileUser?.phone ?? "Pas de numéro enregistré"}
-
-
-
- {isOwnProfile && (
-
-
-
- )}
-
-
-
Tâches :
-
- {profileUser && profileUser.tasks.length > 0 ? (
- profileUser.tasks.map((task) => (
-
- ))
- ) : (
- Aucune tâche pour le moment.
- )}
-
-
+ {isOwnProfile && (
+
+
+ {user?.profile_photo_path && (
+
+ )}
+ )}
+
+
+ {error &&
{error}
}
+ {success &&
{success}
}
+
+
+
+
+ {profileUser?.name} {profileUser?.lastname}
+
+ {user?.isAdmin && profileUser && !isOwnProfile && (
+
+ )}
+
+
+
+
+
Role : {profileUser?.role}
+
Membre depuis : {profileUser && formatDate(profileUser.created_at)}
+
+
+
+
Mail : {profileUser?.email}
+
Téléphone : {profileUser?.phone ?? "Non renseigné"}
+
+
+ {isOwnProfile && (
+
+
+
+ )}
+
+
+
Tâches :
+ {profileUser?.tasks.length ? (
+ profileUser.tasks.map((task) =>
)
+ ) : (
+
Aucune tâche.
+ )}
+
- );
+
+
+ );
}
export default ProfilePage;
\ No newline at end of file
diff --git a/src/pages/Profile/components/SettingsModal/SettingsModal.tsx b/src/pages/Profile/components/SettingsModal/SettingsModal.tsx
index fa6701f..e028735 100644
--- a/src/pages/Profile/components/SettingsModal/SettingsModal.tsx
+++ b/src/pages/Profile/components/SettingsModal/SettingsModal.tsx
@@ -164,4 +164,4 @@ export default function SettingsModal() {
>
);
-}
\ No newline at end of file
+}
diff --git a/src/utils/fetchWrapper.js b/src/utils/fetchWrapper.js
deleted file mode 100644
index aa9f0a0..0000000
--- a/src/utils/fetchWrapper.js
+++ /dev/null
@@ -1,45 +0,0 @@
-export default async function fetchWrapper(
- path,
- data = null,
- method = "GET",
- headers = {}
-) {
- try {
- const res = await fetch(
- `${import.meta.env.VITE_API_URL}${path}`,
- {
- method,
- credentials: "include",
- headers: {
- "Accept": "application/json",
- "Content-Type": "application/json",
- ...headers,
- },
- body: data ? JSON.stringify(data) : null,
- }
- );
-
- let responseData = null;
-
- try {
- responseData = await res.json();
- } catch (_) {
- responseData = null;
- }
-
- return {
- status: res.status,
- data: responseData,
- };
-
- } catch (err) {
- console.error("❌ Erreur réseau :", err);
-
- return {
- status: 0,
- data: {
- message: "Network error",
- },
- };
- }
-}
diff --git a/src/utils/fetchWrapper.ts b/src/utils/fetchWrapper.ts
new file mode 100644
index 0000000..a130373
--- /dev/null
+++ b/src/utils/fetchWrapper.ts
@@ -0,0 +1,92 @@
+/*export default async function fetchWrapper(path,data = null,method = "GET",headers = {}) {
+ try {
+ const res = await fetch(
+ `${import.meta.env.VITE_API_URL}${path}`,
+ {
+ method,
+ credentials: "include",
+ headers: {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ ...headers,
+ },
+ body: data ? JSON.stringify(data) : null,
+ }
+ );
+
+ let responseData = null;
+
+ try {
+ responseData = await res.json();
+ } catch (_) {
+ responseData = null;
+ }
+
+ return {
+ status: res.status,
+ data: responseData,
+ };
+
+ } catch (err) {
+ console.error("❌ Erreur réseau :", err);
+
+ return {
+ status: 0,
+ data: {
+ message: "Network error",
+ },
+ };
+ }
+}*/
+
+interface FetchResponse
{
+ status: number;
+ data: T | null;
+}
+
+export default async function fetchWrapper(
+ path: string,
+ data: any = null,
+ method: string = "GET",
+ headers: Record = {}
+): Promise {
+ try {
+ const res = await fetch(
+ `${import.meta.env.VITE_API_URL}${path}`,
+ {
+ method,
+ credentials: "include",
+ headers: {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ ...headers,
+ },
+ body: data ? JSON.stringify(data) : null,
+ }
+ );
+
+ let responseData = null;
+
+ try {
+ responseData = await res.json();
+ } catch (_) {
+ responseData = null;
+ }
+
+ return {
+ status: res.status,
+ data: responseData,
+ };
+
+ } catch (err) {
+ console.error("❌ Erreur réseau :", err);
+
+ return {
+ status: 0,
+ data: {
+ message: "Network error",
+ },
+ };
+ }
+}
+
diff --git a/src/utils/getXSRF.js b/src/utils/getXSRF.js
deleted file mode 100644
index f1dc5fc..0000000
--- a/src/utils/getXSRF.js
+++ /dev/null
@@ -1,19 +0,0 @@
-export default async function getXSRFToken() {
- const response = await fetch(`${import.meta.env.VITE_API_URL}/sanctum/csrf-cookie`, {
- method: 'GET',
- credentials: 'include'
- });
-
- if (!response.ok && response.status !== 204) {
- throw new Error(`Error : ${response.status}`);
- }
-
- const name = 'XSRF-TOKEN';
- const value = `; ${document.cookie}`;
- const parts = value.split(`; ${name}=`);
- if (parts.length === 2) {
- return decodeURIComponent(parts.pop().split(';').shift());
- }
-
- throw new Error('Error: Invalid XSRF-TOKEN');
-}
diff --git a/src/utils/getXSRF.ts b/src/utils/getXSRF.ts
new file mode 100644
index 0000000..f96606d
--- /dev/null
+++ b/src/utils/getXSRF.ts
@@ -0,0 +1,40 @@
+/*export default async function getXSRFToken() {
+ const response = await fetch(`${import.meta.env.VITE_API_URL}/sanctum/csrf-cookie`, {
+ method: 'GET',
+ credentials: 'include'
+ });
+
+ if (!response.ok && response.status !== 204) {
+ throw new Error(`Error : ${response.status}`);
+ }
+
+ const name = 'XSRF-TOKEN';
+ const value = `; ${document.cookie}`;
+ const parts = value.split(`; ${name}=`);
+ if (parts.length === 2) {
+ return decodeURIComponent(parts.pop().split(';').shift());
+ }
+
+ throw new Error('Error: Invalid XSRF-TOKEN');
+}*/
+
+export default async function getXSRFToken(): Promise {
+ const response = await fetch(`${import.meta.env.VITE_API_URL}/sanctum/csrf-cookie`, {
+ method: 'GET',
+ credentials: 'include'
+ });
+
+ if (!response.ok && response.status !== 204) {
+ throw new Error(`Error : ${response.status}`);
+ }
+
+ const name = 'XSRF-TOKEN';
+ const value = `; ${document.cookie}`;
+ const parts = value.split(`; ${name}=`);
+ if (parts.length === 2) {
+ return decodeURIComponent(parts.pop()!.split(';').shift()!);
+ }
+
+ throw new Error('Error: Invalid XSRF-TOKEN');
+}
+
diff --git a/src/utils/users/deleteProfilePhoto.ts b/src/utils/users/deleteProfilePhoto.ts
new file mode 100644
index 0000000..d0ca642
--- /dev/null
+++ b/src/utils/users/deleteProfilePhoto.ts
@@ -0,0 +1,10 @@
+import fetchWrapper from "../fetchWrapper";
+
+export default async function deleteProfilePhoto(): Promise<{ status: number; ok: boolean; data?: any; error?: string }> {
+ try {
+ const response = await fetchWrapper("/api/profile-photo", null, "DELETE");
+ return { status: response.status || 0, ok: response.status >= 200 && response.status < 300, data: response.data };
+ } catch (err: any) {
+ return { status: 0, ok: false, error: err?.message || "Network error" };
+ }
+}
diff --git a/src/utils/users/deleteUser.js b/src/utils/users/deleteUser.js
deleted file mode 100644
index 4cb9dcf..0000000
--- a/src/utils/users/deleteUser.js
+++ /dev/null
@@ -1,13 +0,0 @@
-import fetchWrapper from "../fetchWrapper.js";
-import getXSRFToken from "../getXSRF.js";
-
-export default async function deleteUser() {
- const csrfToken = await getXSRFToken();
-
- return fetchWrapper(
- "/api/users",
- null,
- "DELETE",
- { "X-XSRF-TOKEN": csrfToken }
- );
-}
diff --git a/src/utils/users/deleteUser.ts b/src/utils/users/deleteUser.ts
new file mode 100644
index 0000000..193e5b0
--- /dev/null
+++ b/src/utils/users/deleteUser.ts
@@ -0,0 +1,13 @@
+import fetchWrapper from "../fetchWrapper";
+import getXSRFToken from "../getXSRF";
+
+export default async function deleteUser(): Promise<{status: number;data: any;}> {
+ const csrfToken: string = await getXSRFToken();
+
+ return fetchWrapper(
+ "/api/users",
+ null,
+ "DELETE",
+ { "X-XSRF-TOKEN": csrfToken }
+ );
+}
diff --git a/src/utils/users/replaceProfilePhoto.ts b/src/utils/users/replaceProfilePhoto.ts
new file mode 100644
index 0000000..92569eb
--- /dev/null
+++ b/src/utils/users/replaceProfilePhoto.ts
@@ -0,0 +1,5 @@
+import uploadProfilePhoto from "./uploadProfilePhoto";
+
+export default async function replaceProfilePhoto(file: File) {
+ return uploadProfilePhoto(file);
+}
diff --git a/src/utils/users/updateUser.js b/src/utils/users/updateUser.js
deleted file mode 100644
index af18273..0000000
--- a/src/utils/users/updateUser.js
+++ /dev/null
@@ -1,13 +0,0 @@
-import fetchWrapper from "../fetchWrapper.js";
-import getXSRFToken from "../getXSRF.js";
-
-export default async function updateUser(name, lastname, phone) {
- const csrfToken = await getXSRFToken();
-
- return fetchWrapper(
- "/api/users/update",
- { name, lastname, phone },
- "POST",
- { "X-XSRF-TOKEN": csrfToken }
- );
-}
diff --git a/src/utils/users/updateUser.ts b/src/utils/users/updateUser.ts
new file mode 100644
index 0000000..6714250
--- /dev/null
+++ b/src/utils/users/updateUser.ts
@@ -0,0 +1,33 @@
+/*import fetchWrapper from "../fetchWrapper.js";
+import getXSRFToken from "../getXSRF.js";
+
+export default async function updateUser(name, lastname, phone) {
+ const csrfToken = await getXSRFToken();
+
+ return fetchWrapper(
+ "/api/users/update",
+ { name, lastname, phone },
+ "POST",
+ { "X-XSRF-TOKEN": csrfToken }
+ );
+}*/
+
+import fetchWrapper from "../fetchWrapper";
+import getXSRFToken from "../getXSRF";
+
+interface UserUpdateData {
+ name: string;
+ lastname: string;
+ phone: string | null;
+}
+
+interface RequestHeaders {
+ "X-XSRF-TOKEN": string;
+}
+export default async function updateUser(name: string,lastname: string,phone: string | null): Promise {
+ const csrfToken: string = await getXSRFToken();
+ const userData: UserUpdateData = {name,lastname,phone,};
+ const headers: RequestHeaders = {"X-XSRF-TOKEN": csrfToken,};
+ return fetchWrapper("/api/users/update",userData,"POST",headers);
+}
+
diff --git a/src/utils/users/uploadProfilePhoto.ts b/src/utils/users/uploadProfilePhoto.ts
new file mode 100644
index 0000000..ca252a2
--- /dev/null
+++ b/src/utils/users/uploadProfilePhoto.ts
@@ -0,0 +1,28 @@
+import getXSRFToken from "../getXSRF.js";
+
+export default async function uploadProfilePhoto(file: File): Promise<{ status: number; ok: boolean; data?: any; error?: string }> {
+ const formData = new FormData();
+ formData.append("photo", file);
+
+ try {
+ const csrfToken = await getXSRFToken();
+ const response = await fetch(`${import.meta.env.VITE_API_URL}/api/profile-photo`, {
+ method: "POST",
+ headers: { "X-XSRF-TOKEN": decodeURIComponent(csrfToken) },
+ credentials: "include",
+ body: formData,
+ });
+
+ const status = response.status;
+ let data = null;
+ try {
+ data = await response.json();
+ } catch (e) {
+ // no json
+ }
+
+ return { status, ok: response.ok, data };
+ } catch (err: any) {
+ return { status: 0, ok: false, error: err?.message || "Network error" };
+ }
+}
diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts
new file mode 100644
index 0000000..b67473e
--- /dev/null
+++ b/src/vite-env.d.ts
@@ -0,0 +1,6 @@
+///
+
+declare module "*.module.css" {
+ const classes: { [key: string]: string };
+ export default classes;
+}
diff --git a/tsconfig.json b/tsconfig.json
index 693c67f..3417353 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,49 +1,4 @@
{
- // 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"],
@@ -52,11 +7,13 @@
"jsx": "react-jsx",
"strict": true,
"isolatedModules": true,
-
- "noUncheckedIndexedAccess": true,
+ "noUncheckedIndexedAccess": false,
"exactOptionalPropertyTypes": true,
-
"resolveJsonModule": true,
- "skipLibCheck": true
- }
+ "skipLibCheck": true,
+ "allowJs": true,
+ "esModuleInterop": true
+ },
+ "include": ["src"]
+ // "exclude": ["**/*.js"]
}