Skip to content

Commit 39f7d26

Browse files
committed
Merge branch 'unsaved-changes-warning-on-tab-switch' of Arnei/opencast-admin-interface into r/17.x
Pull request #1390 Fixes #1342 Show unsaved changes warning on tab switch
2 parents 7376882 + 5aa081e commit 39f7d26

5 files changed

Lines changed: 47 additions & 16 deletions

File tree

src/components/events/partials/modals/EventDetails.tsx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React, { useEffect } from "react";
22
import { useTranslation } from "react-i18next";
33
import cn from "classnames";
4-
import { hasAccess } from "../../../../utils/utils";
4+
import { confirmUnsaved, hasAccess } from "../../../../utils/utils";
55
import EventDetailsCommentsTab from "../ModalTabsAndPages/EventDetailsCommentsTab";
66
import EventDetailsAccessPolicyTab from "../ModalTabsAndPages/EventDetailsAccessPolicyTab";
77
import EventDetailsWorkflowTab from "../ModalTabsAndPages/EventDetailsWorkflowTab";
@@ -219,8 +219,16 @@ const EventDetails = ({
219219
];
220220

221221
const openTab = (tabNr: EventDetailsPage) => {
222-
dispatch(removeNotificationWizardForm());
223-
dispatch(openModalTab(tabNr, "entry", "entry"))
222+
let isUnsavedChanges = false;
223+
isUnsavedChanges = policyChanged;
224+
if (formikRef.current && formikRef.current.dirty !== undefined && formikRef.current.dirty) {
225+
isUnsavedChanges = true;
226+
}
227+
228+
if (!isUnsavedChanges || confirmUnsaved(t)) {
229+
dispatch(removeNotificationWizardForm());
230+
dispatch(openModalTab(tabNr, "entry", "entry"))
231+
}
224232
};
225233

226234
return (

src/components/events/partials/modals/EventDetailsModal.tsx

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { getModalEvent } from "../../../../selectors/eventDetailsSelectors";
77
import { setModalEvent, setShowModal } from "../../../../slices/eventDetailsSlice";
88
import { Modal } from "../../../shared/modals/Modal";
99
import { FormikProps } from "formik";
10+
import { confirmUnsaved } from "../../../../utils/utils";
1011

1112
/**
1213
* This component renders the modal for displaying event details
@@ -21,10 +22,6 @@ const EventDetailsModal = () => {
2122

2223
const event = useAppSelector(state => getModalEvent(state))!;
2324

24-
const confirmUnsaved = () => {
25-
return window.confirm(t("CONFIRMATIONS.WARNINGS.UNSAVED_CHANGES"));
26-
};
27-
2825
const hideModal = () => {
2926
dispatch(setModalEvent(null));
3027
dispatch(setShowModal(false));
@@ -37,7 +34,7 @@ const EventDetailsModal = () => {
3734
isUnsavedChanges = true
3835
}
3936

40-
if (!isUnsavedChanges || confirmUnsaved()) {
37+
if (!isUnsavedChanges || confirmUnsaved(t)) {
4138
setPolicyChanged(false);
4239
dispatch(removeNotificationWizardForm());
4340
hideModal();

src/components/events/partials/modals/SeriesDetails.tsx

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
hasStatistics as seriesHasStatistics,
1212
} from "../../../../selectors/seriesDetailsSelectors";
1313
import { getOrgProperties, getUserInformation } from "../../../../selectors/userInfoSelectors";
14-
import { hasAccess } from "../../../../utils/utils";
14+
import { confirmUnsaved, hasAccess } from "../../../../utils/utils";
1515
import SeriesDetailsAccessTab from "../ModalTabsAndPages/SeriesDetailsAccessTab";
1616
import SeriesDetailsThemeTab from "../ModalTabsAndPages/SeriesDetailsThemeTab";
1717
import SeriesDetailsStatisticTab from "../ModalTabsAndPages/SeriesDetailsStatisticTab";
@@ -28,6 +28,7 @@ import DetailsTobiraTab from "../ModalTabsAndPages/DetailsTobiraTab";
2828
import ButtonLikeAnchor from "../../../shared/ButtonLikeAnchor";
2929
import { removeNotificationWizardTobira } from "../../../../slices/notificationSlice";
3030
import { ParseKeys } from "i18next";
31+
import { FormikProps } from "formik";
3132

3233
/**
3334
* This component manages the tabs of the series details modal
@@ -36,10 +37,12 @@ const SeriesDetails = ({
3637
seriesId,
3738
policyChanged,
3839
setPolicyChanged,
40+
formikRef,
3941
}: {
4042
seriesId: string
4143
policyChanged: boolean
4244
setPolicyChanged: (policyChanged: boolean) => void
45+
formikRef: React.RefObject<FormikProps<any> | null>
4346
}) => {
4447
const { t } = useTranslation();
4548
const dispatch = useAppDispatch();
@@ -110,7 +113,15 @@ const SeriesDetails = ({
110113
];
111114

112115
const openTab = (tabNr: number) => {
113-
setPage(tabNr);
116+
let isUnsavedChanges = false;
117+
isUnsavedChanges = policyChanged;
118+
if (formikRef.current && formikRef.current.dirty !== undefined && formikRef.current.dirty) {
119+
isUnsavedChanges = true;
120+
}
121+
122+
if (!isUnsavedChanges || confirmUnsaved(t)) {
123+
setPage(tabNr);
124+
}
114125
};
115126

116127
return (
@@ -136,6 +147,7 @@ const SeriesDetails = ({
136147
metadata={[metadataFields]}
137148
updateResource={updateSeriesMetadata}
138149
editAccessRole="ROLE_UI_SERIES_DETAILS_METADATA_EDIT"
150+
formikRef={formikRef}
139151
header={tabs[page].tabNameTranslation}
140152
/>
141153
)}
@@ -145,6 +157,7 @@ const SeriesDetails = ({
145157
metadata={extendedMetadata}
146158
updateResource={updateExtendedSeriesMetadata}
147159
editAccessRole="ROLE_UI_SERIES_DETAILS_METADATA_EDIT"
160+
formikRef={formikRef}
148161
/>
149162
)}
150163
{page === 2 && (

src/components/events/partials/modals/SeriesDetailsModal.tsx

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
import React, { useState } from "react";
1+
import React, { useRef, useState } from "react";
22
import { useTranslation } from "react-i18next";
33
import SeriesDetails from "./SeriesDetails";
44
import { removeNotificationWizardForm } from "../../../../slices/notificationSlice";
55
import { useAppDispatch } from "../../../../store";
66
import { Modal, ModalHandle } from "../../../shared/modals/Modal";
7+
import { confirmUnsaved } from "../../../../utils/utils";
8+
import { FormikProps } from "formik";
79

810
/**
911
* This component renders the modal for displaying series details
@@ -22,13 +24,16 @@ const SeriesDetailsModal = ({
2224

2325
// tracks, whether the policies are different to the initial value
2426
const [policyChanged, setPolicyChanged] = useState(false);
25-
26-
const confirmUnsaved = () => {
27-
return window.confirm(t("CONFIRMATIONS.WARNINGS.UNSAVED_CHANGES"));
28-
};
27+
const formikRef = useRef<FormikProps<any>>(null);
2928

3029
const close = () => {
31-
if (!policyChanged || confirmUnsaved()) {
30+
let isUnsavedChanges = false
31+
isUnsavedChanges = policyChanged
32+
if (formikRef.current && formikRef.current.dirty !== undefined && formikRef.current.dirty) {
33+
isUnsavedChanges = true
34+
}
35+
36+
if (!isUnsavedChanges || confirmUnsaved(t)) {
3237
setPolicyChanged(false);
3338
dispatch(removeNotificationWizardForm());
3439
return true;
@@ -47,6 +52,7 @@ const SeriesDetailsModal = ({
4752
seriesId={seriesId}
4853
policyChanged={policyChanged}
4954
setPolicyChanged={(value) => setPolicyChanged(value)}
55+
formikRef={formikRef}
5056
/>
5157
</Modal>
5258
);

src/utils/utils.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,3 +145,10 @@ export const translateOverrideFallback = (asset: UploadOption, t: TFunction, suf
145145

146146
return result;
147147
}
148+
149+
/**
150+
* Have the browser show a warning dialog for unsaved changes
151+
*/
152+
export const confirmUnsaved = (t: TFunction) => {
153+
return window.confirm(t("CONFIRMATIONS.WARNINGS.UNSAVED_CHANGES"));
154+
};

0 commit comments

Comments
 (0)