diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 39b9cd6..633862c 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect, useRef } from 'react'; import { jwtDecode } from 'jwt-decode'; import Layout from './components/Layout'; import OwnerDashboard from './pages/OwnerDashboard'; @@ -21,6 +21,7 @@ function App() { const [myRecords, setMyRecords] = useState([]); const [loading, setLoading] = useState(true); const [currentUser, setCurrentUser] = useState(null); + const caseDetailDirtyRef = useRef(false); // 1. Initialisering: Hämta användare från token vid start useEffect(() => { @@ -109,6 +110,7 @@ function App() { }; const goBackToDashboard = () => { + caseDetailDirtyRef.current = false; setSelectedPet(null); setSelectedRecord(null); if (currentUser?.role === 'ROLE_VET') { @@ -209,6 +211,7 @@ function App() { caseData={selectedRecord} currentUserId={currentUser?.id} userRole={currentUser?.role} // VIKTIGT: Skickar med rollen för veterinär-panelen + onDirtyChange={(dirty) => { caseDetailDirtyRef.current = dirty; }} onBack={goBackToDashboard} onGoToPet={async (petId) => { try { @@ -270,7 +273,13 @@ function App() { userName={currentUser?.name || currentUser?.email || "Användare"} userRole={currentUser?.role} onLogout={handleLogout} - onNavigate={(view) => setCurrentView(view)} + onNavigate={(view) => { + if (currentView === 'case-detail' && caseDetailDirtyRef.current) { + if (!window.confirm('Du har osparade ändringar. Vill du lämna sidan?')) return; + } + caseDetailDirtyRef.current = false; + setCurrentView(view); + }} currentView={currentView} >
diff --git a/frontend/src/pages/CaseDetail.jsx b/frontend/src/pages/CaseDetail.jsx index 339f8c3..a3e67cb 100644 --- a/frontend/src/pages/CaseDetail.jsx +++ b/frontend/src/pages/CaseDetail.jsx @@ -3,7 +3,7 @@ import { commentService, activityService, attachmentService, medicalRecordServic import { STATUS_MAP } from '../utils/statusHelper'; import { Stethoscope, Lock, FileText, CheckCircle, Upload, Trash2, ExternalLink } from 'lucide-react'; -const CaseDetail = ({ caseData, onBack, onGoToPet, currentUserId, userRole }) => { +const CaseDetail = ({ caseData, onBack, onGoToPet, currentUserId, userRole, onDirtyChange }) => { const [newMessage, setNewMessage] = useState(''); const [timeline, setTimeline] = useState([]); const [attachments, setAttachments] = useState([]); @@ -22,6 +22,41 @@ const CaseDetail = ({ caseData, onBack, onGoToPet, currentUserId, userRole }) => const isClosed = localStatus === 'CLOSED'; // Helper för att förenkla checkar + // Refs för att komma åt senaste state i cleanup-funktioner + const newMessageRef = useRef(newMessage); + const isEditingRef = useRef(isEditing); + const editedTitleRef = useRef(editedTitle); + const editedDescriptionRef = useRef(editedDescription); + + useEffect(() => { newMessageRef.current = newMessage; }, [newMessage]); + useEffect(() => { isEditingRef.current = isEditing; }, [isEditing]); + useEffect(() => { editedTitleRef.current = editedTitle; }, [editedTitle]); + useEffect(() => { editedDescriptionRef.current = editedDescription; }, [editedDescription]); + + // Rapportera dirty-state uppåt till App för in-app navigeringsskydd + useEffect(() => { + const journalChanged = isEditing && (editedTitle !== caseData?.title || editedDescription !== caseData?.description); + onDirtyChange?.(newMessage.trim().length > 0 || journalChanged); + }, [newMessage, isEditing, editedTitle, editedDescription]); + + // Varna vid stängning av fliken om det finns osparad text + useEffect(() => { + const handleBeforeUnload = (e) => { + const journalChanged = isEditingRef.current && (editedTitleRef.current !== caseData?.title || editedDescriptionRef.current !== caseData?.description); + const hasUnsaved = newMessageRef.current.trim() || journalChanged; + if (hasUnsaved) { + e.preventDefault(); + e.returnValue = ''; + } + }; + window.addEventListener('beforeunload', handleBeforeUnload); + return () => window.removeEventListener('beforeunload', handleBeforeUnload); + }, []); + + useEffect(() => { + return () => { onDirtyChange?.(false); }; + }, []); + useEffect(() => { if (caseData) { setLocalStatus(caseData.status);