-
Mot de passe institutionnel
-
Dernière modification : Il y a 43 jours
-
+ {!isLoading && !error && (
+
+
+ {/* MFA */}
+
+
+
Authentification (MFA)
+
Exigée par GISE
+
+
+
+
+ {/* MOT DE PASSE (Lien vers la sous-page) */}
+
+
Mot de passe institutionnel
+
Dernière modification : Il y a 43 jours
+
+
+
-
+ )}
);
}
+
export default AccessWidget;
\ No newline at end of file
diff --git a/src/components/widgets/InformationWidget.tsx b/src/components/widgets/InformationWidget.tsx
index ea59a71..514dbd8 100644
--- a/src/components/widgets/InformationWidget.tsx
+++ b/src/components/widgets/InformationWidget.tsx
@@ -1,7 +1,33 @@
import { Card, CardContent, CardHeader } from '@/components/ui/Card';
+import type { Company } from '@/types/Company';
+import type { User } from '@/types/User';
+import { Loader } from '@/components/ui/Loader';
import { Building } from "lucide-react";
-export function InformationWidget() {
+interface InformationWidgetProps {
+ user: User | null;
+ company: Company | null;
+ isLoading: boolean;
+ error: string | null;
+}
+
+function setVipBadge(vip_level: string | undefined) {
+ switch (vip_level?.toLowerCase()) {
+ case "platinum":
+ return
{vip_level?.toUpperCase()};
+ case "premium":
+ return
{vip_level?.toUpperCase()};
+ default:
+ return
{vip_level?.toUpperCase()};
+ }
+}
+
+export const InformationWidget: React.FC
= ({
+ user,
+ company,
+ isLoading,
+ error,
+}) => {
return (
@@ -11,25 +37,29 @@ export function InformationWidget() {
-
-
-
-
- Entité Légale
- - Cabinet Juridique Example & Associés
-
-
-
- Administrateur du compte
- - Direction Générale (direction@example.com)
-
-
-
- Niveau d'Infogérance (SLA)
- -
- VIP PLATINUM
- Couverture 24/7 (99.99%)
-
-
-
-
+ {isLoading && !error && }
+ {!isLoading && !error && (
+
+
+
+
- Entité Légale
+ - {company?.name}
+
+
+
- Administrateur du compte
+ - {user?.role} {user?.name}
+ - Email : {user?.emailVisibility && user?.email}{!user?.emailVisibility && "caché"}
+
+
+
- Niveau d'Infogérance (SLA)
+ -
+ {setVipBadge(company?.vip_level)}
+ Couverture 24/7 (99.99%)
+
+
+
+
+ )}
);
}
diff --git a/src/hooks/useDocumentDownload.ts b/src/hooks/useDocumentDownload.ts
index 9ea383e..c422e43 100644
--- a/src/hooks/useDocumentDownload.ts
+++ b/src/hooks/useDocumentDownload.ts
@@ -33,8 +33,7 @@ export function useDocumentDownload() {
link.click();
document.body.removeChild(link);
- } catch (err) {
- console.error("Erreur lors du téléchargement sécurisé :", err);
+ } catch {
setError("Accès refusé au coffre-fort documentaire.");
} finally {
setIsDownloading(false);
diff --git a/src/hooks/useUserInformations.ts b/src/hooks/useUserInformations.ts
new file mode 100644
index 0000000..1d037fd
--- /dev/null
+++ b/src/hooks/useUserInformations.ts
@@ -0,0 +1,30 @@
+import { pb } from "@/services/pocketbase";
+import type { Company } from "@/types/Company";
+import type { User } from "@/types/User";
+import { useEffect, useState } from "react";
+
+export const useUserInformations = () => {
+ const [user, setUser] = useState(null);
+ const [company, setCompany] = useState(null);
+ const [isLoading, setIsLoading] = useState(true);
+ const [error, setError] = useState(null);
+
+ useEffect(() => {
+ const fetchInformations = async () => {
+ setIsLoading(true);
+ try {
+ const userRecords = await pb.collection('aegis_users').getFullList();
+ setUser(userRecords[0]);
+ const companyRecords = await pb.collection('aegis_companies').getFullList();
+ setCompany(companyRecords[0])
+ } catch (err) {
+ setError("Erreur lors de la récupération des infos utilisateur :"+err);
+ } finally {
+ setIsLoading(false);
+ }
+ };
+ fetchInformations();
+ }, []);
+
+ return { user, company, isLoading, error };
+};
\ No newline at end of file
diff --git a/src/pages/AccountSettings.tsx b/src/pages/AccountSettings.tsx
index 3c196f3..9051e03 100644
--- a/src/pages/AccountSettings.tsx
+++ b/src/pages/AccountSettings.tsx
@@ -1,29 +1,33 @@
import PageHeader from "@/components/ui/PageHeader";
import AccessWidget from "@/components/widgets/AccessWidget";
import InformationWidget from "@/components/widgets/InformationWidget";
+import { useUserInformations } from "@/hooks/useUserInformations";
export default function AccountSettings() {
+ const { user, company, isLoading, error } = useUserInformations();
return (
-
-
{/* Contenu Principal */}
{/* Header */}
-
-
{/* Colonne 1 : Sécurité */}
-
-
+
{/* Colonne 2 : Organisation & Contrat */}
-
-
+
-
);
diff --git a/src/pages/accountsettings/UpdatePasswordPage.tsx b/src/pages/accountsettings/UpdatePasswordPage.tsx
new file mode 100644
index 0000000..e86ab99
--- /dev/null
+++ b/src/pages/accountsettings/UpdatePasswordPage.tsx
@@ -0,0 +1,145 @@
+import React, { useState } from 'react';
+import { useNavigate } from 'react-router-dom';
+import { KeyRound, AlertCircle, ShieldCheck } from "lucide-react";
+import { Card } from '@/components/ui/Card';
+import { Input } from '@/components/ui/Input';
+import { Button } from '@/components/ui/Button';
+import { pb } from '@/services/pocketbase';
+import BackButton from '@/components/ui/BackButton';
+import { NEUMORPHISM } from '@/styles/Neumorphism';
+
+export default function UpdatePasswordPage() {
+ const navigate = useNavigate();
+
+ const [isUpdating, setIsUpdating] = useState(false);
+ const [feedback, setFeedback] = useState<{ type: 'error' | 'success', message: string } | null>(null);
+
+ const [formData, setFormData] = useState({
+ oldPassword: '',
+ newPassword: '',
+ confirmPassword: ''
+ });
+
+ const handlePasswordChange = async (e: React.FormEvent) => {
+ e.preventDefault();
+ setIsUpdating(true);
+ setFeedback(null);
+
+ if (formData.newPassword !== formData.confirmPassword) {
+ setFeedback({ type: 'error', message: "Les nouveaux mots de passe ne correspondent pas." });
+ setIsUpdating(false);
+ return;
+ }
+
+ if (formData.newPassword.length < 8) {
+ setFeedback({ type: 'error', message: "Le mot de passe doit contenir au moins 8 caractères minimum." });
+ setIsUpdating(false);
+ return;
+ }
+
+ try {
+ const userId = pb.authStore.model?.id;
+ if (!userId) throw new Error("Non authentifié.");
+
+ await pb.collection("users").update(userId, {
+ oldPassword: formData.oldPassword,
+ password: formData.newPassword,
+ passwordConfirm: formData.confirmPassword,
+ });
+
+ setFeedback({ type: 'success', message: "Votre mot de passe a été modifié avec succès." });
+ setFormData({ oldPassword: '', newPassword: '', confirmPassword: '' });
+
+ // Retour automatique après 2.5 secondes
+ setTimeout(() => navigate(-1), 2500);
+
+ } catch {
+ setFeedback({ type: 'error', message: "Ancien mot de passe incorrect ou erreur réseau." });
+ } finally {
+ setIsUpdating(false);
+ }
+ };
+
+ const insetNeu = "shadow-[inset_2px_2px_4px_#c5c5c5,inset_-2px_-2px_4px_#ffffff] dark:shadow-[inset_2px_2px_4px_#121926,inset_-2px_-2px_4px_#2a3850]";
+
+ return (
+
+
+ {/* BOUTON DE RETOUR EXTRAIT */}
+
+
+ {/* LE FORMULAIRE */}
+
+
+
+
+
+
+
+ Renouvellement du mot de passe
+
+
+ Veuillez choisir un mot de passe fort et unique pour sécuriser votre accès AEGIS.
+
+
+
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/src/types/Company.ts b/src/types/Company.ts
new file mode 100644
index 0000000..addb1d4
--- /dev/null
+++ b/src/types/Company.ts
@@ -0,0 +1,8 @@
+export interface Company {
+ id: string;
+ name: string;
+ no: string;
+ vip_level: string;
+ created: string;
+ updated: string
+}
\ No newline at end of file
diff --git a/src/types/User.ts b/src/types/User.ts
new file mode 100644
index 0000000..fe0e146
--- /dev/null
+++ b/src/types/User.ts
@@ -0,0 +1,12 @@
+export interface User {
+ id: string;
+ email: string;
+ emailVisibility: boolean;
+ verified: boolean;
+ name: string;
+ role: string;
+ company: string;
+ mfa_enabled: boolean;
+ created: string;
+ updated: string
+}
\ No newline at end of file
diff --git a/vite.config.ts b/vite.config.ts
index 9055c80..427f36f 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -11,20 +11,20 @@ export default defineConfig({
],
resolve: {
alias: {
- '@': path.resolve(__dirname, './src'),
- '@components': path.resolve(__dirname, './src/components'),
- '@ui': path.resolve(__dirname, './src/components/ui'),
- '@common': path.resolve(__dirname, './src/components/common'),
- '@pages': path.resolve(__dirname, './src/pages'),
- '@hooks': path.resolve(__dirname, './src/hooks'),
- '@layouts': path.resolve(__dirname, './src/layouts'),
- '@features': path.resolve(__dirname, './src/features'),
- '@services': path.resolve(__dirname, './src/services'),
- '@utils': path.resolve(__dirname, './src/utils'),
- '@assets': path.resolve(__dirname, './src/assets'),
- '@data': path.resolve(__dirname, './src/data'),
- '@widgets': path.resolve(__dirname, './src/components/widgets'),
- '@styles': path.resolve(__dirname, './src/styles'),
+ '@': path.resolve(import.meta.dirname, './src'),
+ '@components': path.resolve(import.meta.dirname, './src/components'),
+ '@ui': path.resolve(import.meta.dirname, './src/components/ui'),
+ '@common': path.resolve(import.meta.dirname, './src/components/common'),
+ '@pages': path.resolve(import.meta.dirname, './src/pages'),
+ '@hooks': path.resolve(import.meta.dirname, './src/hooks'),
+ '@layouts': path.resolve(import.meta.dirname, './src/layouts'),
+ '@features': path.resolve(import.meta.dirname, './src/features'),
+ '@services': path.resolve(import.meta.dirname, './src/services'),
+ '@utils': path.resolve(import.meta.dirname, './src/utils'),
+ '@assets': path.resolve(import.meta.dirname, './src/assets'),
+ '@data': path.resolve(import.meta.dirname, './src/data'),
+ '@widgets': path.resolve(import.meta.dirname, './src/components/widgets'),
+ '@styles': path.resolve(import.meta.dirname, './src/styles'),
}
}
})