Skip to content

Commit df5fd5e

Browse files
committed
feat: replace browser confirms with custom modal dialogs for unsaved changes
Replace native window.confirm() with ConfirmDialog component for better UX consistency and modern appearance. Adds centered warning modal when user attempts to discard unsaved changes (close draft, switch to preview, or load different draft). Changes: - Add unsavedChangesDialogOpen and pendingAction states - Update toggleEditMode, loadDraft, and handleClose to trigger modal - Add handleDiscardChanges and handleCancelDiscard handlers - Add ConfirmDialog with warning intent at end of component
1 parent 2f7e04c commit df5fd5e

1 file changed

Lines changed: 120 additions & 56 deletions

File tree

frontend/src/features/kba-drafter/KBADrafterPage.jsx

Lines changed: 120 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,8 @@ export default function KBADrafterPage() {
203203
const [replaceDialogOpen, setReplaceDialogOpen] = useState(false);
204204
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
205205
const [draftToDelete, setDraftToDelete] = useState(null);
206+
const [unsavedChangesDialogOpen, setUnsavedChangesDialogOpen] = useState(false);
207+
const [pendingAction, setPendingAction] = useState(null);
206208

207209
// Ticket Viewer Dialog State
208210
const [ticketDialogOpen, setTicketDialogOpen] = useState(false);
@@ -488,6 +490,7 @@ export default function KBADrafterPage() {
488490

489491
setCurrentDraft(updated);
490492
setEditedDraft(JSON.parse(JSON.stringify(updated)));
493+
setEditMode(false);
491494
setMessage({ type: "success", text: "✓ Änderungen gespeichert" });
492495
} catch (error) {
493496
setMessage({ type: "error", text: "✗ Fehler beim Speichern: " + error.message });
@@ -499,10 +502,8 @@ export default function KBADrafterPage() {
499502
// Handler: Toggle Edit Mode
500503
const toggleEditMode = () => {
501504
if (editMode && hasPendingChanges) {
502-
if (window.confirm("Nicht gespeicherte Änderungen verwerfen?")) {
503-
setEditedDraft(JSON.parse(JSON.stringify(currentDraft)));
504-
setEditMode(false);
505-
}
505+
setPendingAction('toggleEdit');
506+
setUnsavedChangesDialogOpen(true);
506507
} else {
507508
setEditMode(!editMode);
508509
if (!editMode) {
@@ -618,9 +619,9 @@ export default function KBADrafterPage() {
618619
// Handler: Load Draft from List
619620
const loadDraft = async (draftId) => {
620621
if (hasPendingChanges) {
621-
if (!window.confirm("Nicht gespeicherte Änderungen verwerfen?")) {
622-
return;
623-
}
622+
setPendingAction({ type: 'loadDraft', draftId });
623+
setUnsavedChangesDialogOpen(true);
624+
return;
624625
}
625626

626627
try {
@@ -667,15 +668,46 @@ export default function KBADrafterPage() {
667668
// Handler: Close Draft
668669
const handleClose = () => {
669670
if (hasPendingChanges) {
670-
if (!window.confirm("Nicht gespeicherte Änderungen verwerfen?")) {
671-
return;
672-
}
671+
setPendingAction('closeDraft');
672+
setUnsavedChangesDialogOpen(true);
673+
return;
673674
}
674675
setCurrentDraft(null);
675676
setEditedDraft(null);
676677
setEditMode(false);
677678
};
678679

680+
// Handler: Discard Unsaved Changes
681+
const handleDiscardChanges = async () => {
682+
setUnsavedChangesDialogOpen(false);
683+
684+
if (pendingAction === 'toggleEdit') {
685+
setEditedDraft(JSON.parse(JSON.stringify(currentDraft)));
686+
setEditMode(false);
687+
} else if (pendingAction === 'closeDraft') {
688+
setCurrentDraft(null);
689+
setEditedDraft(null);
690+
setEditMode(false);
691+
} else if (pendingAction?.type === 'loadDraft') {
692+
try {
693+
const draft = await api.getKBADraft(pendingAction.draftId);
694+
setCurrentDraft(draft);
695+
setEditedDraft(JSON.parse(JSON.stringify(draft)));
696+
setEditMode(false);
697+
} catch (error) {
698+
setMessage({ type: "error", text: "Fehler beim Laden des Entwurfs" });
699+
}
700+
}
701+
702+
setPendingAction(null);
703+
};
704+
705+
// Handler: Cancel Discard
706+
const handleCancelDiscard = () => {
707+
setUnsavedChangesDialogOpen(false);
708+
setPendingAction(null);
709+
};
710+
679711
// Handler: View Ticket
680712
const handleViewTicket = async () => {
681713
if (!displayDraft?.incident_id) {
@@ -785,57 +817,77 @@ export default function KBADrafterPage() {
785817

786818
{/* Current Draft Editor/Viewer */}
787819
{displayDraft && (
788-
<Card className={styles.draftCard}>
820+
<Card className={styles.draftCard} style={{ position: "relative" }}>
821+
{/* Close Button - Top Right Corner */}
822+
<Button
823+
appearance="subtle"
824+
icon={<Dismiss24Regular />}
825+
onClick={handleClose}
826+
disabled={loading || saving}
827+
size="small"
828+
style={{
829+
position: "absolute",
830+
top: "16px",
831+
right: "16px",
832+
zIndex: 10,
833+
minWidth: "32px",
834+
padding: "6px"
835+
}}
836+
title="Schließen"
837+
/>
838+
789839
<CardHeader
790840
header={
791841
<div className={styles.draftHeader}>
792-
<div>
793-
<strong>KBA-Entwurf</strong>
794-
{hasPendingChanges && (
795-
<span className={styles.pendingIndicator}> • Nicht gespeichert</span>
796-
)}
797-
</div>
798-
<div style={{ display: "flex", gap: tokens.spacingHorizontalS, alignItems: "center", marginLeft: tokens.spacingHorizontalL }}>
799-
<Badge
800-
appearance="filled"
801-
color={getStatusBadgeColor(displayDraft.status)}
802-
>
803-
{displayDraft.status}
804-
</Badge>
805-
{displayDraft.is_auto_generated && (
806-
<Badge
807-
appearance="tint"
808-
color="informative"
809-
style={{ fontSize: "11px" }}
842+
<div style={{ display: "flex", alignItems: "center", gap: tokens.spacingHorizontalL, flex: 1 }}>
843+
<div>
844+
<strong>KBA-Entwurf</strong>
845+
{hasPendingChanges && (
846+
<span className={styles.pendingIndicator}> • Nicht gespeichert</span>
847+
)}
848+
</div>
849+
<div style={{ display: "flex", gap: tokens.spacingHorizontalS, alignItems: "center" }}>
850+
<Badge
851+
appearance="filled"
852+
color={getStatusBadgeColor(displayDraft.status)}
810853
>
811-
🤖 AutoGen
854+
{displayDraft.status}
812855
</Badge>
813-
)}
814-
{displayDraft.incident_id && (
815-
<Badge appearance="outline" className={styles.statusBadge}>
816-
{displayDraft.incident_id}
817-
</Badge>
818-
)}
819-
{displayDraft.incident_id && (
820-
<Button
821-
appearance="subtle"
822-
icon={<DocumentSearch20Regular />}
823-
onClick={handleViewTicket}
824-
size="small"
825-
>
826-
Ticket
827-
</Button>
828-
)}
829-
{displayDraft.status === "draft" && (
830-
<Button
831-
appearance="subtle"
832-
icon={editMode ? <Eye24Regular /> : <Edit24Regular />}
833-
onClick={toggleEditMode}
834-
size="small"
835-
>
836-
{editMode ? "Vorschau" : "Bearbeiten"}
837-
</Button>
838-
)}
856+
{displayDraft.is_auto_generated && (
857+
<Badge
858+
appearance="tint"
859+
color="informative"
860+
style={{ fontSize: "11px" }}
861+
>
862+
🤖 AutoGen
863+
</Badge>
864+
)}
865+
{displayDraft.incident_id && (
866+
<Badge appearance="outline" className={styles.statusBadge}>
867+
{displayDraft.incident_id}
868+
</Badge>
869+
)}
870+
{displayDraft.incident_id && (
871+
<Button
872+
appearance="subtle"
873+
icon={<DocumentSearch20Regular />}
874+
onClick={handleViewTicket}
875+
size="small"
876+
>
877+
Ticket
878+
</Button>
879+
)}
880+
{displayDraft.status === "draft" && (
881+
<Button
882+
appearance="subtle"
883+
icon={editMode ? <Eye24Regular /> : <Edit24Regular />}
884+
onClick={toggleEditMode}
885+
size="small"
886+
>
887+
{editMode ? "Vorschau" : "Bearbeiten"}
888+
</Button>
889+
)}
890+
</div>
839891
</div>
840892
</div>
841893
}
@@ -1520,6 +1572,18 @@ export default function KBADrafterPage() {
15201572
</DialogActions>
15211573
</DialogSurface>
15221574
</Dialog>
1575+
1576+
{/* Unsaved Changes Dialog */}
1577+
<ConfirmDialog
1578+
open={unsavedChangesDialogOpen}
1579+
title="Nicht gespeicherte Änderungen"
1580+
message="Sie haben nicht gespeicherte Änderungen. Möchten Sie diese verwerfen?"
1581+
confirmText="Änderungen verwerfen"
1582+
cancelText="Abbrechen"
1583+
intent="warning"
1584+
onConfirm={handleDiscardChanges}
1585+
onCancel={handleCancelDiscard}
1586+
/>
15231587
</div>
15241588
);
15251589
}

0 commit comments

Comments
 (0)