🐛(frontend) change saving behavior firefox
Firefox does not trigger the request everytime the user leaves the page. Plus the request is not intercepted by the service worker. So we prevent the default behavior to have the popup asking the user if he wants to leave the page, by adding the popup, we let the time to the request to be sent, and intercepted by the service worker (for the offline part). We also add a toast to inform the user that the document has been saved, it will make it more obvious that the document has been saved if a firefox user come back from the popup to the page.
This commit is contained in:
@@ -132,6 +132,10 @@ test.describe('Doc Editor', () => {
|
||||
})
|
||||
.click();
|
||||
|
||||
await expect(
|
||||
page.getByText(`Your document "${doc}" has been saved.`),
|
||||
).toBeVisible();
|
||||
|
||||
const card = page.getByLabel('Create new document card').first();
|
||||
await expect(
|
||||
card.getByRole('heading', {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { VariantType, useToastProvider } from '@openfun/cunningham-react';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import * as Y from 'yjs';
|
||||
|
||||
import { useUpdateDoc } from '@/features/docs/doc-management/';
|
||||
@@ -7,7 +9,19 @@ import { useUpdateDoc } from '@/features/docs/doc-management/';
|
||||
import { toBase64 } from '../utils';
|
||||
|
||||
const useSaveDoc = (docId: string, doc: Y.Doc, canSave: boolean) => {
|
||||
const { mutate: updateDoc } = useUpdateDoc();
|
||||
const { toast } = useToastProvider();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { mutate: updateDoc } = useUpdateDoc({
|
||||
onSuccess: (data) => {
|
||||
toast(
|
||||
t('Your document "{{docTitle}}" has been saved.', {
|
||||
docTitle: data.title,
|
||||
}),
|
||||
VariantType.SUCCESS,
|
||||
);
|
||||
},
|
||||
});
|
||||
const [initialDoc, setInitialDoc] = useState<string>(
|
||||
toBase64(Y.encodeStateAsUpdate(doc)),
|
||||
);
|
||||
@@ -40,23 +54,23 @@ const useSaveDoc = (docId: string, doc: Y.Doc, canSave: boolean) => {
|
||||
};
|
||||
}, [doc]);
|
||||
|
||||
/**
|
||||
* Check if the doc has been updated and can be saved.
|
||||
*/
|
||||
const shouldSave = useCallback(() => {
|
||||
const newDoc = toBase64(Y.encodeStateAsUpdate(doc));
|
||||
return initialDoc !== newDoc && canSave;
|
||||
}, [canSave, doc, initialDoc]);
|
||||
|
||||
const saveDoc = useCallback(() => {
|
||||
const newDoc = toBase64(Y.encodeStateAsUpdate(doc));
|
||||
|
||||
/**
|
||||
* Save only if the doc has changed.
|
||||
*/
|
||||
if (initialDoc === newDoc || !canSave) {
|
||||
return;
|
||||
}
|
||||
|
||||
setInitialDoc(newDoc);
|
||||
|
||||
updateDoc({
|
||||
id: docId,
|
||||
content: newDoc,
|
||||
});
|
||||
}, [initialDoc, docId, doc, updateDoc, canSave]);
|
||||
}, [doc, docId, updateDoc]);
|
||||
|
||||
const timeout = useRef<NodeJS.Timeout>();
|
||||
const router = useRouter();
|
||||
@@ -66,8 +80,26 @@ const useSaveDoc = (docId: string, doc: Y.Doc, canSave: boolean) => {
|
||||
clearTimeout(timeout.current);
|
||||
}
|
||||
|
||||
const onSave = () => {
|
||||
const onSave = (e?: Event) => {
|
||||
if (!shouldSave()) {
|
||||
return;
|
||||
}
|
||||
|
||||
saveDoc();
|
||||
|
||||
/**
|
||||
* Firefox does not trigger the request everytime the user leaves the page.
|
||||
* Plus the request is not intercepted by the service worker.
|
||||
* So we prevent the default behavior to have the popup asking the user
|
||||
* if he wants to leave the page, by adding the popup, we let the time to the
|
||||
* request to be sent, and intercepted by the service worker (for the offline part).
|
||||
*/
|
||||
const isFirefox =
|
||||
navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
|
||||
|
||||
if (typeof e !== 'undefined' && e.preventDefault && isFirefox) {
|
||||
e.preventDefault();
|
||||
}
|
||||
};
|
||||
|
||||
// Save every minute
|
||||
@@ -82,7 +114,7 @@ const useSaveDoc = (docId: string, doc: Y.Doc, canSave: boolean) => {
|
||||
removeEventListener('beforeunload', onSave);
|
||||
router.events.off('routeChangeStart', onSave);
|
||||
};
|
||||
}, [router.events, saveDoc]);
|
||||
}, [router.events, saveDoc, shouldSave]);
|
||||
};
|
||||
|
||||
export default useSaveDoc;
|
||||
|
||||
Reference in New Issue
Block a user