@@ -150,112 +33,58 @@ export default function Login({ onLoginSuccess }: LoginProps) {
-
-
- {step === 1 ? (
-
- {error && (
-
- {error}
-
- )}
+
+
+
+ {/* AFFICHAGE DES ERREURS GLOBALES */}
+ {error && (
+
+ {error}
+
+ )}
- {/* BOUTON SSO ZITADEL */}
-
+ {/* ROUTAGE INTERNE DES ÉTAPES */}
+ {step === 1 ? (
+
-
- {/* SÉPARATEUR VISUEL */}
-
-
-
- Ou via vos identifiants locaux
-
-
-
- {/* FORMULAIRE CLASSIQUE */}
-
- )}
-
+
+
+
);
}
\ No newline at end of file
diff --git a/src/pages/NewTicket.tsx b/src/pages/NewTicket.tsx
deleted file mode 100644
index 80b7026..0000000
--- a/src/pages/NewTicket.tsx
+++ /dev/null
@@ -1,216 +0,0 @@
-import React, { useState } from 'react';
-import { pb } from '@services/pocketbase';
-
-interface NewTicketProps {
- onCancel: () => void;
- onTicketCreated: () => void; // Rappel pour recharger la liste et revenir en arrière
-}
-
-export default function NewTicket({ onCancel, onTicketCreated }: NewTicketProps) {
- const [category, setCategory] = useState<'Incident Critique' | 'Évolution' | 'Administratif'>('Incident Critique');
- const [ci, Ci] = useState('general');
- const [subject, setSubject] = useState('');
- const [affectedAsset, setAffectedAsset] = useState('');
- const [incidentTime, setIncidentTime] = useState('');
- const [description, setDescription] = useState('');
- const [isSubmitting, setIsSubmitting] = useState(false);
- const [error, setError] = useState('');
-
- const handleSubmit = async (e: React.FormEvent) => {
- e.preventDefault();
- setError('');
- setIsSubmitting(true);
-
- try {
- const currentUser = pb.authStore.record;
- if (!currentUser) throw new Error("Utilisateur non authentifié");
-
- // Construction de la description enrichie avec les métadonnées techniques
- let fullDescription = description;
- if (affectedAsset.trim()) {
- fullDescription = `[Équipement concerné: ${affectedAsset}]\n` + fullDescription;
- }
- if (category === 'Incident Critique' && incidentTime) {
- fullDescription = `[Heure de l'incident: ${new Date(incidentTime).toLocaleString('fr-FR')}]\n` + fullDescription;
- }
-
- // Enregistrement dans PocketBase
- await pb.collection('aegis_tickets').create({
- author: currentUser.id,
- company: currentUser.company,
- category,
- subject,
- description: fullDescription,
- status: 'Ouvert',
- });
-
- onTicketCreated(); // Retourne à la liste et rafraîchit
- } catch (err) {
- console.error("Erreur lors de la création du ticket :", err);
- setError("Impossible d'enregistrer le ticket sur le serveur sécurisé.");
- } finally {
- setIsSubmitting(false);
- }
- };
-
- return (
-
-
- {/* Header */}
-
-
-
-
-
Ouvrir un nouveau ticket
-
Qualification de votre requête ITSM
-
-
-
-
- {/* Formulaire Principal */}
-
-
-
-
- );
-}
\ No newline at end of file
diff --git a/src/pages/ServiceDesk.tsx b/src/pages/ServiceDesk.tsx
index d54e108..f5cb9a8 100644
--- a/src/pages/ServiceDesk.tsx
+++ b/src/pages/ServiceDesk.tsx
@@ -1,153 +1,30 @@
-import { useState, useEffect } from 'react';
-import { pb } from '@services/pocketbase';
-import NewTicket from './NewTicket';
-import TicketDetail from './TicketDetail';
-
-interface Ticket {
- id: string;
- subject: string;
- category: string;
- status: 'Ouvert' | 'En analyse' | 'Résolu';
- created: string;
-}
+import { useNavigate } from 'react-router-dom';
+import { Button } from '@/components/ui/Button';
+import { PageHeader } from '@/components/ui/PageHeader';
+import { TicketsWidget } from '@/components/widgets/TicketsWidget';
export default function ServiceDesk() {
- const [tickets, setTickets] = useState
([]);
- const [isLoading, setIsLoading] = useState(true);
-
- // États de navigation interne au module Service Desk
- const [currentView, setCurrentView] = useState<'list' | 'new' | 'detail'>('list');
- const [selectedTicketId, setSelectedTicketId] = useState(null);
+ const navigate = useNavigate();
- // Récupération des tickets de l'entreprise connectée
- const fetchTickets = async () => {
- try {
- const records = await pb.collection('aegis_tickets').getFullList({
- sort: '-created', // Du plus récent au plus ancien
- });
- setTickets(records);
- } catch (error) {
- console.error("Erreur lors de la récupération des tickets :", error);
- } finally {
- setIsLoading(false);
- }
- };
-
- useEffect(() => {
- fetchTickets();
- }, []);
-
- // Gestion du clic sur un ticket pour ouvrir la discussion
- const handleSelectTicket = (id: string) => {
- setSelectedTicketId(id);
- setCurrentView('detail');
- };
-
- // Styles visuels pour les statuts
- const getStatusStyle = (status: Ticket['status']) => {
- switch (status) {
- case 'Ouvert': return 'bg-blue-50 text-blue-700 border-blue-100';
- case 'En analyse': return 'bg-amber-50 text-amber-700 border-amber-100';
- case 'Résolu': return 'bg-emerald-50 text-emerald-700 border-emerald-100';
- default: return 'bg-slate-50 text-slate-700 border-slate-100';
- }
- };
-
- // Rendu conditionnel selon la vue active
- if (currentView === 'new') {
- return (
- setCurrentView('list')}
- onTicketCreated={() => {
- setCurrentView('list');
- fetchTickets(); // On recharge la liste pour afficher le nouveau ticket
- }}
- />
- );
- }
-
- if (currentView === 'detail' && selectedTicketId) {
- return (
- {
- setCurrentView('list');
- setSelectedTicketId(null);
- fetchTickets();
- }}
- />
- );
- }
-
- // Vue par défaut : La liste des tickets
return (
-
-
- {/* Header */}
-
-
-
-
Centre de Support (Service Desk)
-
Canal de communication sécurisé avec vos experts GISE.
-
-
-
-
+
+
-
+ {/* WIDGET DES TICKETS */}
+ navigate(`/support/tickets/${ticketId}`)}
+ />
- {/* Liste des tickets */}
-
-
-
Requêtes en cours et historiques
-
-
- {isLoading ? (
-
- ) : tickets.length === 0 ? (
-
- Aucun ticket enregistré pour le moment.
-
- ) : (
-
- {tickets.map((ticket) => (
-
handleSelectTicket(ticket.id)}
- className="p-6 flex items-center justify-between hover:bg-slate-50 transition-colors cursor-pointer group"
- >
-
-
-
- {ticket.category}
-
-
- Ouvert le {new Date(ticket.created).toLocaleDateString('fr-FR')}
-
-
-
- {ticket.subject}
-
-
-
-
- {ticket.status}
-
-
-
- ))}
-
- )}
-
);
diff --git a/src/pages/TicketDetail.tsx b/src/pages/TicketDetail.tsx
deleted file mode 100644
index cbc0d94..0000000
--- a/src/pages/TicketDetail.tsx
+++ /dev/null
@@ -1,201 +0,0 @@
-import React, { useState, useEffect } from 'react';
-import { pb } from '@services/pocketbase';
-
-interface Ticket {
- id: string;
- subject: string;
- description: string;
- category: string;
- status: 'Ouvert' | 'En analyse' | 'Résolu';
- created: string;
-}
-
-interface Message {
- id: string;
- content: string;
- created: string;
- expand?: {
- author?: {
- id?: string;
- name?: string;
- email?: string;
- avatar?: string;
- };
- };
-}
-
-interface TicketDetailProps {
- ticketId: string;
- onBack: () => void;
-}
-
-export default function TicketDetail({ ticketId, onBack }: TicketDetailProps) {
- const [ticket, setTicket] = useState(null);
- const [messages, setMessages] = useState([]);
- const [newMessage, setNewMessage] = useState('');
- const [isLoading, setIsLoading] = useState(true);
- const [isSending, setIsSending] = useState(false);
-
- const currentUser = pb.authStore.record;
-
- // Récupération du ticket et de ses messages associés
- const fetchTicketData = async () => {
- try {
- const ticketData = await pb.collection('aegis_tickets').getOne(ticketId);
- setTicket(ticketData);
-
- const messageRecords = await pb.collection('aegis_ticket_messages').getFullList({
- filter: `ticket = "${ticketId}"`,
- expand: 'author',
- sort: 'created',
- });
- setMessages(messageRecords);
- } catch (error) {
- console.error("Erreur lors du chargement de la discussion :", error);
- } finally {
- setIsLoading(false);
- }
- };
-
- useEffect(() => {
- fetchTicketData();
- }, [ticketId]);
-
- // Envoi d'un nouveau message dans la discussion
- const handleSendMessage = async (e: React.SubmitEvent) => {
- e.preventDefault();
- if (!newMessage.trim() || !currentUser) return;
-
- setIsSending(true);
- try {
- await pb.collection('aegis_ticket_messages').create({
- ticket: ticketId,
- author: currentUser.id,
- content: newMessage.trim(),
- });
-
- setNewMessage('');
- await fetchTicketData(); // Recharger les messages
- } catch (error) {
- console.error("Erreur lors de l'envoi du message :", error);
- alert("Impossible d'envoyer le message.");
- } finally {
- setIsSending(false);
- }
- };
-
- if (isLoading) {
- return (
-
- );
- }
-
- if (!ticket) {
- return (
-
-
Ticket introuvable ou accès non autorisé.
-
-
- );
- }
-
- return (
-
- {/* Barre de navigation / Retour */}
-
-
-
-
- {ticket.category}
-
-
- {ticket.status}
-
-
-
-
- {/* En-tête du ticket & Description initiale */}
-
-
{ticket.subject}
-
-
Description initiale :
- {ticket.description}
-
-
- Créé le {new Date(ticket.created).toLocaleString('fr-FR')}
-
-
-
- {/* Fil de discussion / Messages */}
-
-
-
Échanges avec l'équipe GISE
-
-
- {/* Liste des messages */}
-
- {messages.length === 0 ? (
-
- Aucun message pour l'instant. Démarrez la conversation ci-dessous.
-
- ) : (
- messages.map((msg) => {
- const isMyMessage = msg.expand?.author?.id === currentUser?.id;
- const authorName = msg.expand?.author?.name || msg.expand?.author?.email || 'Expert GISE';
-
- return (
-
-
- {authorName}
-
- {new Date(msg.created).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}
-
-
-
- {msg.content}
-
-
- );
- })
- )}
-
-
- {/* Formulaire de réponse */}
-
-
-
- );
-}
\ No newline at end of file
diff --git a/src/pages/TrustCenter.tsx b/src/pages/TrustCenter.tsx
index 3867b21..ea0139c 100644
--- a/src/pages/TrustCenter.tsx
+++ b/src/pages/TrustCenter.tsx
@@ -4,36 +4,36 @@ import BackupWidget from '@/components/widgets/BackupWidget';
import SecurityWidget from '@/components/widgets/SecurityWidget';
import ServicesWidget from '@/components/widgets/ServicesWidget';
import SupportCtaWidget from '@/components/widgets/SupportCtaWidget';
+import { PageHeader } from '@/components/ui/PageHeader';
export default function TrustCenter() {
const navigate = useNavigate();
return (