From 903299daf79cc533f79a6f107ae17fe51b4bbf8a Mon Sep 17 00:00:00 2001 From: Tim Arney Date: Mon, 3 Feb 2025 09:42:30 -0500 Subject: [PATCH] add prompt --- .../forms/SaveAndResume/ConfirmDownload.tsx | 118 ++++++++++++++++++ .../forms/SaveAndResume/SaveAndResume.tsx | 74 +++-------- i18n/translations/en/common.json | 6 + i18n/translations/fr/common.json | 6 + 4 files changed, 146 insertions(+), 58 deletions(-) create mode 100644 components/clientComponents/forms/SaveAndResume/ConfirmDownload.tsx diff --git a/components/clientComponents/forms/SaveAndResume/ConfirmDownload.tsx b/components/clientComponents/forms/SaveAndResume/ConfirmDownload.tsx new file mode 100644 index 0000000000..445e2fb89d --- /dev/null +++ b/components/clientComponents/forms/SaveAndResume/ConfirmDownload.tsx @@ -0,0 +1,118 @@ +import { useCallback, useState } from "react"; +import * as AlertDialog from "@radix-ui/react-alert-dialog"; +import { useTranslation } from "@i18n/client"; +import Markdown from "markdown-to-jsx"; + +import { type Language } from "@lib/types/form-builder-types"; +import { Button } from "@clientComponents/globals"; +import { useGCFormsContext } from "@lib/hooks/useGCFormContext"; +import { slugify } from "@lib/client/clientHelpers"; + +export type handleCloseType = (value: boolean) => void; + +declare global { + interface Window { + showSaveFilePicker: ({}) => Promise; + createWritable: () => Promise; + } +} + +async function promptToSave(fileName: string, data: string) { + const handle = await window?.showSaveFilePicker({ + suggestedName: fileName, + types: [ + { + description: "Form Progress (Save to resume later)", + accept: { "text/plain": [".txt"] }, + }, + ], + }); + + const writable = await handle.createWritable(); + await writable.write(data); + await writable.close(); +} + +export const ConfirmDownload = ({ + open, + handleClose, + formId, + formTitleEn, + formTitleFr, + language, +}: { + open: boolean; + handleClose: handleCloseType; + formId: string; + formTitleEn: string; + formTitleFr: string; + language: Language; +}) => { + const { t } = useTranslation("form-builder"); + + const { getProgressData } = useGCFormsContext(); + const [saving, setSaving] = useState(false); + + const handleSave = useCallback(async () => { + try { + setSaving(true); + + const title = language === "en" ? formTitleEn : formTitleFr; + + const fileName = `${slugify(title)}-${formId}.txt`; + + const data = btoa(JSON.stringify(getProgressData())); + + if (!window?.showSaveFilePicker) { + const downloadLink = document.createElement("a"); + const blob = new Blob([data], { type: "text/plain" }); + downloadLink.href = URL.createObjectURL(blob); + downloadLink.download = fileName; + downloadLink.click(); + URL.revokeObjectURL(downloadLink.href); + } else { + await promptToSave(fileName, data); + } + setSaving(false); + } catch (error) { + setSaving(false); + } + }, [formId, formTitleEn, formTitleFr, getProgressData, language]); + + return ( + + + + + + {t("saveAndResume.prompt.title")} + + + + {t("saveAndResume.prompt.description")} + + +
+ + + + + + +
+
+
+
+ ); +}; diff --git a/components/clientComponents/forms/SaveAndResume/SaveAndResume.tsx b/components/clientComponents/forms/SaveAndResume/SaveAndResume.tsx index be896de070..f5061c519f 100644 --- a/components/clientComponents/forms/SaveAndResume/SaveAndResume.tsx +++ b/components/clientComponents/forms/SaveAndResume/SaveAndResume.tsx @@ -1,33 +1,10 @@ -import { useCallback, useState } from "react"; -import { useGCFormsContext } from "@lib/hooks/useGCFormContext"; -import { LinkButton } from "@serverComponents/globals/Buttons/LinkButton"; -import { SubmitButton as DownloadProgress } from "@clientComponents/globals/Buttons/SubmitButton"; +import { useState } from "react"; import { useTranslation } from "@i18n/client"; -import { Language } from "@lib/types/form-builder-types"; -import { slugify } from "@lib/client/clientHelpers"; - -declare global { - interface Window { - showSaveFilePicker: ({}) => Promise; - createWritable: () => Promise; - } -} -async function promptToSave(fileName: string, data: string) { - const handle = await window?.showSaveFilePicker({ - suggestedName: fileName, - types: [ - { - description: "Form Progress (Save to resume later)", - accept: { "text/plain": [".txt"] }, - }, - ], - }); - - const writable = await handle.createWritable(); - await writable.write(data); - await writable.close(); -} +import { type Language } from "@lib/types/form-builder-types"; +import { LinkButton } from "@serverComponents/globals/Buttons/LinkButton"; +import { SubmitButton as DownloadProgress } from "@clientComponents/globals/Buttons/SubmitButton"; +import { ConfirmDownload } from "./ConfirmDownload"; export const SaveAndResume = ({ formId, @@ -40,50 +17,31 @@ export const SaveAndResume = ({ formTitleFr: string; language: Language; }) => { - const { getProgressData } = useGCFormsContext(); const { t } = useTranslation(["review", "common"]); - const [saving, setSaving] = useState(false); - - const handleSave = useCallback(async () => { - try { - setSaving(true); - - const title = language === "en" ? formTitleEn : formTitleFr; - - const fileName = `${slugify(title)}.txt`; - - const data = btoa(JSON.stringify(getProgressData())); - - if (!window?.showSaveFilePicker) { - const downloadLink = document.createElement("a"); - const blob = new Blob([data], { type: "text/plain" }); - downloadLink.href = URL.createObjectURL(blob); - downloadLink.download = fileName; - downloadLink.click(); - URL.revokeObjectURL(downloadLink.href); - } else { - await promptToSave(fileName, data); - } - setSaving(false); - } catch (error) { - setSaving(false); - } - }, [formTitleEn, formTitleFr, getProgressData, language]); + const [confirm, setConfirm] = useState(false); return (
setConfirm(true)} > {t("saveAndResume.saveBtn")} {t("saveAndResume.resumeBtn")} + setConfirm(false)} + />
); }; diff --git a/i18n/translations/en/common.json b/i18n/translations/en/common.json index d8a0437be4..2a4b8088df 100644 --- a/i18n/translations/en/common.json +++ b/i18n/translations/en/common.json @@ -227,6 +227,12 @@ "title": "Start again", "description": "Fill out a blank form" } + }, + "prompt": { + "title": "Save your progress", + "description": "Warning you are responsible for protecting the downloaded file. If you lose it, you will not be able to resume your form.", + "okay": "Okay", + "cancel": "Cancel" } } } diff --git a/i18n/translations/fr/common.json b/i18n/translations/fr/common.json index 6c0b50eca6..46b3856b68 100644 --- a/i18n/translations/fr/common.json +++ b/i18n/translations/fr/common.json @@ -227,6 +227,12 @@ "title": "Start again FR", "description": "Fill out a blank form FR" } + }, + "prompt": { + "title": "Save your progress [FR]", + "description": "Warning you are responsible for protecting the downloaded file. If you lose it, you will not be able to resume your form. [FR]", + "okay": "Okay [FR]", + "cancel": "Cancel [FR]" } } }