Skip to content
Snippets Groups Projects
Verified Commit 6c0ba3c3 authored by Dorian Koch's avatar Dorian Koch
Browse files

Fix Player title not updating after navigating to next lecture

parent 4853be59
No related branches found
No related tags found
No related merge requests found
Pipeline #6369 passed
...@@ -20,6 +20,7 @@ import type { ...@@ -20,6 +20,7 @@ import type {
int, int,
} from "@/api/api_v1_types"; } from "@/api/api_v1_types";
import { StylizedText } from "./StylizedText"; import { StylizedText } from "./StylizedText";
import StopNavigation from "./StopNavigation";
const markdownSupportingFields = [ const markdownSupportingFields = [
"announcement.text", "announcement.text",
...@@ -135,9 +136,9 @@ export function EmbeddedOMFieldComponent({ ...@@ -135,9 +136,9 @@ export function EmbeddedOMFieldComponent({
// We need an additional references since a state is not updated immediately and sometimes the API call would fail // We need an additional references since a state is not updated immediately and sometimes the API call would fail
// due to an unexpected current value. (Only using a ref does not work, since the rendering needs this to indicate // due to an unexpected current value. (Only using a ref does not work, since the rendering needs this to indicate
// if changes have been made) // if changes have been made)
const fieldValueRef = useRef<field_value>(); const serverSideFieldValueRef = useRef<field_value>(); // This is what we expect the value to be on the server
const updatedSinceLastReloadRef = useRef<boolean>(false); const updatedSinceLastReloadRef = useRef<boolean>(false);
const beforeEditingValue = useRef(initialValue); const beforeEditingValue = useRef();
const { editMode } = useEditMode(); const { editMode } = useEditMode();
// These types can be edited without loading the configuration or starting editing (e.g. isEditing is ignored) // These types can be edited without loading the configuration or starting editing (e.g. isEditing is ignored)
...@@ -145,7 +146,7 @@ export function EmbeddedOMFieldComponent({ ...@@ -145,7 +146,7 @@ export function EmbeddedOMFieldComponent({
const isInstantEdit = ["boolean"].includes(field_type); const isInstantEdit = ["boolean"].includes(field_type);
useEffect(() => { useEffect(() => {
if (!isInstantEdit) return; if (isInstantEdit) {
setField({ setField({
description: { description: {
id: field_id, id: field_id,
...@@ -154,7 +155,9 @@ export function EmbeddedOMFieldComponent({ ...@@ -154,7 +155,9 @@ export function EmbeddedOMFieldComponent({
}, },
value: initialValue, value: initialValue,
}); });
fieldValueRef.current = initialValue; }
serverSideFieldValueRef.current = initialValue;
setValue(initialValue); setValue(initialValue);
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [isInstantEdit, field_id, field_type, initialValue]); }, [isInstantEdit, field_id, field_type, initialValue]);
...@@ -162,6 +165,7 @@ export function EmbeddedOMFieldComponent({ ...@@ -162,6 +165,7 @@ export function EmbeddedOMFieldComponent({
useEffect(() => { useEffect(() => {
if (!isEditing) return; if (!isEditing) return;
// TODO: disable editing while config is still loading, this is especially annoying with high latency
api.getOMConfiguration(object_type, object_id) api.getOMConfiguration(object_type, object_id)
.then((config) => { .then((config) => {
const field = config.fields?.find((field) => field.description.id === field_id); const field = config.fields?.find((field) => field.description.id === field_id);
...@@ -171,7 +175,7 @@ export function EmbeddedOMFieldComponent({ ...@@ -171,7 +175,7 @@ export function EmbeddedOMFieldComponent({
return; return;
} }
setField(field); setField(field);
fieldValueRef.current = field.value; serverSideFieldValueRef.current = field.value;
setValue(field.value); setValue(field.value);
}) })
.catch((error) => { .catch((error) => {
...@@ -180,18 +184,18 @@ export function EmbeddedOMFieldComponent({ ...@@ -180,18 +184,18 @@ export function EmbeddedOMFieldComponent({
}); });
}, [api, isEditing, object_type, object_id, field_id]); }, [api, isEditing, object_type, object_id, field_id]);
const [deferred, now] = useDebounceUpdateData<any, void>( const [deferredSendValueUpdate, nowSendValueUpdate] = useDebounceUpdateData<any, void>(
async (newValue: any) => { async (newValue: any) => {
if (field === undefined) return; if (field === undefined) return;
if (deepEquals(newValue, fieldValueRef.current)) return; if (deepEquals(newValue, serverSideFieldValueRef.current)) return;
return api return api
.updateOMObject(object_type, object_id, { .updateOMObject(object_type, object_id, {
updates: { [field_id]: newValue }, updates: { [field_id]: newValue },
expected_current_values: { [field_id]: fieldValueRef.current }, expected_current_values: { [field_id]: serverSideFieldValueRef.current },
}) })
.then(() => { .then(() => {
fieldValueRef.current = newValue; serverSideFieldValueRef.current = newValue;
setField(field === undefined ? undefined : { ...field, value: newValue }); setField(field === undefined ? undefined : { ...field, value: newValue });
if (isInstantEdit) { if (isInstantEdit) {
reloadFunc(); reloadFunc();
...@@ -209,7 +213,7 @@ export function EmbeddedOMFieldComponent({ ...@@ -209,7 +213,7 @@ export function EmbeddedOMFieldComponent({
const disableEditing = () => { const disableEditing = () => {
if (!isValid) return; if (!isValid) return;
if (!isEditing) return; if (!isEditing) return;
now(value).then(() => { nowSendValueUpdate(value).then(() => {
setIsEditing(false); setIsEditing(false);
if (updatedSinceLastReloadRef.current) { if (updatedSinceLastReloadRef.current) {
reloadFunc(); reloadFunc();
...@@ -222,7 +226,7 @@ export function EmbeddedOMFieldComponent({ ...@@ -222,7 +226,7 @@ export function EmbeddedOMFieldComponent({
if (!isEditing) return; if (!isEditing) return;
setValue(beforeEditingValue.current); setValue(beforeEditingValue.current);
setIsValid(true); setIsValid(true);
deferred(beforeEditingValue.current); deferredSendValueUpdate(beforeEditingValue.current);
}; };
useEffect(() => { useEffect(() => {
...@@ -276,9 +280,9 @@ export function EmbeddedOMFieldComponent({ ...@@ -276,9 +280,9 @@ export function EmbeddedOMFieldComponent({
setIsValid(isValid); setIsValid(isValid);
if (isValid) { if (isValid) {
if (affectNow) { if (affectNow) {
now(newValue); nowSendValueUpdate(newValue);
} else { } else {
deferred(newValue); deferredSendValueUpdate(newValue);
} }
} }
}, },
...@@ -301,6 +305,9 @@ export function EmbeddedOMFieldComponent({ ...@@ -301,6 +305,9 @@ export function EmbeddedOMFieldComponent({
onBlur={disableEditing} onBlur={disableEditing}
onSubmit={disableEditing} onSubmit={disableEditing}
> >
{isEditing && hasChanged && (
<StopNavigation warningText="You have unsaved changes. Are you sure you want to leave?" />
)}
<div <div
className={"vr mx-1 " + (hasChanged ? "opacity-25" : "opacity-0")} className={"vr mx-1 " + (hasChanged ? "opacity-25" : "opacity-0")}
style={{ color: "orange", width: "4px", verticalAlign: "baseline" }} style={{ color: "orange", width: "4px", verticalAlign: "baseline" }}
......
import { useEffect } from "react";
import { useRouter } from "next/router";
export default function StopNavigation({ warningText }: { warningText: string }) {
const router = useRouter();
useEffect(() => {
const handleWindowClose = (e: BeforeUnloadEvent) => {
e.preventDefault();
return warningText;
};
const handleBrowseAway = () => {
if (window.confirm(warningText)) return;
router.events.emit("routeChangeError");
throw "routeChange aborted.";
};
window.addEventListener("beforeunload", handleWindowClose);
router.events.on("routeChangeStart", handleBrowseAway);
return () => {
window.removeEventListener("beforeunload", handleWindowClose);
router.events.off("routeChangeStart", handleBrowseAway);
};
}, [router, warningText]);
return null;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment