From 0b6f59ddebf48e85e5d053830a7c2411be08558f Mon Sep 17 00:00:00 2001 From: Eric Ribeiro Date: Mon, 27 Nov 2023 16:50:02 -0800 Subject: [PATCH] fix: error message --- .../src/components/Form/Item/View.js | 539 ++++++++++++++++++ 1 file changed, 539 insertions(+) create mode 100644 forms-flow-ai/forms-flow-ai-ee/forms-flow-web/src/components/Form/Item/View.js diff --git a/forms-flow-ai/forms-flow-ai-ee/forms-flow-web/src/components/Form/Item/View.js b/forms-flow-ai/forms-flow-ai-ee/forms-flow-web/src/components/Form/Item/View.js new file mode 100644 index 00000000..cccd5ec8 --- /dev/null +++ b/forms-flow-ai/forms-flow-ai-ee/forms-flow-web/src/components/Form/Item/View.js @@ -0,0 +1,539 @@ +import React, { useCallback, useEffect, useRef, useState } from "react"; +import { Link, useParams } from "react-router-dom"; +import { push } from "connected-react-router"; +import { connect, useDispatch, useSelector } from "react-redux"; +import { + selectRoot, + resetSubmissions, + saveSubmission, + Form, + selectError, + Errors, + getForm, + Formio, +} from "react-formio"; +import { useTranslation, Translation } from "react-i18next"; +import isEqual from "lodash/isEqual"; + +import Loading from "../../../containers/Loading"; +import { + getProcessReq, + getDraftReqFormat, +} from "../../../apiManager/services/bpmServices"; +import { formio_resourceBundles } from "../../../resourceBundles/formio_resourceBundles"; +import { + setFormFailureErrorData, + setFormRequestData, + setFormSubmissionError, + setFormSubmissionLoading, + setFormSuccessData, + setMaintainBPMFormPagination, +} from "../../../actions/formActions"; +import SubmissionError from "../../../containers/SubmissionError"; +import { publicApplicationStatus } from "../../../apiManager/services/applicationServices"; +import LoadingOverlay from "react-loading-overlay"; +import { CUSTOM_EVENT_TYPE } from "../../ServiceFlow/constants/customEventTypes"; +import { toast } from "react-toastify"; +import { setFormSubmitted } from "../../../actions/formActions"; +import { fetchFormByAlias } from "../../../apiManager/services/bpmFormServices"; +import { checkIsObjectId } from "../../../apiManager/services/formatterService"; +import { + draftCreate, + draftUpdate, + publicDraftCreate, + publicDraftUpdate, +} from "../../../apiManager/services/draftService"; +import { setPublicStatusLoading } from "../../../actions/applicationActions"; +import { postCustomSubmission } from "../../../apiManager/services/FormServices"; +import { + CUSTOM_SUBMISSION_URL, + CUSTOM_SUBMISSION_ENABLE, + MULTITENANCY_ENABLED, + DRAFT_ENABLED, + DRAFT_POLLING_RATE, +} from "../../../constants/constants"; +import useInterval from "../../../customHooks/useInterval"; +import selectApplicationCreateAPI from "./apiSelectHelper"; +import { + getApplicationCount, + getFormProcesses, +} from "../../../apiManager/services/processServices"; +import { setFormStatusLoading } from "../../../actions/processActions"; +import SavingLoading from "../../Loading/SavingLoading"; +//import NotFound from "../../NotFound/"; +import { renderPage } from "../../../helper/helper"; + +const View = React.memo((props) => { + const [formStatus, setFormStatus] = React.useState(""); + const { t } = useTranslation(); + const lang = useSelector((state) => state.user.lang); + const pubSub = useSelector((state) => state.pubSub); + const formStatusLoading = useSelector( + (state) => state.process?.formStatusLoading + ); + const isFormSubmissionLoading = useSelector( + (state) => state.formDelete.isFormSubmissionLoading + ); + const isPublicStatusLoading = useSelector( + (state) => state.applications.isPublicStatusLoading + ); + + const isFormSubmitted = useSelector( + (state) => state.formDelete.formSubmitted + ); + const publicFormStatus = useSelector( + (state) => state.formDelete.publicFormStatus + ); + const draftSubmissionId = useSelector( + (state) => state.draft.draftSubmission?.id + ); + // Holds the latest data saved by the server + const processLoadError = useSelector((state) => state.process?.processLoadError); + const lastUpdatedDraft = useSelector((state) => state.draft.lastUpdated); + const isPublic = !props.isAuthenticated; + const tenantKey = useSelector((state) => state.tenants?.tenantId); + const redirectUrl = MULTITENANCY_ENABLED ? `/tenant/${tenantKey}/` : "/"; + /** + * `draftData` is used for keeping the uptodate form entry, + * this will get updated on every change the form is having. + */ + const [draftData, setDraftData] = useState({}); + const draftRef = useRef(); + const [isDraftCreated, setIsDraftCreated] = useState(false); + + const { formId } = useParams(); + const [validFormId, setValidFormId] = useState(undefined); + + const [showPublicForm, setShowPublicForm] = useState("checking"); + const [poll, setPoll] = useState(DRAFT_ENABLED); + const exitType = useRef("UNMOUNT"); + const [draftSaved, setDraftSaved] = useState(false); + const [notified, setNotified] = useState(false); + const { + isAuthenticated, + submission, + hideComponents, + onSubmit, + onCustomEvent, + errors, + options, + form: { form, isActive, url, error }, + } = props; + + const [isValidResource, setIsValidResource] = useState(false); + + const dispatch = useDispatch(); + /* + Selecting which endpoint to use based on authentication status, + public endpoint or authenticated endpoint. + */ + const draftCreateMethod = isAuthenticated ? draftCreate : publicDraftCreate; + const draftUpdateMethod = isAuthenticated ? draftUpdate : publicDraftUpdate; + + const getPublicForm = useCallback( + (form_id, isObjectId, formObj) => { + dispatch(setPublicStatusLoading(true)); + dispatch( + publicApplicationStatus(form_id, (err) => { + dispatch(setPublicStatusLoading(false)); + if (!err) { + if (isPublic) { + if (isObjectId) { + dispatch(getForm("form", form_id)); + dispatch(setFormStatusLoading(false)); + } else { + dispatch( + setFormRequestData( + "form", + form_id, + `${Formio.getProjectUrl()}/form/${form_id}` + ) + ); + dispatch(setFormSuccessData("form", formObj)); + dispatch(setFormStatusLoading(false)); + } + } + } + }) + ); + }, + [dispatch, isPublic] + ); + const getFormData = useCallback(() => { + const isObjectId = checkIsObjectId(formId); + if (isObjectId) { + getPublicForm(formId, isObjectId); + setValidFormId(formId); + } else { + dispatch( + fetchFormByAlias(formId, async (err, formObj) => { + if (!err) { + const form_id = formObj._id; + getPublicForm(form_id, isObjectId, formObj); + setValidFormId(form_id); + } else { + dispatch(setFormFailureErrorData("form", err)); + } + }) + ); + } + }, [formId, dispatch, getPublicForm]); + /** + * Compares the current form data and last saved data + * Draft is updated only if the form is updated from the last saved form data. + */ + const saveDraft = (payload, exitType = exitType) => { + if (exitType === "SUBMIT") return; + let dataChanged = !isEqual(payload.data, lastUpdatedDraft.data); + if (draftSubmissionId && isDraftCreated) { + if (dataChanged) { + setDraftSaved(false); + dispatch( + draftUpdateMethod(payload, draftSubmissionId, (err) => { + if (exitType === "UNMOUNT" && !err && isAuthenticated) { + toast.success(t("Submission saved to draft.")); + } + if (!err) { + setDraftSaved(true); + } else { + setDraftSaved(false); + } + }) + ); + } + } + }; + + useEffect(() => { + if (form._id && !error) setIsValidResource(true); + return () => setIsValidResource(false); + }, [error, form._id]); + + useEffect(() => { + setTimeout(() => { + setNotified(true); + }, 5000); + }, []); + + useEffect(() => { + if (isDraftCreated) { + setDraftSaved(true); + } + }, [isDraftCreated]); + + /** + * Will create a draft application when the form is selected for entry. + */ + useEffect(() => { + if ( + validFormId && + DRAFT_ENABLED && + isValidResource && + ((isAuthenticated && formStatus === "active") || + (!isAuthenticated && publicFormStatus?.status == "active")) + ) { + let payload = getDraftReqFormat(validFormId, draftData?.data); + dispatch(draftCreateMethod(payload, setIsDraftCreated)); + } + }, [validFormId, formStatus, publicFormStatus, isValidResource]); + + /** + * We will repeatedly update the current state to draft table + * on purticular interval + */ + useInterval( + () => { + let payload = getDraftReqFormat(validFormId, { ...draftData?.data }); + saveDraft(payload); + }, + poll ? DRAFT_POLLING_RATE : null + ); + + /** + * Save the current state when the component unmounts. + * Save the data before submission to handle submission failure. + */ + useEffect(() => { + return () => { + let payload = getDraftReqFormat(validFormId, draftRef.current?.data); + if (poll) saveDraft(payload, exitType.current); + }; + }, [validFormId, draftSubmissionId, isDraftCreated, poll, exitType.current]); + + useEffect(() => { + if (isAuthenticated) { + dispatch(setFormStatusLoading(true)); + dispatch( + getFormProcesses(formId, (err, data) => { + if (!err) { + dispatch(getApplicationCount(data.id)); + setFormStatus(data.status); + dispatch(setFormStatusLoading(false)); + }else{ + dispatch(setFormStatusLoading(false)); + } + }) + ); + } + }, [isAuthenticated]); + + useEffect(() => { + if (isPublic) { + getFormData(); + } else { + setValidFormId(formId); + } + }, [isPublic, dispatch, getFormData]); + + useEffect(() => { + if (publicFormStatus) { + if ( + publicFormStatus.anonymous === true && + publicFormStatus.status === "active" + ) { + setShowPublicForm(true); + } else { + setShowPublicForm(false); + } + } + }, [publicFormStatus]); + + useEffect(()=>{ + if(pubSub.publish){ + pubSub.publish('ES_FORM', form); + } + },[form, pubSub.publish]); + + if (isActive || isPublicStatusLoading || formStatusLoading) { + return ( +
+ +
+ ); + } + + if (isFormSubmitted && !isAuthenticated) { + return ( +
+

{t("Thank you for your response.")}

+

{t("saved successfully")}

+
+ ); + } + + if (isPublic && !showPublicForm) { + return ( +
+ {t("Form not available")} +
+ ); + } + return ( +
+ {DRAFT_ENABLED && + isAuthenticated && + isValidResource && + (formStatus === "active" || + (publicFormStatus?.anonymous === true && + publicFormStatus?.status === "active")) && ( + <> + + {!notified && ( + + + {t( + "Unfinished applications will be saved to Applications/Drafts." + )} + + )} + + {notified && poll && ( + + )} + + + )} +
+
+ + {isAuthenticated ? ( + + + + ) : null} + + {form.title ? ( +

+ +