From fee107ba5d410a1eb778a91b41b691f5408039a5 Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Fri, 14 Jun 2024 12:03:56 -0400 Subject: [PATCH 01/29] Add env variables and update config for 2024 forms --- app/server/.env.example | 7 +++++++ app/server/app/config/formio.js | 18 ++++++++++++++++++ app/server/app/index.js | 7 +++++++ 3 files changed, 32 insertions(+) diff --git a/app/server/.env.example b/app/server/.env.example index 271ded31..088b05b6 100644 --- a/app/server/.env.example +++ b/app/server/.env.example @@ -16,6 +16,9 @@ CSB_2022_CRF_OPEN=true CSB_2023_FRF_OPEN=true CSB_2023_PRF_OPEN=true CSB_2023_CRF_OPEN=true +CSB_2024_FRF_OPEN=true +CSB_2024_PRF_OPEN=true +CSB_2024_CRF_OPEN=true FORMIO_2022_FRF_PATH= FORMIO_2022_PRF_PATH= FORMIO_2022_CRF_PATH= @@ -23,6 +26,10 @@ FORMIO_2023_FRF_PATH= FORMIO_2023_PRF_PATH= FORMIO_2023_CRF_PATH= FORMIO_2023_CHANGE_PATH= +FORMIO_2024_FRF_PATH= +FORMIO_2024_PRF_PATH= +FORMIO_2024_CRF_PATH= +FORMIO_2024_CHANGE_PATH= FORMIO_BASE_URL= FORMIO_PROJECT_NAME= FORMIO_API_KEY= diff --git a/app/server/app/config/formio.js b/app/server/app/config/formio.js index 63f44fd6..f3b3e00f 100644 --- a/app/server/app/config/formio.js +++ b/app/server/app/config/formio.js @@ -12,6 +12,9 @@ const { CSB_2023_FRF_OPEN, CSB_2023_PRF_OPEN, CSB_2023_CRF_OPEN, + CSB_2024_FRF_OPEN, + CSB_2024_PRF_OPEN, + CSB_2024_CRF_OPEN, FORMIO_BASE_URL, FORMIO_PROJECT_NAME, FORMIO_API_KEY, @@ -22,6 +25,10 @@ const { FORMIO_2023_PRF_PATH, FORMIO_2023_CRF_PATH, FORMIO_2023_CHANGE_PATH, + FORMIO_2024_FRF_PATH, + FORMIO_2024_PRF_PATH, + FORMIO_2024_CRF_PATH, + FORMIO_2024_CHANGE_PATH, } = process.env; const formioProjectUrl = `${FORMIO_BASE_URL}/${FORMIO_PROJECT_NAME}`; @@ -42,6 +49,12 @@ const formUrl = { crf: `${formioProjectUrl}/${FORMIO_2023_CRF_PATH}`, change: `${formioProjectUrl}/${FORMIO_2023_CHANGE_PATH}`, }, + 2024: { + frf: `${formioProjectUrl}/${FORMIO_2024_FRF_PATH}`, + prf: `${formioProjectUrl}/${FORMIO_2024_PRF_PATH}`, + crf: `${formioProjectUrl}/${FORMIO_2024_CRF_PATH}`, + change: `${formioProjectUrl}/${FORMIO_2024_CHANGE_PATH}`, + }, }; /** @@ -58,6 +71,11 @@ const submissionPeriodOpen = { prf: CSB_2023_PRF_OPEN === "true", crf: CSB_2023_CRF_OPEN === "true", }, + 2024: { + frf: CSB_2024_FRF_OPEN === "true", + prf: CSB_2024_PRF_OPEN === "true", + crf: CSB_2024_CRF_OPEN === "true", + }, }; /** @param {express.Request} req */ diff --git a/app/server/app/index.js b/app/server/app/index.js index 34336562..97dfd791 100644 --- a/app/server/app/index.js +++ b/app/server/app/index.js @@ -35,6 +35,9 @@ const requiredEnvironmentVariables = [ "CSB_2023_FRF_OPEN", "CSB_2023_PRF_OPEN", "CSB_2023_CRF_OPEN", + "CSB_2024_FRF_OPEN", + "CSB_2024_PRF_OPEN", + "CSB_2024_CRF_OPEN", "FORMIO_2022_FRF_PATH", "FORMIO_2022_PRF_PATH", "FORMIO_2022_CRF_PATH", @@ -42,6 +45,10 @@ const requiredEnvironmentVariables = [ "FORMIO_2023_PRF_PATH", "FORMIO_2023_CRF_PATH", "FORMIO_2023_CHANGE_PATH", + "FORMIO_2024_FRF_PATH", + "FORMIO_2024_PRF_PATH", + "FORMIO_2024_CRF_PATH", + "FORMIO_2024_CHANGE_PATH", "FORMIO_BASE_URL", "FORMIO_PROJECT_NAME", "FORMIO_API_KEY", From ca161a37eb747e47d925c94d443823dfaa47fde9 Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Fri, 14 Jun 2024 12:07:43 -0400 Subject: [PATCH 02/29] Update GitHub Actions workflows to support 2024 forms env variables --- .github/workflows/dev.yml | 14 ++++++++++++++ .github/workflows/staging.yml | 14 ++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml index ab584b7e..8cf703eb 100644 --- a/.github/workflows/dev.yml +++ b/.github/workflows/dev.yml @@ -47,6 +47,9 @@ jobs: CSB_2023_FRF_OPEN: true CSB_2023_PRF_OPEN: true CSB_2023_CRF_OPEN: true + CSB_2024_FRF_OPEN: true + CSB_2024_PRF_OPEN: true + CSB_2024_CRF_OPEN: true FORMIO_2022_FRF_PATH: ${{ secrets.FORMIO_2022_FRF_PATH }} FORMIO_2022_PRF_PATH: ${{ secrets.FORMIO_2022_PRF_PATH }} FORMIO_2022_CRF_PATH: ${{ secrets.FORMIO_2022_CRF_PATH }} @@ -54,6 +57,10 @@ jobs: FORMIO_2023_PRF_PATH: ${{ secrets.FORMIO_2023_PRF_PATH }} FORMIO_2023_CRF_PATH: ${{ secrets.FORMIO_2023_CRF_PATH }} FORMIO_2023_CHANGE_PATH: ${{ secrets.FORMIO_2023_CHANGE_PATH }} + FORMIO_2024_FRF_PATH: ${{ secrets.FORMIO_2024_FRF_PATH }} + FORMIO_2024_PRF_PATH: ${{ secrets.FORMIO_2024_PRF_PATH }} + FORMIO_2024_CRF_PATH: ${{ secrets.FORMIO_2024_CRF_PATH }} + FORMIO_2024_CHANGE_PATH: ${{ secrets.FORMIO_2024_CHANGE_PATH }} FORMIO_BASE_URL: ${{ secrets.FORMIO_BASE_URL }} FORMIO_PROJECT_NAME: ${{ secrets.FORMIO_PROJECT_NAME }} FORMIO_API_KEY: ${{ secrets.FORMIO_API_KEY }} @@ -133,6 +140,9 @@ jobs: cf set-env $APP_NAME "CSB_2023_FRF_OPEN" "$CSB_2023_FRF_OPEN" > /dev/null cf set-env $APP_NAME "CSB_2023_PRF_OPEN" "$CSB_2023_PRF_OPEN" > /dev/null cf set-env $APP_NAME "CSB_2023_CRF_OPEN" "$CSB_2023_CRF_OPEN" > /dev/null + cf set-env $APP_NAME "CSB_2024_FRF_OPEN" "$CSB_2024_FRF_OPEN" > /dev/null + cf set-env $APP_NAME "CSB_2024_PRF_OPEN" "$CSB_2024_PRF_OPEN" > /dev/null + cf set-env $APP_NAME "CSB_2024_CRF_OPEN" "$CSB_2024_CRF_OPEN" > /dev/null cf set-env $APP_NAME "FORMIO_2022_FRF_PATH" "$FORMIO_2022_FRF_PATH" > /dev/null cf set-env $APP_NAME "FORMIO_2022_PRF_PATH" "$FORMIO_2022_PRF_PATH" > /dev/null cf set-env $APP_NAME "FORMIO_2022_CRF_PATH" "$FORMIO_2022_CRF_PATH" > /dev/null @@ -140,6 +150,10 @@ jobs: cf set-env $APP_NAME "FORMIO_2023_PRF_PATH" "$FORMIO_2023_PRF_PATH" > /dev/null cf set-env $APP_NAME "FORMIO_2023_CRF_PATH" "$FORMIO_2023_CRF_PATH" > /dev/null cf set-env $APP_NAME "FORMIO_2023_CHANGE_PATH" "$FORMIO_2023_CHANGE_PATH" > /dev/null + cf set-env $APP_NAME "FORMIO_2024_FRF_PATH" "$FORMIO_2024_FRF_PATH" > /dev/null + cf set-env $APP_NAME "FORMIO_2024_PRF_PATH" "$FORMIO_2024_PRF_PATH" > /dev/null + cf set-env $APP_NAME "FORMIO_2024_CRF_PATH" "$FORMIO_2024_CRF_PATH" > /dev/null + cf set-env $APP_NAME "FORMIO_2024_CHANGE_PATH" "$FORMIO_2024_CHANGE_PATH" > /dev/null cf set-env $APP_NAME "FORMIO_BASE_URL" "$FORMIO_BASE_URL" > /dev/null cf set-env $APP_NAME "FORMIO_PROJECT_NAME" "$FORMIO_PROJECT_NAME" > /dev/null cf set-env $APP_NAME "FORMIO_API_KEY" "$FORMIO_API_KEY" > /dev/null diff --git a/.github/workflows/staging.yml b/.github/workflows/staging.yml index b2b6d5e7..873b3d80 100644 --- a/.github/workflows/staging.yml +++ b/.github/workflows/staging.yml @@ -47,6 +47,9 @@ jobs: CSB_2023_FRF_OPEN: true CSB_2023_PRF_OPEN: true CSB_2023_CRF_OPEN: true + CSB_2024_FRF_OPEN: true + CSB_2024_PRF_OPEN: true + CSB_2024_CRF_OPEN: true FORMIO_2022_FRF_PATH: ${{ secrets.FORMIO_2022_FRF_PATH }} FORMIO_2022_PRF_PATH: ${{ secrets.FORMIO_2022_PRF_PATH }} FORMIO_2022_CRF_PATH: ${{ secrets.FORMIO_2022_CRF_PATH }} @@ -54,6 +57,10 @@ jobs: FORMIO_2023_PRF_PATH: ${{ secrets.FORMIO_2023_PRF_PATH }} FORMIO_2023_CRF_PATH: ${{ secrets.FORMIO_2023_CRF_PATH }} FORMIO_2023_CHANGE_PATH: ${{ secrets.FORMIO_2023_CHANGE_PATH }} + FORMIO_2024_FRF_PATH: ${{ secrets.FORMIO_2024_FRF_PATH }} + FORMIO_2024_PRF_PATH: ${{ secrets.FORMIO_2024_PRF_PATH }} + FORMIO_2024_CRF_PATH: ${{ secrets.FORMIO_2024_CRF_PATH }} + FORMIO_2024_CHANGE_PATH: ${{ secrets.FORMIO_2024_CHANGE_PATH }} FORMIO_BASE_URL: ${{ secrets.FORMIO_BASE_URL }} FORMIO_PROJECT_NAME: ${{ secrets.FORMIO_PROJECT_NAME }} FORMIO_API_KEY: ${{ secrets.FORMIO_API_KEY }} @@ -133,6 +140,9 @@ jobs: cf set-env $APP_NAME "CSB_2023_FRF_OPEN" "$CSB_2023_FRF_OPEN" > /dev/null cf set-env $APP_NAME "CSB_2023_PRF_OPEN" "$CSB_2023_PRF_OPEN" > /dev/null cf set-env $APP_NAME "CSB_2023_CRF_OPEN" "$CSB_2023_CRF_OPEN" > /dev/null + cf set-env $APP_NAME "CSB_2024_FRF_OPEN" "$CSB_2024_FRF_OPEN" > /dev/null + cf set-env $APP_NAME "CSB_2024_PRF_OPEN" "$CSB_2024_PRF_OPEN" > /dev/null + cf set-env $APP_NAME "CSB_2024_CRF_OPEN" "$CSB_2024_CRF_OPEN" > /dev/null cf set-env $APP_NAME "FORMIO_2022_FRF_PATH" "$FORMIO_2022_FRF_PATH" > /dev/null cf set-env $APP_NAME "FORMIO_2022_PRF_PATH" "$FORMIO_2022_PRF_PATH" > /dev/null cf set-env $APP_NAME "FORMIO_2022_CRF_PATH" "$FORMIO_2022_CRF_PATH" > /dev/null @@ -140,6 +150,10 @@ jobs: cf set-env $APP_NAME "FORMIO_2023_PRF_PATH" "$FORMIO_2023_PRF_PATH" > /dev/null cf set-env $APP_NAME "FORMIO_2023_CRF_PATH" "$FORMIO_2023_CRF_PATH" > /dev/null cf set-env $APP_NAME "FORMIO_2023_CHANGE_PATH" "$FORMIO_2023_CHANGE_PATH" > /dev/null + cf set-env $APP_NAME "FORMIO_2024_FRF_PATH" "$FORMIO_2024_FRF_PATH" > /dev/null + cf set-env $APP_NAME "FORMIO_2024_PRF_PATH" "$FORMIO_2024_PRF_PATH" > /dev/null + cf set-env $APP_NAME "FORMIO_2024_CRF_PATH" "$FORMIO_2024_CRF_PATH" > /dev/null + cf set-env $APP_NAME "FORMIO_2024_CHANGE_PATH" "$FORMIO_2024_CHANGE_PATH" > /dev/null cf set-env $APP_NAME "FORMIO_BASE_URL" "$FORMIO_BASE_URL" > /dev/null cf set-env $APP_NAME "FORMIO_PROJECT_NAME" "$FORMIO_PROJECT_NAME" > /dev/null cf set-env $APP_NAME "FORMIO_API_KEY" "$FORMIO_API_KEY" > /dev/null From 5dd702c887ba8ed8d0f6c44326a5592b5278eca7 Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Fri, 14 Jun 2024 14:53:03 -0400 Subject: [PATCH 03/29] Reorder 2023 change request data types --- app/client/src/utilities.ts | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/app/client/src/utilities.ts b/app/client/src/utilities.ts index e9cee943..9a9b764b 100644 --- a/app/client/src/utilities.ts +++ b/app/client/src/utilities.ts @@ -130,20 +130,6 @@ type FormioSubmission = { }; }; -type FormioChange2023Data = { - [field: string]: unknown; - // fields injected upon a new draft Change Request form submission creation: - _request_form: FormType; - _bap_entity_combo_key: string; - _bap_rebate_id: string; - _mongo_id: string; - _user_email: string; - _user_title: string; - _user_name: string; - // fields set by the form definition (among others): - request_type: { label: string; value: string }; -}; - type FormioFRF2022Data = { [field: string]: unknown; // fields injected upon a new draft FRF submission creation: @@ -243,8 +229,18 @@ type FormioCRF2023Data = { _bap_rebate_id: string; }; -export type FormioChange2023Submission = FormioSubmission & { - data: FormioChange2023Data; +type FormioChange2023Data = { + [field: string]: unknown; + // fields injected upon a new draft Change Request form submission creation: + _request_form: FormType; + _bap_entity_combo_key: string; + _bap_rebate_id: string; + _mongo_id: string; + _user_email: string; + _user_title: string; + _user_name: string; + // fields set by the form definition (among others): + request_type: { label: string; value: string }; }; export type FormioFRF2022Submission = FormioSubmission & { @@ -271,6 +267,10 @@ export type FormioCRF2023Submission = FormioSubmission & { data: FormioCRF2023Data; }; +export type FormioChange2023Submission = FormioSubmission & { + data: FormioChange2023Data; +}; + export type BapSubmission = { modified: string | null; // ISO 8601 date time string comboKey: string | null; // UEI + EFTI combo key From f2b93feef81a478f0b231104c4439686994b40cb Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Fri, 14 Jun 2024 15:35:03 -0400 Subject: [PATCH 04/29] Move shared types out of utilities file and into types file --- app/client/src/components/change2023New.tsx | 3 +- app/client/src/routes/change2023.tsx | 7 +- app/client/src/routes/crf2022.tsx | 2 +- app/client/src/routes/frf2022.tsx | 2 +- app/client/src/routes/frf2023.tsx | 2 +- app/client/src/routes/frfNew.tsx | 4 +- app/client/src/routes/helpdesk.tsx | 17 +- app/client/src/routes/prf2022.tsx | 2 +- app/client/src/routes/prf2023.tsx | 2 +- app/client/src/routes/submissions.tsx | 16 +- app/client/src/types.ts | 310 +++++++++++++++++++ app/client/src/utilities.ts | 312 ++------------------ 12 files changed, 360 insertions(+), 319 deletions(-) create mode 100644 app/client/src/types.ts diff --git a/app/client/src/components/change2023New.tsx b/app/client/src/components/change2023New.tsx index ff439e9e..286b7b68 100644 --- a/app/client/src/components/change2023New.tsx +++ b/app/client/src/components/change2023New.tsx @@ -6,10 +6,9 @@ import { Form } from "@formio/react"; import clsx from "clsx"; import icons from "uswds/img/sprite.svg"; // --- +import { type FormType, type FormioChange2023Submission } from "@/types"; import { serverUrl, messages } from "@/config"; import { - type FormType, - type FormioChange2023Submission, getData, postData, useContentData, diff --git a/app/client/src/routes/change2023.tsx b/app/client/src/routes/change2023.tsx index e75b54e9..f6dea4a0 100644 --- a/app/client/src/routes/change2023.tsx +++ b/app/client/src/routes/change2023.tsx @@ -4,12 +4,9 @@ import { useQueryClient, useQuery } from "@tanstack/react-query"; import { Form } from "@formio/react"; import icons from "uswds/img/sprite.svg"; // --- +import { type FormioChange2023Submission } from "@/types"; import { serverUrl, messages } from "@/config"; -import { - type FormioChange2023Submission, - getData, - useContentData, -} from "@/utilities"; +import { getData, useContentData } from "@/utilities"; import { Loading } from "@/components/loading"; import { Message } from "@/components/message"; import { MarkdownContent } from "@/components/markdownContent"; diff --git a/app/client/src/routes/crf2022.tsx b/app/client/src/routes/crf2022.tsx index dcd17c38..d51dda30 100644 --- a/app/client/src/routes/crf2022.tsx +++ b/app/client/src/routes/crf2022.tsx @@ -8,9 +8,9 @@ import clsx from "clsx"; import { cloneDeep, isEqual } from "lodash"; import icons from "uswds/img/sprite.svg"; // --- +import { type FormioCRF2022Submission } from "@/types"; import { serverUrl, messages } from "@/config"; import { - type FormioCRF2022Submission, getData, postData, useContentData, diff --git a/app/client/src/routes/frf2022.tsx b/app/client/src/routes/frf2022.tsx index 57d99939..d79c45fc 100644 --- a/app/client/src/routes/frf2022.tsx +++ b/app/client/src/routes/frf2022.tsx @@ -8,9 +8,9 @@ import clsx from "clsx"; import { cloneDeep, isEqual } from "lodash"; import icons from "uswds/img/sprite.svg"; // --- +import { type FormioFRF2022Submission } from "@/types"; import { serverUrl, messages } from "@/config"; import { - type FormioFRF2022Submission, getData, postData, useContentData, diff --git a/app/client/src/routes/frf2023.tsx b/app/client/src/routes/frf2023.tsx index 92f2c021..88a177a4 100644 --- a/app/client/src/routes/frf2023.tsx +++ b/app/client/src/routes/frf2023.tsx @@ -8,9 +8,9 @@ import clsx from "clsx"; import { cloneDeep, isEqual } from "lodash"; import icons from "uswds/img/sprite.svg"; // --- +import { type FormioFRF2023Submission } from "@/types"; import { serverUrl, messages } from "@/config"; import { - type FormioFRF2023Submission, getData, postData, useContentData, diff --git a/app/client/src/routes/frfNew.tsx b/app/client/src/routes/frfNew.tsx index f75eef83..fa495505 100644 --- a/app/client/src/routes/frfNew.tsx +++ b/app/client/src/routes/frfNew.tsx @@ -5,11 +5,13 @@ import { XMarkIcon } from "@heroicons/react/24/outline"; import clsx from "clsx"; import icons from "uswds/img/sprite.svg"; // --- -import { serverUrl, messages } from "@/config"; import { type BapSamEntity, type FormioFRF2022Submission, type FormioFRF2023Submission, +} from "@/types"; +import { serverUrl, messages } from "@/config"; +import { postData, useContentData, useConfigData, diff --git a/app/client/src/routes/helpdesk.tsx b/app/client/src/routes/helpdesk.tsx index 37b3ebef..1acdca5e 100644 --- a/app/client/src/routes/helpdesk.tsx +++ b/app/client/src/routes/helpdesk.tsx @@ -11,6 +11,16 @@ import clsx from "clsx"; import icon from "uswds/img/usa-icons-bg/search--white.svg"; import icons from "uswds/img/sprite.svg"; // --- +import { + type FormType, + type BapSubmission, + type FormioFRF2022Submission, + type FormioPRF2022Submission, + type FormioCRF2022Submission, + type FormioFRF2023Submission, + type FormioPRF2023Submission, + // type FormioCRF2023Submission +} from "@/types"; import { serverUrl, messages, @@ -20,13 +30,6 @@ import { formioEmailField, } from "@/config"; import { - type FormType, - type FormioFRF2022Submission, - type FormioPRF2022Submission, - type FormioCRF2022Submission, - type FormioFRF2023Submission, - type FormioPRF2023Submission, - type BapSubmission, getData, postData, useContentData, diff --git a/app/client/src/routes/prf2022.tsx b/app/client/src/routes/prf2022.tsx index d9155e31..ecafc008 100644 --- a/app/client/src/routes/prf2022.tsx +++ b/app/client/src/routes/prf2022.tsx @@ -8,9 +8,9 @@ import clsx from "clsx"; import { cloneDeep, isEqual } from "lodash"; import icons from "uswds/img/sprite.svg"; // --- +import { type FormioPRF2022Submission } from "@/types"; import { serverUrl, messages } from "@/config"; import { - type FormioPRF2022Submission, getData, postData, useContentData, diff --git a/app/client/src/routes/prf2023.tsx b/app/client/src/routes/prf2023.tsx index f93247b5..6a3e4ef1 100644 --- a/app/client/src/routes/prf2023.tsx +++ b/app/client/src/routes/prf2023.tsx @@ -8,9 +8,9 @@ import clsx from "clsx"; import { cloneDeep, isEqual } from "lodash"; import icons from "uswds/img/sprite.svg"; // --- +import { type FormioPRF2023Submission } from "@/types"; import { serverUrl, messages } from "@/config"; import { - type FormioPRF2023Submission, getData, postData, useContentData, diff --git a/app/client/src/routes/submissions.tsx b/app/client/src/routes/submissions.tsx index 2ecff827..44f067b8 100644 --- a/app/client/src/routes/submissions.tsx +++ b/app/client/src/routes/submissions.tsx @@ -9,6 +9,15 @@ import { ChevronUpIcon } from "@heroicons/react/20/solid"; import clsx from "clsx"; import icons from "uswds/img/sprite.svg"; // --- +import { + type FormioFRF2022Submission, + type FormioPRF2022Submission, + type FormioCRF2022Submission, + type FormioFRF2023Submission, + type FormioPRF2023Submission, + // type FormioCRF2023Submission + type Rebate, +} from "@/types"; import { serverUrl, messages, @@ -17,13 +26,6 @@ import { statusIconMap, } from "@/config"; import { - type FormioFRF2022Submission, - type FormioPRF2022Submission, - type FormioCRF2022Submission, - type FormioFRF2023Submission, - type FormioPRF2023Submission, - // type FormioCRF2023Submission, - type Rebate, postData, useContentData, useConfigData, diff --git a/app/client/src/types.ts b/app/client/src/types.ts new file mode 100644 index 00000000..0738ea36 --- /dev/null +++ b/app/client/src/types.ts @@ -0,0 +1,310 @@ +export type RebateYear = "2022" | "2023"; + +export type FormType = "frf" | "prf" | "crf"; + +export type Content = { + siteAlert: string; + helpdeskIntro: string; + allRebatesIntro: string; + allRebatesOutro: string; + newFRFDialog: string; + draftFRFIntro: string; + submittedFRFIntro: string; + draftPRFIntro: string; + submittedPRFIntro: string; + draftCRFIntro: string; + submittedCRFIntro: string; + newChangeIntro: string; + submittedChangeIntro: string; +}; + +export type UserData = { + mail: string; + memberof: string; + exp: number; +}; + +export type ConfigData = { + submissionPeriodOpen: { + 2022: { frf: boolean; prf: boolean; crf: boolean }; + 2023: { frf: boolean; prf: boolean; crf: boolean }; + }; +}; + +export type BapSamEntity = { + Id: string; + ENTITY_COMBO_KEY__c: string; + UNIQUE_ENTITY_ID__c: string; + ENTITY_EFT_INDICATOR__c: string; + ENTITY_STATUS__c: "Active" | string; + LEGAL_BUSINESS_NAME__c: string; + PHYSICAL_ADDRESS_LINE_1__c: string; + PHYSICAL_ADDRESS_LINE_2__c: string | null; + PHYSICAL_ADDRESS_CITY__c: string; + PHYSICAL_ADDRESS_PROVINCE_OR_STATE__c: string; + PHYSICAL_ADDRESS_ZIPPOSTAL_CODE__c: string; + PHYSICAL_ADDRESS_ZIP_CODE_4__c: string; + // contacts + ELEC_BUS_POC_EMAIL__c: string | null; + ELEC_BUS_POC_NAME__c: string | null; + ELEC_BUS_POC_TITLE__c: string | null; + // + ALT_ELEC_BUS_POC_EMAIL__c: string | null; + ALT_ELEC_BUS_POC_NAME__c: string | null; + ALT_ELEC_BUS_POC_TITLE__c: string | null; + // + GOVT_BUS_POC_EMAIL__c: string | null; + GOVT_BUS_POC_NAME__c: string | null; + GOVT_BUS_POC_TITLE__c: string | null; + // + ALT_GOVT_BUS_POC_EMAIL__c: string | null; + ALT_GOVT_BUS_POC_NAME__c: string | null; + ALT_GOVT_BUS_POC_TITLE__c: string | null; + // + attributes: { type: string; url: string }; +}; + +export type BapSamData = + | { results: false; entities: [] } + | { results: true; entities: BapSamEntity[] }; + +export type BapFormSubmission = { + UEI_EFTI_Combo_Key__c: string; // UEI + EFTI combo key + CSB_Form_ID__c: string; // MongoDB ObjectId string + CSB_Modified_Full_String__c: string; // ISO 8601 date time string + CSB_Review_Item_ID__c: string; // CSB Rebate ID with form/version ID (9 digits) + Parent_Rebate_ID__c: string; // CSB Rebate ID (6 digits) + Record_Type_Name__c: /* + * NOTE: 2022 submissions don't have a year in their record type name, but + * we'll account for it here in case the BAP switches to using it in the future. + */ + | "CSB Funding Request" // NOTE: 2022 submissions + | "CSB Payment Request" // NOTE: 2022 submissions + | "CSB Close Out Request" // NOTE: 2022 submissions + | "CSB Funding Request 2022" // NOTE: not currently used + | "CSB Payment Request 2022" // NOTE: not currently used + | "CSB Close Out Request 2022" // NOTE: not currently used + | "CSB Funding Request 2023" + | "CSB Payment Request 2023" + | "CSB Close Out Request 2023"; + Rebate_Program_Year__c: null | RebateYear; + Parent_CSB_Rebate__r: { + CSB_Funding_Request_Status__c: string; + CSB_Payment_Request_Status__c: string; + CSB_Closeout_Request_Status__c: string; + attributes: { type: string; url: string }; + }; + attributes: { type: string; url: string }; +}; + +export type BapFormSubmissions = { + 2022: { + frfs: BapFormSubmission[]; + prfs: BapFormSubmission[]; + crfs: BapFormSubmission[]; + }; + 2023: { + frfs: BapFormSubmission[]; + prfs: BapFormSubmission[]; + crfs: BapFormSubmission[]; + }; +}; + +export type BapSubmission = { + modified: string | null; // ISO 8601 date time string + comboKey: string | null; // UEI + EFTI combo key + mongoId: string | null; // MongoDB Object ID + rebateId: string | null; // CSB Rebate ID (6 digits) + reviewItemId: string | null; // CSB Rebate ID with form/version ID (9 digits) + status: string | null; +}; + +export type FormioSubmission = { + [field: string]: unknown; + _id: string; // MongoDB ObjectId string – submission ID + form: string; // MongoDB ObjectId string – form ID + state: "submitted" | "draft"; + modified: string; // ISO 8601 date time string + metadata: { + [field: string]: unknown; + }; + data: { + [field: string]: unknown; + }; +}; + +type FormioFRF2022Data = { + [field: string]: unknown; + // fields injected upon a new draft FRF submission creation: + last_updated_by: string; + hidden_current_user_email: string; + hidden_current_user_title: string; + hidden_current_user_name: string; + bap_hidden_entity_combo_key: string; + sam_hidden_applicant_email: string; + sam_hidden_applicant_title: string; + sam_hidden_applicant_name: string; + sam_hidden_applicant_efti: string; + sam_hidden_applicant_uei: string; + sam_hidden_applicant_organization_name: string; + sam_hidden_applicant_street_address_1: string; + sam_hidden_applicant_street_address_2: string; + sam_hidden_applicant_city: string; + sam_hidden_applicant_state: string; + sam_hidden_applicant_zip_code: string; + // fields set by form definition (among others): + applicantUEI: string; + applicantEfti: string; + applicantEfti_display: string; + applicantOrganizationName: string; + schoolDistrictName: string; +}; + +type FormioPRF2022Data = { + [field: string]: unknown; + // fields injected upon a new draft PRF submission creation: + bap_hidden_entity_combo_key: string; + hidden_application_form_modified: string; // ISO 8601 date time string + hidden_current_user_email: string; + hidden_current_user_title: string; + hidden_current_user_name: string; + hidden_bap_rebate_id: string; + // fields set by form definition (among others): + applicantName: string; +}; + +type FormioCRF2022Data = { + [field: string]: unknown; + // fields injected upon a new draft CRF submission creation: + bap_hidden_entity_combo_key: string; + hidden_prf_modified: string; // ISO 8601 date time string + hidden_current_user_email: string; + hidden_current_user_title: string; + hidden_current_user_name: string; + hidden_bap_rebate_id: string; + // fields set by form definition (among others): + signatureName: string; +}; + +type FormioFRF2023Data = { + [field: string]: unknown; + // fields injected upon a new draft FRF submission creation: + _user_email: string; + _user_title: string; + _user_name: string; + _bap_entity_combo_key: string; + _bap_applicant_email: string; + _bap_applicant_title: string; + _bap_applicant_name: string; + _bap_applicant_efti: string; + _bap_applicant_uei: string; + _bap_applicant_organization_name: string; + _bap_applicant_street_address_1: string; + _bap_applicant_street_address_2: string; + _bap_applicant_city: string; + _bap_applicant_state: string; + _bap_applicant_zip: string; + // fields set by form definition (among others): + appInfo_uei: string; + appInfo_efti: string; + appInfo_orgName: string; + _formio_schoolDistrictName: string; +}; + +type FormioPRF2023Data = { + [field: string]: unknown; + // fields injected upon a new draft FRF submission creation: + _user_email: string; + _user_title: string; + _user_name: string; + _bap_entity_combo_key: string; + _bap_rebate_id: string; +}; + +type FormioCRF2023Data = { + [field: string]: unknown; + // fields injected upon a new draft FRF submission creation: + _user_email: string; + _user_title: string; + _user_name: string; + _bap_entity_combo_key: string; + _bap_rebate_id: string; +}; + +type FormioChange2023Data = { + [field: string]: unknown; + // fields injected upon a new draft Change Request form submission creation: + _request_form: FormType; + _bap_entity_combo_key: string; + _bap_rebate_id: string; + _mongo_id: string; + _user_email: string; + _user_title: string; + _user_name: string; + // fields set by the form definition (among others): + request_type: { label: string; value: string }; +}; + +type FormioFRF2024Data = { + [field: string]: unknown; + // fields injected upon a new draft FRF submission creation: + _user_email: string; + _user_title: string; + _user_name: string; + _bap_entity_combo_key: string; + _bap_applicant_email: string; + _bap_applicant_title: string; + _bap_applicant_name: string; + _bap_applicant_efti: string; + _bap_applicant_uei: string; + _bap_applicant_organization_name: string; + _bap_applicant_street_address_1: string; + _bap_applicant_street_address_2: string; + _bap_applicant_city: string; + _bap_applicant_state: string; + _bap_applicant_zip: string; +}; + +export type FormioFRF2022Submission = FormioSubmission & { + data: FormioFRF2022Data; +}; + +export type FormioPRF2022Submission = FormioSubmission & { + data: FormioPRF2022Data; +}; + +export type FormioCRF2022Submission = FormioSubmission & { + data: FormioCRF2022Data; +}; + +export type FormioFRF2023Submission = FormioSubmission & { + data: FormioFRF2023Data; +}; + +export type FormioPRF2023Submission = FormioSubmission & { + data: FormioPRF2023Data; +}; + +export type FormioCRF2023Submission = FormioSubmission & { + data: FormioCRF2023Data; +}; + +export type FormioChange2023Submission = FormioSubmission & { + data: FormioChange2023Data; +}; + +export type Rebate = { + rebateYear: RebateYear; + frf: { + formio: FormioFRF2022Submission | FormioFRF2023Submission; + bap: BapSubmission | null; + }; + prf: { + formio: FormioPRF2022Submission | FormioPRF2023Submission | null; + bap: BapSubmission | null; + }; + crf: { + formio: FormioCRF2022Submission | FormioCRF2023Submission | null; + bap: BapSubmission | null; + }; +}; diff --git a/app/client/src/utilities.ts b/app/client/src/utilities.ts index 9a9b764b..69466629 100644 --- a/app/client/src/utilities.ts +++ b/app/client/src/utilities.ts @@ -2,300 +2,28 @@ import { useEffect } from "react"; import { useQueryClient, useQuery, useQueries } from "@tanstack/react-query"; import { useSearchParams } from "react-router-dom"; // --- +import { + type RebateYear, + type Content, + type UserData, + type ConfigData, + type BapSamEntity, + type BapSamData, + type BapFormSubmission, + type BapFormSubmissions, + type BapSubmission, + type FormioSubmission, + type FormioFRF2022Submission, + type FormioPRF2022Submission, + type FormioCRF2022Submission, + type FormioFRF2023Submission, + type FormioPRF2023Submission, + type FormioCRF2023Submission, + type FormioChange2023Submission, + type Rebate, +} from "@/types"; import { serverUrl } from "@/config"; -type RebateYear = "2022" | "2023"; - -type Content = { - siteAlert: string; - helpdeskIntro: string; - allRebatesIntro: string; - allRebatesOutro: string; - newFRFDialog: string; - draftFRFIntro: string; - submittedFRFIntro: string; - draftPRFIntro: string; - submittedPRFIntro: string; - draftCRFIntro: string; - submittedCRFIntro: string; - newChangeIntro: string; - submittedChangeIntro: string; -}; - -type UserData = { - mail: string; - memberof: string; - exp: number; -}; - -type ConfigData = { - submissionPeriodOpen: { - 2022: { frf: boolean; prf: boolean; crf: boolean }; - 2023: { frf: boolean; prf: boolean; crf: boolean }; - }; -}; - -export type BapSamEntity = { - Id: string; - ENTITY_COMBO_KEY__c: string; - UNIQUE_ENTITY_ID__c: string; - ENTITY_EFT_INDICATOR__c: string; - ENTITY_STATUS__c: "Active" | string; - LEGAL_BUSINESS_NAME__c: string; - PHYSICAL_ADDRESS_LINE_1__c: string; - PHYSICAL_ADDRESS_LINE_2__c: string | null; - PHYSICAL_ADDRESS_CITY__c: string; - PHYSICAL_ADDRESS_PROVINCE_OR_STATE__c: string; - PHYSICAL_ADDRESS_ZIPPOSTAL_CODE__c: string; - PHYSICAL_ADDRESS_ZIP_CODE_4__c: string; - // contacts - ELEC_BUS_POC_EMAIL__c: string | null; - ELEC_BUS_POC_NAME__c: string | null; - ELEC_BUS_POC_TITLE__c: string | null; - // - ALT_ELEC_BUS_POC_EMAIL__c: string | null; - ALT_ELEC_BUS_POC_NAME__c: string | null; - ALT_ELEC_BUS_POC_TITLE__c: string | null; - // - GOVT_BUS_POC_EMAIL__c: string | null; - GOVT_BUS_POC_NAME__c: string | null; - GOVT_BUS_POC_TITLE__c: string | null; - // - ALT_GOVT_BUS_POC_EMAIL__c: string | null; - ALT_GOVT_BUS_POC_NAME__c: string | null; - ALT_GOVT_BUS_POC_TITLE__c: string | null; - // - attributes: { type: string; url: string }; -}; - -export type BapSamData = - | { results: false; entities: [] } - | { results: true; entities: BapSamEntity[] }; - -type BapFormSubmission = { - UEI_EFTI_Combo_Key__c: string; // UEI + EFTI combo key - CSB_Form_ID__c: string; // MongoDB ObjectId string - CSB_Modified_Full_String__c: string; // ISO 8601 date time string - CSB_Review_Item_ID__c: string; // CSB Rebate ID with form/version ID (9 digits) - Parent_Rebate_ID__c: string; // CSB Rebate ID (6 digits) - Record_Type_Name__c: /* - * NOTE: 2022 submissions don't have a year in their record type name, but - * we'll account for it here in case the BAP switches to using it in the future. - */ - | "CSB Funding Request" // NOTE: 2022 submissions - | "CSB Payment Request" // NOTE: 2022 submissions - | "CSB Close Out Request" // NOTE: 2022 submissions - | "CSB Funding Request 2022" // NOTE: not currently used - | "CSB Payment Request 2022" // NOTE: not currently used - | "CSB Close Out Request 2022" // NOTE: not currently used - | "CSB Funding Request 2023" - | "CSB Payment Request 2023" - | "CSB Close Out Request 2023"; - Rebate_Program_Year__c: null | RebateYear; - Parent_CSB_Rebate__r: { - CSB_Funding_Request_Status__c: string; - CSB_Payment_Request_Status__c: string; - CSB_Closeout_Request_Status__c: string; - attributes: { type: string; url: string }; - }; - attributes: { type: string; url: string }; -}; - -type BapFormSubmissions = { - 2022: { - frfs: BapFormSubmission[]; - prfs: BapFormSubmission[]; - crfs: BapFormSubmission[]; - }; - 2023: { - frfs: BapFormSubmission[]; - prfs: BapFormSubmission[]; - crfs: BapFormSubmission[]; - }; -}; - -export type FormType = "frf" | "prf" | "crf"; - -type FormioSubmission = { - [field: string]: unknown; - _id: string; // MongoDB ObjectId string – submission ID - form: string; // MongoDB ObjectId string – form ID - state: "submitted" | "draft"; - modified: string; // ISO 8601 date time string - metadata: { - [field: string]: unknown; - }; - data: { - [field: string]: unknown; - }; -}; - -type FormioFRF2022Data = { - [field: string]: unknown; - // fields injected upon a new draft FRF submission creation: - last_updated_by: string; - hidden_current_user_email: string; - hidden_current_user_title: string; - hidden_current_user_name: string; - bap_hidden_entity_combo_key: string; - sam_hidden_applicant_email: string; - sam_hidden_applicant_title: string; - sam_hidden_applicant_name: string; - sam_hidden_applicant_efti: string; - sam_hidden_applicant_uei: string; - sam_hidden_applicant_organization_name: string; - sam_hidden_applicant_street_address_1: string; - sam_hidden_applicant_street_address_2: string; - sam_hidden_applicant_city: string; - sam_hidden_applicant_state: string; - sam_hidden_applicant_zip_code: string; - // fields set by form definition (among others): - applicantUEI: string; - applicantEfti: string; - applicantEfti_display: string; - applicantOrganizationName: string; - schoolDistrictName: string; -}; - -type FormioPRF2022Data = { - [field: string]: unknown; - // fields injected upon a new draft PRF submission creation: - bap_hidden_entity_combo_key: string; - hidden_application_form_modified: string; // ISO 8601 date time string - hidden_current_user_email: string; - hidden_current_user_title: string; - hidden_current_user_name: string; - hidden_bap_rebate_id: string; - // fields set by form definition (among others): - applicantName: string; -}; - -type FormioCRF2022Data = { - [field: string]: unknown; - // fields injected upon a new draft CRF submission creation: - bap_hidden_entity_combo_key: string; - hidden_prf_modified: string; // ISO 8601 date time string - hidden_current_user_email: string; - hidden_current_user_title: string; - hidden_current_user_name: string; - hidden_bap_rebate_id: string; - // fields set by form definition (among others): - signatureName: string; -}; - -type FormioFRF2023Data = { - [field: string]: unknown; - // fields injected upon a new draft FRF submission creation: - _user_email: string; - _user_title: string; - _user_name: string; - _bap_entity_combo_key: string; - _bap_applicant_email: string; - _bap_applicant_title: string; - _bap_applicant_name: string; - _bap_applicant_efti: string; - _bap_applicant_uei: string; - _bap_applicant_organization_name: string; - _bap_applicant_street_address_1: string; - _bap_applicant_street_address_2: string; - _bap_applicant_city: string; - _bap_applicant_state: string; - _bap_applicant_zip: string; - // fields set by form definition (among others): - appInfo_uei: string; - appInfo_efti: string; - appInfo_orgName: string; - _formio_schoolDistrictName: string; -}; - -type FormioPRF2023Data = { - [field: string]: unknown; - // fields injected upon a new draft FRF submission creation: - _user_email: string; - _user_title: string; - _user_name: string; - _bap_entity_combo_key: string; - _bap_rebate_id: string; - // TODO: add more here if helpful -}; - -type FormioCRF2023Data = { - [field: string]: unknown; - // fields injected upon a new draft FRF submission creation: - _user_email: string; - _user_title: string; - _user_name: string; - _bap_entity_combo_key: string; - _bap_rebate_id: string; -}; - -type FormioChange2023Data = { - [field: string]: unknown; - // fields injected upon a new draft Change Request form submission creation: - _request_form: FormType; - _bap_entity_combo_key: string; - _bap_rebate_id: string; - _mongo_id: string; - _user_email: string; - _user_title: string; - _user_name: string; - // fields set by the form definition (among others): - request_type: { label: string; value: string }; -}; - -export type FormioFRF2022Submission = FormioSubmission & { - data: FormioFRF2022Data; -}; - -export type FormioPRF2022Submission = FormioSubmission & { - data: FormioPRF2022Data; -}; - -export type FormioCRF2022Submission = FormioSubmission & { - data: FormioCRF2022Data; -}; - -export type FormioFRF2023Submission = FormioSubmission & { - data: FormioFRF2023Data; -}; - -export type FormioPRF2023Submission = FormioSubmission & { - data: FormioPRF2023Data; -}; - -export type FormioCRF2023Submission = FormioSubmission & { - data: FormioCRF2023Data; -}; - -export type FormioChange2023Submission = FormioSubmission & { - data: FormioChange2023Data; -}; - -export type BapSubmission = { - modified: string | null; // ISO 8601 date time string - comboKey: string | null; // UEI + EFTI combo key - mongoId: string | null; // MongoDB Object ID - rebateId: string | null; // CSB Rebate ID (6 digits) - reviewItemId: string | null; // CSB Rebate ID with form/version ID (9 digits) - status: string | null; -}; - -export type Rebate = { - rebateYear: RebateYear; - frf: { - formio: FormioFRF2022Submission | FormioFRF2023Submission; - bap: BapSubmission | null; - }; - prf: { - formio: FormioPRF2022Submission | FormioPRF2023Submission | null; - bap: BapSubmission | null; - }; - crf: { - formio: FormioCRF2022Submission | FormioCRF2023Submission | null; - bap: BapSubmission | null; - }; -}; - async function fetchData(url: string, options: RequestInit) { try { const response = await fetch(url, options); From a228c57a58d29ca795fc542993ec2a05ee22c597 Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Fri, 14 Jun 2024 15:43:54 -0400 Subject: [PATCH 05/29] Rename type BapSubmission to BapSubmissionData --- app/client/src/routes/helpdesk.tsx | 8 ++++---- app/client/src/types.ts | 8 ++++---- app/client/src/utilities.ts | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/client/src/routes/helpdesk.tsx b/app/client/src/routes/helpdesk.tsx index 1acdca5e..ac0a8192 100644 --- a/app/client/src/routes/helpdesk.tsx +++ b/app/client/src/routes/helpdesk.tsx @@ -13,7 +13,7 @@ import icons from "uswds/img/sprite.svg"; // --- import { type FormType, - type BapSubmission, + type BapSubmissionData, type FormioFRF2022Submission, type FormioPRF2022Submission, type FormioCRF2022Submission, @@ -51,7 +51,7 @@ type ServerResponse = | { formSchema: null; formio: null; - bap: BapSubmission; + bap: BapSubmissionData; } | { formSchema: { url: string; json: object }; @@ -61,7 +61,7 @@ type ServerResponse = | FormioCRF2022Submission | FormioFRF2023Submission | FormioPRF2023Submission; - bap: BapSubmission; + bap: BapSubmissionData; }; type SubmissionAction = { @@ -127,7 +127,7 @@ function ResultTableRow(props: { | FormioCRF2022Submission | FormioFRF2023Submission | FormioPRF2023Submission; - bap: BapSubmission; + bap: BapSubmissionData; }) { const { setFormDisplayed, diff --git a/app/client/src/types.ts b/app/client/src/types.ts index 0738ea36..ea6b71ec 100644 --- a/app/client/src/types.ts +++ b/app/client/src/types.ts @@ -110,7 +110,7 @@ export type BapFormSubmissions = { }; }; -export type BapSubmission = { +export type BapSubmissionData = { modified: string | null; // ISO 8601 date time string comboKey: string | null; // UEI + EFTI combo key mongoId: string | null; // MongoDB Object ID @@ -297,14 +297,14 @@ export type Rebate = { rebateYear: RebateYear; frf: { formio: FormioFRF2022Submission | FormioFRF2023Submission; - bap: BapSubmission | null; + bap: BapSubmissionData | null; }; prf: { formio: FormioPRF2022Submission | FormioPRF2023Submission | null; - bap: BapSubmission | null; + bap: BapSubmissionData | null; }; crf: { formio: FormioCRF2022Submission | FormioCRF2023Submission | null; - bap: BapSubmission | null; + bap: BapSubmissionData | null; }; }; diff --git a/app/client/src/utilities.ts b/app/client/src/utilities.ts index 69466629..9baff415 100644 --- a/app/client/src/utilities.ts +++ b/app/client/src/utilities.ts @@ -11,7 +11,7 @@ import { type BapSamData, type BapFormSubmission, type BapFormSubmissions, - type BapSubmission, + type BapSubmissionData, type FormioSubmission, type FormioFRF2022Submission, type FormioPRF2022Submission, @@ -563,7 +563,7 @@ export function useSubmissions(rebateYear: RebateYear) { */ export function submissionNeedsEdits(options: { formio: FormioSubmission | null; - bap: BapSubmission | null; + bap: BapSubmissionData | null; }) { const { formio, bap } = options; From fe24c3446be46fad40d1893a78f8de0ba4d9f64e Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Fri, 14 Jun 2024 15:50:08 -0400 Subject: [PATCH 06/29] Update types to include 2024 formio and bap submission types --- app/client/src/types.ts | 78 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 73 insertions(+), 5 deletions(-) diff --git a/app/client/src/types.ts b/app/client/src/types.ts index ea6b71ec..d73a4a96 100644 --- a/app/client/src/types.ts +++ b/app/client/src/types.ts @@ -1,4 +1,4 @@ -export type RebateYear = "2022" | "2023"; +export type RebateYear = "2022" | "2023" | "2024"; export type FormType = "frf" | "prf" | "crf"; @@ -28,6 +28,7 @@ export type ConfigData = { submissionPeriodOpen: { 2022: { frf: boolean; prf: boolean; crf: boolean }; 2023: { frf: boolean; prf: boolean; crf: boolean }; + 2024: { frf: boolean; prf: boolean; crf: boolean }; }; }; @@ -86,7 +87,10 @@ export type BapFormSubmission = { | "CSB Close Out Request 2022" // NOTE: not currently used | "CSB Funding Request 2023" | "CSB Payment Request 2023" - | "CSB Close Out Request 2023"; + | "CSB Close Out Request 2023" + | "CSB Funding Request 2024" // TODO: confirm with BAP team + | "CSB Payment Request 2024" // TODO: confirm with BAP team + | "CSB Close Out Request 2024"; // TODO: confirm with BAP team Rebate_Program_Year__c: null | RebateYear; Parent_CSB_Rebate__r: { CSB_Funding_Request_Status__c: string; @@ -108,6 +112,11 @@ export type BapFormSubmissions = { prfs: BapFormSubmission[]; crfs: BapFormSubmission[]; }; + 2024: { + frfs: BapFormSubmission[]; + prfs: BapFormSubmission[]; + crfs: BapFormSubmission[]; + }; }; export type BapSubmissionData = { @@ -265,6 +274,38 @@ type FormioFRF2024Data = { _bap_applicant_zip: string; }; +type FormioPRF2024Data = { + [field: string]: unknown; + // fields injected upon a new draft FRF submission creation: + _user_email: string; + _user_title: string; + _user_name: string; + _bap_entity_combo_key: string; + _bap_rebate_id: string; +}; + +type FormioCRF2024Data = { + [field: string]: unknown; + // fields injected upon a new draft FRF submission creation: + _user_email: string; + _user_title: string; + _user_name: string; + _bap_entity_combo_key: string; + _bap_rebate_id: string; +}; + +type FormioChange2024Data = { + [field: string]: unknown; + // fields injected upon a new draft Change Request form submission creation: + _request_form: FormType; + _bap_entity_combo_key: string; + _bap_rebate_id: string; + _mongo_id: string; + _user_email: string; + _user_title: string; + _user_name: string; +}; + export type FormioFRF2022Submission = FormioSubmission & { data: FormioFRF2022Data; }; @@ -293,18 +334,45 @@ export type FormioChange2023Submission = FormioSubmission & { data: FormioChange2023Data; }; +export type FormioFRF2024Submission = FormioSubmission & { + data: FormioFRF2024Data; +}; + +export type FormioPRF2024Submission = FormioSubmission & { + data: FormioPRF2024Data; +}; + +export type FormioCRF2024Submission = FormioSubmission & { + data: FormioCRF2024Data; +}; + +export type FormioChange2024Submission = FormioSubmission & { + data: FormioChange2024Data; +}; + export type Rebate = { rebateYear: RebateYear; frf: { - formio: FormioFRF2022Submission | FormioFRF2023Submission; + formio: + | FormioFRF2022Submission + | FormioFRF2023Submission + | FormioFRF2024Submission; bap: BapSubmissionData | null; }; prf: { - formio: FormioPRF2022Submission | FormioPRF2023Submission | null; + formio: + | FormioPRF2022Submission + | FormioPRF2023Submission + | FormioPRF2024Submission + | null; bap: BapSubmissionData | null; }; crf: { - formio: FormioCRF2022Submission | FormioCRF2023Submission | null; + formio: + | FormioCRF2022Submission + | FormioCRF2023Submission + | FormioCRF2024Submission + | null; bap: BapSubmissionData | null; }; }; From 0eb6d50c2b130526f58072ee028f24963af7bbb5 Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Wed, 26 Jun 2024 11:37:32 -0400 Subject: [PATCH 07/29] Update ulitities to account for fetching 2024 forms data --- app/client/src/utilities.ts | 90 ++++++++++++++++++++++++++++++++----- 1 file changed, 79 insertions(+), 11 deletions(-) diff --git a/app/client/src/utilities.ts b/app/client/src/utilities.ts index 9baff415..59faaf22 100644 --- a/app/client/src/utilities.ts +++ b/app/client/src/utilities.ts @@ -20,6 +20,10 @@ import { type FormioPRF2023Submission, type FormioCRF2023Submission, type FormioChange2023Submission, + type FormioFRF2024Submission, + type FormioPRF2024Submission, + type FormioCRF2024Submission, + type FormioChange2024Submission, type Rebate, } from "@/types"; import { serverUrl } from "@/config"; @@ -163,6 +167,15 @@ export function useChangeRequestsQuery(rebateYear: RebateYear) { refetchOnWindowFocus: false, }; + const changeRequest2024Query = { + queryKey: ["formio/2024/changes"], + queryFn: () => { + const url = `${serverUrl}/api/formio/2024/changes`; + return getData(url); + }, + refetchOnWindowFocus: false, + }; + /* NOTE: Fallback (not used, as rebate year will match a query above) */ const changeRequestQuery = { queryKey: ["formio/changes"], @@ -175,7 +188,9 @@ export function useChangeRequestsQuery(rebateYear: RebateYear) { ? changeRequest2022Query : rebateYear === "2023" ? changeRequest2023Query - : changeRequestQuery; + : rebateYear === "2024" + ? changeRequest2024Query + : changeRequestQuery; return useQuery(query); } @@ -186,11 +201,17 @@ export function useChangeRequestsQuery(rebateYear: RebateYear) { */ export function useChangeRequestsData(rebateYear: RebateYear) { const queryClient = useQueryClient(); + const changeRequest2022Data = queryClient.getQueryData<[]>(["formio/2022/changes"]); // prettier-ignore + const changeRequest2023Data = queryClient.getQueryData(["formio/2023/changes"]); // prettier-ignore + const changeRequest2024Data = queryClient.getQueryData(["formio/2024/changes"]); // prettier-ignore + return rebateYear === "2022" - ? queryClient.getQueryData<[]>(["formio/2022/changes"]) + ? changeRequest2022Data : rebateYear === "2023" - ? queryClient.getQueryData(["formio/2023/changes"]) // prettier-ignore - : undefined; + ? changeRequest2023Data + : rebateYear === "2024" + ? changeRequest2024Data + : undefined; } /** Custom hook to fetch submissions from the BAP and Formio. */ @@ -237,6 +258,11 @@ export function useSubmissionsQueries(rebateYear: RebateYear) { prfs: [] as BapFormSubmission[], crfs: [] as BapFormSubmission[], }, + 2024: { + frfs: [] as BapFormSubmission[], + prfs: [] as BapFormSubmission[], + crfs: [] as BapFormSubmission[], + }, }, ); @@ -300,6 +326,33 @@ export function useSubmissionsQueries(rebateYear: RebateYear) { refetchOnWindowFocus: false, }; + const formioFRF2024Query = { + queryKey: ["formio/2024/frf-submissions"], + queryFn: () => { + const url = `${serverUrl}/api/formio/2024/frf-submissions`; + return getData(url); + }, + refetchOnWindowFocus: false, + }; + + const formioPRF2024Query = { + queryKey: ["formio/2024/prf-submissions"], + queryFn: () => { + const url = `${serverUrl}/api/formio/2024/prf-submissions`; + return getData(url); + }, + refetchOnWindowFocus: false, + }; + + const formioCRF2024Query = { + queryKey: ["formio/2024/crf-submissions"], + queryFn: () => { + const url = `${serverUrl}/api/formio/2024/crf-submissions`; + return getData(url); + }, + refetchOnWindowFocus: false, + }; + type Query = { queryKey: string[]; queryFn: () => @@ -309,7 +362,10 @@ export function useSubmissionsQueries(rebateYear: RebateYear) { | Promise | Promise | Promise - | Promise; + | Promise + | Promise + | Promise + | Promise; refetchOnWindowFocus: boolean; }; @@ -318,7 +374,9 @@ export function useSubmissionsQueries(rebateYear: RebateYear) { ? [bapQuery, formioFRF2022Query, formioPRF2022Query, formioCRF2022Query] : rebateYear === "2023" ? [bapQuery, formioFRF2023Query, formioPRF2023Query, formioCRF2023Query] - : []; + : rebateYear === "2024" + ? [bapQuery, formioFRF2024Query, formioPRF2024Query, formioCRF2024Query] // prettier-ignore + : []; return useQueries({ queries }); } @@ -338,21 +396,27 @@ function useCombinedSubmissions(rebateYear: RebateYear) { ? queryClient.getQueryData(["formio/2022/frf-submissions"]) // prettier-ignore : rebateYear === "2023" ? queryClient.getQueryData(["formio/2023/frf-submissions"]) // prettier-ignore - : undefined; + : rebateYear === "2024" + ? queryClient.getQueryData(["formio/2024/frf-submissions"]) // prettier-ignore + : undefined; const formioPRFSubmissions = rebateYear === "2022" ? queryClient.getQueryData(["formio/2022/prf-submissions"]) // prettier-ignore : rebateYear === "2023" ? queryClient.getQueryData(["formio/2023/prf-submissions"]) // prettier-ignore - : undefined; + : rebateYear === "2024" + ? queryClient.getQueryData(["formio/2024/prf-submissions"]) // prettier-ignore + : undefined; const formioCRFSubmissions = rebateYear === "2022" ? queryClient.getQueryData(["formio/2022/crf-submissions"]) // prettier-ignore : rebateYear === "2023" ? queryClient.getQueryData(["formio/2023/crf-submissions"]) // prettier-ignore - : undefined; + : rebateYear === "2024" + ? queryClient.getQueryData(["formio/2024/crf-submissions"]) // prettier-ignore + : undefined; const submissions: { [rebateId: string]: Rebate; @@ -415,7 +479,9 @@ function useCombinedSubmissions(rebateYear: RebateYear) { ? (formioPRFSubmission as FormioPRF2022Submission).data.hidden_bap_rebate_id // prettier-ignore : rebateYear === "2023" ? (formioPRFSubmission as FormioPRF2023Submission).data._bap_rebate_id - : null; + : rebateYear === "2024" + ? (formioPRFSubmission as FormioPRF2024Submission).data._bap_rebate_id // prettier-ignore + : null; const bapMatch = bapFormSubmissions[rebateYear].prfs.find((bapPRFSub) => { return bapPRFSub.Parent_Rebate_ID__c === formioBapRebateId; @@ -446,7 +512,9 @@ function useCombinedSubmissions(rebateYear: RebateYear) { ? (formioCRFSubmission as FormioCRF2022Submission).data.hidden_bap_rebate_id // prettier-ignore : rebateYear === "2023" ? (formioCRFSubmission as FormioCRF2023Submission).data._bap_rebate_id - : null; + : rebateYear === "2024" + ? (formioCRFSubmission as FormioCRF2024Submission).data._bap_rebate_id // prettier-ignore + : null; const bapMatch = bapFormSubmissions[rebateYear].crfs.find((bapCRFSub) => { return bapCRFSub.Parent_Rebate_ID__c === formioBapRebateId; From 2436445df951c99c55d9f9dba48747bddcb5197b Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Wed, 26 Jun 2024 15:24:16 -0400 Subject: [PATCH 08/29] Update config file to account for 2024 forms --- app/client/src/config.tsx | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/app/client/src/config.tsx b/app/client/src/config.tsx index 794f6962..3f0cb091 100644 --- a/app/client/src/config.tsx +++ b/app/client/src/config.tsx @@ -108,7 +108,12 @@ export const bapStatusMap = { .set("Withdrawn", "Withdrawn") .set("Coordinator Denied", "Funding Denied") .set("Accepted", "Funding Approved"), - crf: new Map(), + crf: new Map(), // TODO + }, + 2024: { + frf: new Map(), // TODO + prf: new Map(), // TODO + crf: new Map(), // TODO }, }; @@ -141,7 +146,12 @@ export const formioNameField = { 2023: { frf: "_user_name", prf: "_user_name", - crf: "", + crf: "", // TODO + }, + 2024: { + frf: "", // TODO + prf: "", // TODO + crf: "", // TODO }, }; @@ -157,6 +167,11 @@ export const formioEmailField = { 2023: { frf: "_user_email", prf: "_user_email", - crf: "", + crf: "", // TODO + }, + 2024: { + frf: "", // TODO + prf: "", // TODO + crf: "", // TODO }, }; From 7cb23ffc4615df5ceaee86bf3c34f66e38ba142a Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Wed, 26 Jun 2024 15:26:29 -0400 Subject: [PATCH 09/29] Update rebateYear context, helpdesk compmponent, and submissions component to use RebateYear type from types file, and add 2024 as a select option in the rebate year dropdown in both the helpdesk component and submissions component --- app/client/src/contexts/rebateYear.tsx | 4 ++-- app/client/src/routes/helpdesk.tsx | 3 ++- app/client/src/routes/submissions.tsx | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/client/src/contexts/rebateYear.tsx b/app/client/src/contexts/rebateYear.tsx index 9823eb38..495cad28 100644 --- a/app/client/src/contexts/rebateYear.tsx +++ b/app/client/src/contexts/rebateYear.tsx @@ -7,13 +7,13 @@ import { useContext, useReducer, } from "react"; +// --- +import { type RebateYear } from "@/types"; type Props = { children: ReactNode; }; -export type RebateYear = "2022" | "2023"; - type State = { rebateYear: RebateYear; }; diff --git a/app/client/src/routes/helpdesk.tsx b/app/client/src/routes/helpdesk.tsx index ac0a8192..9934b5c9 100644 --- a/app/client/src/routes/helpdesk.tsx +++ b/app/client/src/routes/helpdesk.tsx @@ -12,6 +12,7 @@ import icon from "uswds/img/usa-icons-bg/search--white.svg"; import icons from "uswds/img/sprite.svg"; // --- import { + type RebateYear, type FormType, type BapSubmissionData, type FormioFRF2022Submission, @@ -42,7 +43,6 @@ import { MarkdownContent } from "@/components/markdownContent"; import { TextWithTooltip } from "@/components/tooltip"; import { useDialogActions } from "@/contexts/dialog"; import { - type RebateYear, useRebateYearState, useRebateYearActions, } from "@/contexts/rebateYear"; @@ -456,6 +456,7 @@ export function Helpdesk() { > + diff --git a/app/client/src/routes/submissions.tsx b/app/client/src/routes/submissions.tsx index 44f067b8..afa4dc7f 100644 --- a/app/client/src/routes/submissions.tsx +++ b/app/client/src/routes/submissions.tsx @@ -10,6 +10,7 @@ import clsx from "clsx"; import icons from "uswds/img/sprite.svg"; // --- import { + type RebateYear, type FormioFRF2022Submission, type FormioPRF2022Submission, type FormioCRF2022Submission, @@ -44,7 +45,6 @@ import { TextWithTooltip } from "@/components/tooltip"; import { ChangeRequest2023Button } from "@/components/change2023New"; import { useNotificationsActions } from "@/contexts/notifications"; import { - type RebateYear, useRebateYearState, useRebateYearActions, } from "@/contexts/rebateYear"; @@ -1589,6 +1589,7 @@ export function Submissions() { > + From 987a9dbfc6ef8bc069d85f6fd2224a70eb965f9c Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Fri, 28 Jun 2024 09:59:17 -0400 Subject: [PATCH 10/29] Begin updating utility functions that deal with rebate year to return the correct typescript types --- app/client/src/utilities.ts | 38 ++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/app/client/src/utilities.ts b/app/client/src/utilities.ts index 59faaf22..267345df 100644 --- a/app/client/src/utilities.ts +++ b/app/client/src/utilities.ts @@ -28,6 +28,15 @@ import { } from "@/types"; import { serverUrl } from "@/config"; +/** + * Formio Change Request submissions by rebate year. + */ +interface FormioChangeSubmissions { + "2022": never[]; + "2023": FormioChange2023Submission[]; + "2024": FormioChange2024Submission[]; +} + async function fetchData(url: string, options: RequestInit) { try { const response = await fetch(url, options); @@ -147,7 +156,9 @@ export function useBapSamData() { } /** Custom hook to fetch Change Request form submissions from Formio. */ -export function useChangeRequestsQuery(rebateYear: RebateYear) { +export function useChangeRequestsQuery< + Year extends keyof FormioChangeSubmissions, +>(rebateYear: Year): UseQueryResult { /* * NOTE: Change Request form was added in the 2023 rebate year, so there's no * change request data to fetch for 2022. @@ -177,7 +188,7 @@ export function useChangeRequestsQuery(rebateYear: RebateYear) { }; /* NOTE: Fallback (not used, as rebate year will match a query above) */ - const changeRequestQuery = { + const changeRequestFallbackQuery = { queryKey: ["formio/changes"], queryFn: () => Promise.resolve([]), refetchOnWindowFocus: false, @@ -190,7 +201,7 @@ export function useChangeRequestsQuery(rebateYear: RebateYear) { ? changeRequest2023Query : rebateYear === "2024" ? changeRequest2024Query - : changeRequestQuery; + : changeRequestFallbackQuery; return useQuery(query); } @@ -199,19 +210,24 @@ export function useChangeRequestsQuery(rebateYear: RebateYear) { * Custom hook that returns cached fetched Change Request form submissions from * Formio. */ -export function useChangeRequestsData(rebateYear: RebateYear) { +export function useChangeRequestsData< + Year extends keyof FormioChangeSubmissions, +>(rebateYear: Year): FormioChangeSubmissions[Year] { const queryClient = useQueryClient(); const changeRequest2022Data = queryClient.getQueryData<[]>(["formio/2022/changes"]); // prettier-ignore const changeRequest2023Data = queryClient.getQueryData(["formio/2023/changes"]); // prettier-ignore const changeRequest2024Data = queryClient.getQueryData(["formio/2024/changes"]); // prettier-ignore - return rebateYear === "2022" - ? changeRequest2022Data - : rebateYear === "2023" - ? changeRequest2023Data - : rebateYear === "2024" - ? changeRequest2024Data - : undefined; + const result = + rebateYear === "2022" + ? changeRequest2022Data + : rebateYear === "2023" + ? changeRequest2023Data + : rebateYear === "2024" + ? changeRequest2024Data + : undefined; + + return result as FormioChangeSubmissions[Year]; } /** Custom hook to fetch submissions from the BAP and Formio. */ From 00f85ba900c1636af54a18a8d3ce12c2efd336d5 Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Fri, 28 Jun 2024 11:13:38 -0400 Subject: [PATCH 11/29] Update TypeScript types in utility functions to still take RebateYear as param in functions --- app/client/src/utilities.ts | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/app/client/src/utilities.ts b/app/client/src/utilities.ts index 267345df..a937b0f7 100644 --- a/app/client/src/utilities.ts +++ b/app/client/src/utilities.ts @@ -28,14 +28,13 @@ import { } from "@/types"; import { serverUrl } from "@/config"; -/** - * Formio Change Request submissions by rebate year. - */ -interface FormioChangeSubmissions { - "2022": never[]; - "2023": FormioChange2023Submission[]; - "2024": FormioChange2024Submission[]; -} +/** Formio Change Request submissions by rebate year. */ +/* prettier-ignore */ +type FormioChangeSubmissions = + Year extends "2022" ? never[] | undefined : + Year extends "2023" ? FormioChange2023Submission[] | undefined : + Year extends "2024" ? FormioChange2024Submission[] | undefined : + never; async function fetchData(url: string, options: RequestInit) { try { @@ -156,9 +155,9 @@ export function useBapSamData() { } /** Custom hook to fetch Change Request form submissions from Formio. */ -export function useChangeRequestsQuery< - Year extends keyof FormioChangeSubmissions, ->(rebateYear: Year): UseQueryResult { +export function useChangeRequestsQuery( + rebateYear: Year, +): UseQueryResult, unknown> { /* * NOTE: Change Request form was added in the 2023 rebate year, so there's no * change request data to fetch for 2022. @@ -210,10 +209,11 @@ export function useChangeRequestsQuery< * Custom hook that returns cached fetched Change Request form submissions from * Formio. */ -export function useChangeRequestsData< - Year extends keyof FormioChangeSubmissions, ->(rebateYear: Year): FormioChangeSubmissions[Year] { +export function useChangeRequestsData( + rebateYear: Year, +): FormioChangeSubmissions { const queryClient = useQueryClient(); + const changeRequest2022Data = queryClient.getQueryData<[]>(["formio/2022/changes"]); // prettier-ignore const changeRequest2023Data = queryClient.getQueryData(["formio/2023/changes"]); // prettier-ignore const changeRequest2024Data = queryClient.getQueryData(["formio/2024/changes"]); // prettier-ignore @@ -227,7 +227,7 @@ export function useChangeRequestsData< ? changeRequest2024Data : undefined; - return result as FormioChangeSubmissions[Year]; + return result as FormioChangeSubmissions; } /** Custom hook to fetch submissions from the BAP and Formio. */ From 76376fd6eb198cac3b10b511521d414daf297ac3 Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Mon, 1 Jul 2024 14:51:36 -0400 Subject: [PATCH 12/29] Rename FormioChangeSubmissions type to FormioChangeRequests --- app/client/src/utilities.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/client/src/utilities.ts b/app/client/src/utilities.ts index a937b0f7..74e5c30a 100644 --- a/app/client/src/utilities.ts +++ b/app/client/src/utilities.ts @@ -30,7 +30,7 @@ import { serverUrl } from "@/config"; /** Formio Change Request submissions by rebate year. */ /* prettier-ignore */ -type FormioChangeSubmissions = +type FormioChangeRequests = Year extends "2022" ? never[] | undefined : Year extends "2023" ? FormioChange2023Submission[] | undefined : Year extends "2024" ? FormioChange2024Submission[] | undefined : @@ -157,7 +157,7 @@ export function useBapSamData() { /** Custom hook to fetch Change Request form submissions from Formio. */ export function useChangeRequestsQuery( rebateYear: Year, -): UseQueryResult, unknown> { +): UseQueryResult> { /* * NOTE: Change Request form was added in the 2023 rebate year, so there's no * change request data to fetch for 2022. @@ -211,7 +211,7 @@ export function useChangeRequestsQuery( */ export function useChangeRequestsData( rebateYear: Year, -): FormioChangeSubmissions { +): FormioChangeRequests { const queryClient = useQueryClient(); const changeRequest2022Data = queryClient.getQueryData<[]>(["formio/2022/changes"]); // prettier-ignore @@ -227,7 +227,7 @@ export function useChangeRequestsData( ? changeRequest2024Data : undefined; - return result as FormioChangeSubmissions; + return result as FormioChangeRequests; } /** Custom hook to fetch submissions from the BAP and Formio. */ From 507ea1e6c1c4dbd39924c636e1d2f765c3de1a9e Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Mon, 1 Jul 2024 14:56:03 -0400 Subject: [PATCH 13/29] Update useSubmissionsQueries() to return the correct type, based on provided rebate year --- app/client/src/utilities.ts | 40 ++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/app/client/src/utilities.ts b/app/client/src/utilities.ts index 74e5c30a..a22e2d8a 100644 --- a/app/client/src/utilities.ts +++ b/app/client/src/utilities.ts @@ -1,5 +1,11 @@ import { useEffect } from "react"; -import { useQueryClient, useQuery, useQueries } from "@tanstack/react-query"; +import { + type UseQueryOptions, + type UseQueryResult, + useQueryClient, + useQuery, + useQueries, +} from "@tanstack/react-query"; import { useSearchParams } from "react-router-dom"; // --- import { @@ -36,6 +42,14 @@ type FormioChangeRequests = Year extends "2024" ? FormioChange2024Submission[] | undefined : never; +/** BAP and Formio submissions by rebate year. */ +/* prettier-ignore */ +type BapAndFormioSubmissions = + Year extends "2022" ? BapFormSubmissions | FormioFRF2022Submission[] | FormioPRF2022Submission[] | FormioCRF2022Submission[] : + Year extends "2023" ? BapFormSubmissions | FormioFRF2023Submission[] | FormioPRF2023Submission[] | FormioCRF2023Submission[] : + Year extends "2024" ? BapFormSubmissions | FormioFRF2024Submission[] | FormioPRF2024Submission[] | FormioCRF2024Submission[] : + never; + async function fetchData(url: string, options: RequestInit) { try { const response = await fetch(url, options); @@ -231,7 +245,9 @@ export function useChangeRequestsData( } /** Custom hook to fetch submissions from the BAP and Formio. */ -export function useSubmissionsQueries(rebateYear: RebateYear) { +export function useSubmissionsQueries( + rebateYear: Year, +): UseQueryResult>[] { const bapQuery = { queryKey: ["bap/submissions"], queryFn: () => { @@ -241,7 +257,7 @@ export function useSubmissionsQueries(rebateYear: RebateYear) { return Promise.reject(res); } - const submissions = res.reduce( + const submissions: BapFormSubmissions = res.reduce( (object, submission) => { const { Record_Type_Name__c, Rebate_Program_Year__c } = submission; @@ -369,23 +385,7 @@ export function useSubmissionsQueries(rebateYear: RebateYear) { refetchOnWindowFocus: false, }; - type Query = { - queryKey: string[]; - queryFn: () => - | Promise - | Promise - | Promise - | Promise - | Promise - | Promise - | Promise - | Promise - | Promise - | Promise; - refetchOnWindowFocus: boolean; - }; - - const queries: Query[] = + const queries: UseQueryOptions>[] = rebateYear === "2022" ? [bapQuery, formioFRF2022Query, formioPRF2022Query, formioCRF2022Query] : rebateYear === "2023" From f0fb73613021f2324470cfafdd1e906ecb5bd235 Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Wed, 3 Jul 2024 14:18:30 -0400 Subject: [PATCH 14/29] Update useSubmissionsQueries() so queries are properly typed, and update useChangeRequestQuery() to properly type query variable as well --- app/client/src/utilities.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/app/client/src/utilities.ts b/app/client/src/utilities.ts index a22e2d8a..4297ff69 100644 --- a/app/client/src/utilities.ts +++ b/app/client/src/utilities.ts @@ -207,7 +207,9 @@ export function useChangeRequestsQuery( refetchOnWindowFocus: false, }; - const query = + const query: UseQueryOptions< + BapAndFormioSubmissions<"2022" | "2023" | "2024"> + > = rebateYear === "2022" ? changeRequest2022Query : rebateYear === "2023" @@ -216,7 +218,7 @@ export function useChangeRequestsQuery( ? changeRequest2024Query : changeRequestFallbackQuery; - return useQuery(query); + return useQuery(query) as UseQueryResult>; } /** @@ -385,7 +387,9 @@ export function useSubmissionsQueries( refetchOnWindowFocus: false, }; - const queries: UseQueryOptions>[] = + const queries: UseQueryOptions< + BapAndFormioSubmissions<"2022" | "2023" | "2024"> + >[] = rebateYear === "2022" ? [bapQuery, formioFRF2022Query, formioPRF2022Query, formioCRF2022Query] : rebateYear === "2023" @@ -394,7 +398,9 @@ export function useSubmissionsQueries( ? [bapQuery, formioFRF2024Query, formioPRF2024Query, formioCRF2024Query] // prettier-ignore : []; - return useQueries({ queries }); + return useQueries({ queries }) as UseQueryResult< + BapAndFormioSubmissions + >[]; } /** From 82a51ea2befac1905af79553c9e2cbd6069ef11e Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Tue, 9 Jul 2024 09:19:29 -0400 Subject: [PATCH 15/29] Add formBapRebateIdField config and update useCombinedSubmissions to use it and update implementation of rebateYear param --- app/client/src/config.tsx | 21 +++++++++++++++ app/client/src/utilities.ts | 52 +++++++++++++++++++------------------ 2 files changed, 48 insertions(+), 25 deletions(-) diff --git a/app/client/src/config.tsx b/app/client/src/config.tsx index 3f0cb091..4773e4e3 100644 --- a/app/client/src/config.tsx +++ b/app/client/src/config.tsx @@ -175,3 +175,24 @@ export const formioEmailField = { crf: "", // TODO }, }; + +/** + * Formio BAP rebate ID field by year and form type. + */ +export const formioBapRebateIdField = { + 2022: { + frf: "", // NOTE: no BAP rebate ID in the FRF + prf: "hidden_bap_rebate_id", + crf: "hidden_bap_rebate_id", + }, + 2023: { + frf: "", // NOTE: no BAP rebate ID in the FRF + prf: "_bap_rebate_id", + crf: "_bap_rebate_id", + }, + 2024: { + frf: "", // NOTE: no BAP rebate ID in the FRF + prf: "", // TODO + crf: "", // TODO + }, +}; diff --git a/app/client/src/utilities.ts b/app/client/src/utilities.ts index 4297ff69..4e6cf042 100644 --- a/app/client/src/utilities.ts +++ b/app/client/src/utilities.ts @@ -32,7 +32,7 @@ import { type FormioChange2024Submission, type Rebate, } from "@/types"; -import { serverUrl } from "@/config"; +import { serverUrl, formioBapRebateIdField } from "@/config"; /** Formio Change Request submissions by rebate year. */ /* prettier-ignore */ @@ -408,36 +408,48 @@ export function useSubmissionsQueries( * from both the BAP and Formio into a single object, with the BAP assigned * rebateId as the object's keys. **/ -function useCombinedSubmissions(rebateYear: RebateYear) { +function useCombinedSubmissions(rebateYear: Year) { const queryClient = useQueryClient(); const bapFormSubmissions = queryClient.getQueryData(["bap/submissions"]); // prettier-ignore + const formioFRF2022Data = queryClient.getQueryData(["formio/2022/frf-submissions"]); // prettier-ignore + const formioFRF2023Data = queryClient.getQueryData(["formio/2023/frf-submissions"]); // prettier-ignore + const formioFRF2024Data = queryClient.getQueryData(["formio/2024/frf-submissions"]); // prettier-ignore + + const formioPRF2022Data = queryClient.getQueryData(["formio/2022/prf-submissions"]); // prettier-ignore + const formioPRF2023Data = queryClient.getQueryData(["formio/2023/prf-submissions"]); // prettier-ignore + const formioPRF2024Data = queryClient.getQueryData(["formio/2024/prf-submissions"]); // prettier-ignore + + const formioCRF2022Data = queryClient.getQueryData(["formio/2022/crf-submissions"]); // prettier-ignore + const formioCRF2023Data = queryClient.getQueryData(["formio/2023/crf-submissions"]); // prettier-ignore + const formioCRF2024Data = queryClient.getQueryData(["formio/2024/crf-submissions"]); // prettier-ignore + const formioFRFSubmissions = rebateYear === "2022" - ? queryClient.getQueryData(["formio/2022/frf-submissions"]) // prettier-ignore + ? formioFRF2022Data : rebateYear === "2023" - ? queryClient.getQueryData(["formio/2023/frf-submissions"]) // prettier-ignore + ? formioFRF2023Data : rebateYear === "2024" - ? queryClient.getQueryData(["formio/2024/frf-submissions"]) // prettier-ignore + ? formioFRF2024Data : undefined; const formioPRFSubmissions = rebateYear === "2022" - ? queryClient.getQueryData(["formio/2022/prf-submissions"]) // prettier-ignore + ? formioPRF2022Data : rebateYear === "2023" - ? queryClient.getQueryData(["formio/2023/prf-submissions"]) // prettier-ignore + ? formioPRF2023Data : rebateYear === "2024" - ? queryClient.getQueryData(["formio/2024/prf-submissions"]) // prettier-ignore + ? formioPRF2024Data : undefined; const formioCRFSubmissions = rebateYear === "2022" - ? queryClient.getQueryData(["formio/2022/crf-submissions"]) // prettier-ignore + ? formioCRF2022Data : rebateYear === "2023" - ? queryClient.getQueryData(["formio/2023/crf-submissions"]) // prettier-ignore + ? formioCRF2023Data : rebateYear === "2024" - ? queryClient.getQueryData(["formio/2024/crf-submissions"]) // prettier-ignore + ? formioCRF2024Data : undefined; const submissions: { @@ -496,14 +508,9 @@ function useCombinedSubmissions(rebateYear: RebateYear) { * returned from the BAP, so we can set BAP PRF submission data. */ for (const formioPRFSubmission of formioPRFSubmissions) { + const formioBapPrfRebateIdField = formioBapRebateIdField[rebateYear].prf; const formioBapRebateId = - rebateYear === "2022" - ? (formioPRFSubmission as FormioPRF2022Submission).data.hidden_bap_rebate_id // prettier-ignore - : rebateYear === "2023" - ? (formioPRFSubmission as FormioPRF2023Submission).data._bap_rebate_id - : rebateYear === "2024" - ? (formioPRFSubmission as FormioPRF2024Submission).data._bap_rebate_id // prettier-ignore - : null; + (formioPRFSubmission.data?.[formioBapPrfRebateIdField] as string) || null; const bapMatch = bapFormSubmissions[rebateYear].prfs.find((bapPRFSub) => { return bapPRFSub.Parent_Rebate_ID__c === formioBapRebateId; @@ -529,14 +536,9 @@ function useCombinedSubmissions(rebateYear: RebateYear) { * returned from the BAP, so we can set BAP CRF submission data. */ for (const formioCRFSubmission of formioCRFSubmissions) { + const formioBapCrfRebateIdField = formioBapRebateIdField[rebateYear].crf; const formioBapRebateId = - rebateYear === "2022" - ? (formioCRFSubmission as FormioCRF2022Submission).data.hidden_bap_rebate_id // prettier-ignore - : rebateYear === "2023" - ? (formioCRFSubmission as FormioCRF2023Submission).data._bap_rebate_id - : rebateYear === "2024" - ? (formioCRFSubmission as FormioCRF2024Submission).data._bap_rebate_id // prettier-ignore - : null; + (formioCRFSubmission.data?.[formioBapCrfRebateIdField] as string) || null; const bapMatch = bapFormSubmissions[rebateYear].crfs.find((bapCRFSub) => { return bapCRFSub.Parent_Rebate_ID__c === formioBapRebateId; From 067445f19ef9c89521f0aba68e8f8ab5730fe50e Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Wed, 10 Jul 2024 11:02:15 -0400 Subject: [PATCH 16/29] Split Rebate type into Rebate2022, Rebate2023, and Rebate2024 types, and update useCombinedSubmissions(), useSortedSubmissions(), and useSubmissions() to be properly typed via the passed rebateYear parameter --- app/client/src/types.ts | 53 ++++++++++++++++++++++++++----------- app/client/src/utilities.ts | 34 +++++++++++++++++------- 2 files changed, 61 insertions(+), 26 deletions(-) diff --git a/app/client/src/types.ts b/app/client/src/types.ts index d73a4a96..2d0d6420 100644 --- a/app/client/src/types.ts +++ b/app/client/src/types.ts @@ -350,29 +350,50 @@ export type FormioChange2024Submission = FormioSubmission & { data: FormioChange2024Data; }; -export type Rebate = { - rebateYear: RebateYear; +export type Rebate2022 = { + rebateYear: "2022"; frf: { - formio: - | FormioFRF2022Submission - | FormioFRF2023Submission - | FormioFRF2024Submission; + formio: FormioFRF2022Submission; bap: BapSubmissionData | null; }; prf: { - formio: - | FormioPRF2022Submission - | FormioPRF2023Submission - | FormioPRF2024Submission - | null; + formio: FormioPRF2022Submission | null; bap: BapSubmissionData | null; }; crf: { - formio: - | FormioCRF2022Submission - | FormioCRF2023Submission - | FormioCRF2024Submission - | null; + formio: FormioCRF2022Submission | null; + bap: BapSubmissionData | null; + }; +}; + +export type Rebate2023 = { + rebateYear: "2023"; + frf: { + formio: FormioFRF2023Submission; + bap: BapSubmissionData | null; + }; + prf: { + formio: FormioPRF2023Submission | null; + bap: BapSubmissionData | null; + }; + crf: { + formio: FormioCRF2023Submission | null; + bap: BapSubmissionData | null; + }; +}; + +export type Rebate2024 = { + rebateYear: "2024"; + frf: { + formio: FormioFRF2024Submission; + bap: BapSubmissionData | null; + }; + prf: { + formio: FormioPRF2024Submission | null; + bap: BapSubmissionData | null; + }; + crf: { + formio: FormioCRF2024Submission | null; bap: BapSubmissionData | null; }; }; diff --git a/app/client/src/utilities.ts b/app/client/src/utilities.ts index 4e6cf042..0148507c 100644 --- a/app/client/src/utilities.ts +++ b/app/client/src/utilities.ts @@ -30,7 +30,9 @@ import { type FormioPRF2024Submission, type FormioCRF2024Submission, type FormioChange2024Submission, - type Rebate, + type Rebate2022, + type Rebate2023, + type Rebate2024, } from "@/types"; import { serverUrl, formioBapRebateIdField } from "@/config"; @@ -50,6 +52,14 @@ type BapAndFormioSubmissions = Year extends "2024" ? BapFormSubmissions | FormioFRF2024Submission[] | FormioPRF2024Submission[] | FormioCRF2024Submission[] : never; +/** Combined Formio and BAP submissions by rebate year */ +/* prettier-ignore */ +type Rebate = + Year extends "2022" ? Rebate2022 : + Year extends "2023" ? Rebate2023 : + Year extends "2024" ? Rebate2024 : + never; + async function fetchData(url: string, options: RequestInit) { try { const response = await fetch(url, options); @@ -234,7 +244,7 @@ export function useChangeRequestsData( const changeRequest2023Data = queryClient.getQueryData(["formio/2023/changes"]); // prettier-ignore const changeRequest2024Data = queryClient.getQueryData(["formio/2024/changes"]); // prettier-ignore - const result = + const result: FormioChangeRequests<"2022" | "2023" | "2024"> = rebateYear === "2022" ? changeRequest2022Data : rebateYear === "2023" @@ -408,7 +418,9 @@ export function useSubmissionsQueries( * from both the BAP and Formio into a single object, with the BAP assigned * rebateId as the object's keys. **/ -function useCombinedSubmissions(rebateYear: Year) { +function useCombinedSubmissions( + rebateYear: Year, +): { [rebateId: string]: Rebate } { const queryClient = useQueryClient(); const bapFormSubmissions = queryClient.getQueryData(["bap/submissions"]); // prettier-ignore @@ -453,7 +465,7 @@ function useCombinedSubmissions(rebateYear: Year) { : undefined; const submissions: { - [rebateId: string]: Rebate; + [rebateId: string]: Rebate; } = {}; /* ensure form submissions data has been fetched from both the BAP and Formio */ @@ -463,7 +475,7 @@ function useCombinedSubmissions(rebateYear: Year) { !formioPRFSubmissions || !formioCRFSubmissions ) { - return {}; + return submissions; } /** @@ -500,7 +512,7 @@ function useCombinedSubmissions(rebateYear: Year) { }, prf: { formio: null, bap: null }, crf: { formio: null, bap: null }, - }; + } as Rebate; } /** @@ -527,7 +539,7 @@ function useCombinedSubmissions(rebateYear: Year) { submissions[formioBapRebateId].prf = { formio: { ...formioPRFSubmission }, bap: { modified, comboKey, mongoId, rebateId, reviewItemId, status }, - }; + } as Rebate["prf"]; } } @@ -555,7 +567,7 @@ function useCombinedSubmissions(rebateYear: Year) { submissions[formioBapRebateId].crf = { formio: { ...formioCRFSubmission }, bap: { modified, comboKey, mongoId, rebateId, reviewItemId, status }, - }; + } as Rebate["crf"]; } } @@ -569,7 +581,9 @@ function useCombinedSubmissions(rebateYear: Year) { * - Selected FRF submissions without a corresponding PRF submission * - Funding Approved PRF submissions without a corresponding CRF submission **/ -function useSortedSubmissions(rebates: { [rebateId: string]: Rebate }) { +function useSortedSubmissions(rebates: { + [rebateId: string]: Rebate; +}): (Rebate & { rebateId: string })[] { return Object.entries(rebates) .map(([rebateId, rebate]) => ({ rebateId, ...rebate })) .sort((r1, r2) => { @@ -630,7 +644,7 @@ function useSortedSubmissions(rebates: { [rebateId: string]: Rebate }) { * Custom hook that returns sorted submissions, and logs them if 'debug' search * parameter exists. */ -export function useSubmissions(rebateYear: RebateYear) { +export function useSubmissions(rebateYear: Year) { const [searchParams] = useSearchParams(); const combinedSubmissions = useCombinedSubmissions(rebateYear); From dd9c908c179a83e196f9a95a1602ee00f3d63a64 Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Wed, 10 Jul 2024 11:12:27 -0400 Subject: [PATCH 17/29] Update Submissions component to use Rebate2022, Rebate2023, and Rebate2024 types --- app/client/src/routes/submissions.tsx | 55 +++++++++------------------ 1 file changed, 19 insertions(+), 36 deletions(-) diff --git a/app/client/src/routes/submissions.tsx b/app/client/src/routes/submissions.tsx index afa4dc7f..c9eafcbe 100644 --- a/app/client/src/routes/submissions.tsx +++ b/app/client/src/routes/submissions.tsx @@ -11,13 +11,9 @@ import icons from "uswds/img/sprite.svg"; // --- import { type RebateYear, - type FormioFRF2022Submission, - type FormioPRF2022Submission, - type FormioCRF2022Submission, - type FormioFRF2023Submission, - type FormioPRF2023Submission, - // type FormioCRF2023Submission - type Rebate, + type Rebate2022, + type Rebate2023, + // type Rebate2024, } from "@/types"; import { serverUrl, @@ -167,7 +163,7 @@ function SubmissionsTableHeader(props: { rebateYear: RebateYear }) { ); } -function FRF2022Submission(props: { rebate: Rebate }) { +function FRF2022Submission(props: { rebate: Rebate2022 }) { const { rebate } = props; const { frf, prf, crf } = rebate; @@ -184,7 +180,7 @@ function FRF2022Submission(props: { rebate: Rebate }) { applicantOrganizationName, schoolDistrictName, last_updated_by, - } = (frf.formio as FormioFRF2022Submission).data; + } = frf.formio.data; const date = new Date(frf.formio.modified).toLocaleDateString(); const time = new Date(frf.formio.modified).toLocaleTimeString(); @@ -381,7 +377,7 @@ save the form for the EFT indicator to be displayed. */ ); } -function PRF2022Submission(props: { rebate: Rebate }) { +function PRF2022Submission(props: { rebate: Rebate2022 }) { const { rebate } = props; const { frf, prf, crf } = rebate; @@ -404,8 +400,7 @@ function PRF2022Submission(props: { rebate: Rebate }) { /** matched SAM.gov entity for the FRF submission */ const entity = bapSamData.entities.find((entity) => { const { ENTITY_STATUS__c, ENTITY_COMBO_KEY__c } = entity; - const comboKey = (frf.formio as FormioFRF2022Submission).data - .bap_hidden_entity_combo_key; + const comboKey = frf.formio.data.bap_hidden_entity_combo_key; return ENTITY_STATUS__c === "Active" && ENTITY_COMBO_KEY__c === comboKey; }); @@ -497,10 +492,7 @@ function PRF2022Submission(props: { rebate: Rebate }) { // return if a Payment Request submission has not been created for this rebate if (!prf.formio) return null; - const { - hidden_current_user_email, - hidden_bap_rebate_id, // - } = (prf.formio as FormioPRF2022Submission).data; + const { hidden_current_user_email, hidden_bap_rebate_id } = prf.formio.data; const date = new Date(prf.formio.modified).toLocaleDateString(); const time = new Date(prf.formio.modified).toLocaleTimeString(); @@ -595,7 +587,7 @@ function PRF2022Submission(props: { rebate: Rebate }) { ); } -function CRF2022Submission(props: { rebate: Rebate }) { +function CRF2022Submission(props: { rebate: Rebate2022 }) { const { rebate } = props; const { frf, prf, crf } = rebate; @@ -618,8 +610,7 @@ function CRF2022Submission(props: { rebate: Rebate }) { /** matched SAM.gov entity for the PRF submission */ const entity = bapSamData.entities.find((entity) => { const { ENTITY_STATUS__c, ENTITY_COMBO_KEY__c } = entity; - const comboKey = (prf.formio as FormioPRF2022Submission | null)?.data - .bap_hidden_entity_combo_key; + const comboKey = prf.formio?.data.bap_hidden_entity_combo_key; return ENTITY_STATUS__c === "Active" && ENTITY_COMBO_KEY__c === comboKey; }); @@ -711,10 +702,7 @@ function CRF2022Submission(props: { rebate: Rebate }) { // return if a Close Out submission has not been created for this rebate if (!crf.formio) return null; - const { - hidden_current_user_email, - hidden_bap_rebate_id, // - } = (crf.formio as FormioCRF2022Submission).data; + const { hidden_current_user_email, hidden_bap_rebate_id } = crf.formio.data; const date = new Date(crf.formio.modified).toLocaleDateString(); const time = new Date(crf.formio.modified).toLocaleTimeString(); @@ -807,7 +795,7 @@ function CRF2022Submission(props: { rebate: Rebate }) { ); } -function FRF2023Submission(props: { rebate: Rebate }) { +function FRF2023Submission(props: { rebate: Rebate2023 }) { const { rebate } = props; const { frf, prf, crf } = rebate; @@ -821,8 +809,7 @@ function FRF2023Submission(props: { rebate: Rebate }) { /** matched SAM.gov entity for the FRF submission */ const entity = bapSamData.entities.find((entity) => { const { ENTITY_STATUS__c, ENTITY_COMBO_KEY__c } = entity; - const comboKey = (frf.formio as FormioFRF2023Submission).data - ._bap_entity_combo_key; + const comboKey = frf.formio.data._bap_entity_combo_key; return ENTITY_STATUS__c === "Active" && ENTITY_COMBO_KEY__c === comboKey; }); @@ -839,7 +826,7 @@ function FRF2023Submission(props: { rebate: Rebate }) { appInfo_efti, appInfo_orgName, _formio_schoolDistrictName, - } = (frf.formio as FormioFRF2023Submission).data; + } = frf.formio.data; const date = new Date(frf.formio.modified).toLocaleDateString(); const time = new Date(frf.formio.modified).toLocaleTimeString(); @@ -1025,7 +1012,7 @@ handle when it's value is an empty string. */} ); } -function PRF2023Submission(props: { rebate: Rebate }) { +function PRF2023Submission(props: { rebate: Rebate2023 }) { const { rebate } = props; const { frf, prf, crf } = rebate; @@ -1048,8 +1035,7 @@ function PRF2023Submission(props: { rebate: Rebate }) { /** matched SAM.gov entity for the FRF submission */ const entity = bapSamData.entities.find((entity) => { const { ENTITY_STATUS__c, ENTITY_COMBO_KEY__c } = entity; - const comboKey = (frf.formio as FormioFRF2023Submission).data - ._bap_entity_combo_key; + const comboKey = frf.formio.data._bap_entity_combo_key; return ENTITY_STATUS__c === "Active" && ENTITY_COMBO_KEY__c === comboKey; }); @@ -1141,11 +1127,8 @@ function PRF2023Submission(props: { rebate: Rebate }) { // return if a Payment Request submission has not been created for this rebate if (!prf.formio) return null; - const { - _user_email, - _bap_entity_combo_key, - _bap_rebate_id, // - } = (prf.formio as FormioPRF2023Submission).data; + const { _user_email, _bap_entity_combo_key, _bap_rebate_id } = + prf.formio.data; const date = new Date(prf.formio.modified).toLocaleDateString(); const time = new Date(prf.formio.modified).toLocaleTimeString(); @@ -1255,7 +1238,7 @@ function PRF2023Submission(props: { rebate: Rebate }) { ); } -// function CRF2023Submission(props: { rebate: Rebate }) { +// function CRF2023Submission(props: { rebate: Rebate2023 }) { // // // } From 2bcfde0151e5b83d14eaf5180fa0f35cc491251a Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Wed, 10 Jul 2024 16:58:25 -0400 Subject: [PATCH 18/29] Update form route components to include rebate year string value directly when setting the 'submission period open' variables, as it's known ahead of time per file, so no need to read the value from react context --- app/client/src/routes/crf2022.tsx | 5 +---- app/client/src/routes/frf2022.tsx | 5 +---- app/client/src/routes/frf2023.tsx | 5 +---- app/client/src/routes/prf2022.tsx | 5 +---- app/client/src/routes/prf2023.tsx | 5 +---- 5 files changed, 5 insertions(+), 20 deletions(-) diff --git a/app/client/src/routes/crf2022.tsx b/app/client/src/routes/crf2022.tsx index d51dda30..1fe0443d 100644 --- a/app/client/src/routes/crf2022.tsx +++ b/app/client/src/routes/crf2022.tsx @@ -25,7 +25,6 @@ import { Loading } from "@/components/loading"; import { Message } from "@/components/message"; import { MarkdownContent } from "@/components/markdownContent"; import { useNotificationsActions } from "@/contexts/notifications"; -import { useRebateYearState } from "@/contexts/rebateYear"; type ServerResponse = | { @@ -127,7 +126,6 @@ function CloseOutRequestForm(props: { email: string }) { displayErrorNotification, dismissNotification, } = useNotificationsActions(); - const { rebateYear } = useRebateYearState(); const submissionsQueries = useSubmissionsQueries("2022"); const submissions = useSubmissions("2022"); @@ -195,8 +193,7 @@ function CloseOutRequestForm(props: { email: string }) { bap: rebate.crf.bap, }); - const crfSubmissionPeriodOpen = - configData.submissionPeriodOpen[rebateYear].crf; + const crfSubmissionPeriodOpen = configData.submissionPeriodOpen["2022"].crf; const formIsReadOnly = (submission.state === "submitted" || !crfSubmissionPeriodOpen) && diff --git a/app/client/src/routes/frf2022.tsx b/app/client/src/routes/frf2022.tsx index d79c45fc..0806850d 100644 --- a/app/client/src/routes/frf2022.tsx +++ b/app/client/src/routes/frf2022.tsx @@ -26,7 +26,6 @@ import { Message } from "@/components/message"; import { MarkdownContent } from "@/components/markdownContent"; import { useDialogActions } from "@/contexts/dialog"; import { useNotificationsActions } from "@/contexts/notifications"; -import { useRebateYearState } from "@/contexts/rebateYear"; type ServerResponse = | { @@ -140,7 +139,6 @@ function FundingRequestForm(props: { email: string }) { displayErrorNotification, dismissNotification, } = useNotificationsActions(); - const { rebateYear } = useRebateYearState(); const submissionsQueries = useSubmissionsQueries("2022"); const submissions = useSubmissions("2022"); @@ -330,8 +328,7 @@ function FundingRequestForm(props: { email: string }) { return null; } - const frfSubmissionPeriodOpen = - configData.submissionPeriodOpen[rebateYear].frf; + const frfSubmissionPeriodOpen = configData.submissionPeriodOpen["2022"].frf; const formIsReadOnly = (submission.state === "submitted" || !frfSubmissionPeriodOpen) && diff --git a/app/client/src/routes/frf2023.tsx b/app/client/src/routes/frf2023.tsx index 88a177a4..6b366c81 100644 --- a/app/client/src/routes/frf2023.tsx +++ b/app/client/src/routes/frf2023.tsx @@ -26,7 +26,6 @@ import { Message } from "@/components/message"; import { MarkdownContent } from "@/components/markdownContent"; import { useDialogActions } from "@/contexts/dialog"; import { useNotificationsActions } from "@/contexts/notifications"; -import { useRebateYearState } from "@/contexts/rebateYear"; type ServerResponse = | { @@ -126,7 +125,6 @@ function FundingRequestForm(props: { email: string }) { displayErrorNotification, dismissNotification, } = useNotificationsActions(); - const { rebateYear } = useRebateYearState(); const submissionsQueries = useSubmissionsQueries("2023"); const submissions = useSubmissions("2023"); @@ -316,8 +314,7 @@ function FundingRequestForm(props: { email: string }) { return null; } - const frfSubmissionPeriodOpen = - configData.submissionPeriodOpen[rebateYear].frf; + const frfSubmissionPeriodOpen = configData.submissionPeriodOpen["2023"].frf; const formIsReadOnly = (submission.state === "submitted" || !frfSubmissionPeriodOpen) && diff --git a/app/client/src/routes/prf2022.tsx b/app/client/src/routes/prf2022.tsx index ecafc008..56a0403c 100644 --- a/app/client/src/routes/prf2022.tsx +++ b/app/client/src/routes/prf2022.tsx @@ -25,7 +25,6 @@ import { Loading } from "@/components/loading"; import { Message } from "@/components/message"; import { MarkdownContent } from "@/components/markdownContent"; import { useNotificationsActions } from "@/contexts/notifications"; -import { useRebateYearState } from "@/contexts/rebateYear"; type ServerResponse = | { @@ -127,7 +126,6 @@ function PaymentRequestForm(props: { email: string }) { displayErrorNotification, dismissNotification, } = useNotificationsActions(); - const { rebateYear } = useRebateYearState(); const submissionsQueries = useSubmissionsQueries("2022"); const submissions = useSubmissions("2022"); @@ -202,8 +200,7 @@ function PaymentRequestForm(props: { email: string }) { bap: rebate.prf.bap, }); - const prfSubmissionPeriodOpen = - configData.submissionPeriodOpen[rebateYear].prf; + const prfSubmissionPeriodOpen = configData.submissionPeriodOpen["2022"].prf; const formIsReadOnly = frfNeedsEdits || diff --git a/app/client/src/routes/prf2023.tsx b/app/client/src/routes/prf2023.tsx index 6a3e4ef1..91592dbd 100644 --- a/app/client/src/routes/prf2023.tsx +++ b/app/client/src/routes/prf2023.tsx @@ -25,7 +25,6 @@ import { Loading } from "@/components/loading"; import { Message } from "@/components/message"; import { MarkdownContent } from "@/components/markdownContent"; import { useNotificationsActions } from "@/contexts/notifications"; -import { useRebateYearState } from "@/contexts/rebateYear"; type ServerResponse = | { @@ -127,7 +126,6 @@ function PaymentRequestForm(props: { email: string }) { displayErrorNotification, dismissNotification, } = useNotificationsActions(); - const { rebateYear } = useRebateYearState(); const submissionsQueries = useSubmissionsQueries("2023"); const submissions = useSubmissions("2023"); @@ -202,8 +200,7 @@ function PaymentRequestForm(props: { email: string }) { bap: rebate.prf.bap, }); - const prfSubmissionPeriodOpen = - configData.submissionPeriodOpen[rebateYear].prf; + const prfSubmissionPeriodOpen = configData.submissionPeriodOpen["2023"].prf; const formIsReadOnly = frfNeedsEdits || From fe49c90476864723c2abd08f42fcdbe1f25a85c2 Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Wed, 10 Jul 2024 17:03:56 -0400 Subject: [PATCH 19/29] Update frfNew route component to account for 2024 rebate year (placeholder empty object returned for now in createInitialSubmissionData() for 2024) --- app/client/src/routes/frfNew.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/app/client/src/routes/frfNew.tsx b/app/client/src/routes/frfNew.tsx index fa495505..74a85dd9 100644 --- a/app/client/src/routes/frfNew.tsx +++ b/app/client/src/routes/frfNew.tsx @@ -6,6 +6,7 @@ import clsx from "clsx"; import icons from "uswds/img/sprite.svg"; // --- import { + type RebateYear, type BapSamEntity, type FormioFRF2022Submission, type FormioFRF2023Submission, @@ -28,7 +29,7 @@ import { useRebateYearState } from "@/contexts/rebateYear"; * Creates the initial FRF submission data for a given rebate year */ function createInitialSubmissionData(options: { - rebateYear: "2022" | "2023"; + rebateYear: RebateYear; email: string; entity: BapSamEntity; }) { @@ -93,7 +94,11 @@ function createInitialSubmissionData(options: { _bap_applicant_state: PHYSICAL_ADDRESS_PROVINCE_OR_STATE__c, _bap_applicant_zip: PHYSICAL_ADDRESS_ZIPPOSTAL_CODE__c, } - : null; + : rebateYear === "2024" + ? { + // TODO + } + : null; } export function FRFNew() { From 13277c30f990b66a5350ee44f719feaa465ab8e8 Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Wed, 10 Jul 2024 17:05:02 -0400 Subject: [PATCH 20/29] Update utilities to rely on RebateYear type directly instead of string (year) enum value --- app/client/src/utilities.ts | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/app/client/src/utilities.ts b/app/client/src/utilities.ts index 0148507c..d45c5add 100644 --- a/app/client/src/utilities.ts +++ b/app/client/src/utilities.ts @@ -52,7 +52,10 @@ type BapAndFormioSubmissions = Year extends "2024" ? BapFormSubmissions | FormioFRF2024Submission[] | FormioPRF2024Submission[] | FormioCRF2024Submission[] : never; -/** Combined Formio and BAP submissions by rebate year */ +/** + * Formio and BAP submissions connected by rebate ID across all three forms + * (FRF, PRF, CRF) for a given rebate year. + */ /* prettier-ignore */ type Rebate = Year extends "2022" ? Rebate2022 : @@ -217,9 +220,7 @@ export function useChangeRequestsQuery( refetchOnWindowFocus: false, }; - const query: UseQueryOptions< - BapAndFormioSubmissions<"2022" | "2023" | "2024"> - > = + const query: UseQueryOptions> = rebateYear === "2022" ? changeRequest2022Query : rebateYear === "2023" @@ -244,7 +245,7 @@ export function useChangeRequestsData( const changeRequest2023Data = queryClient.getQueryData(["formio/2023/changes"]); // prettier-ignore const changeRequest2024Data = queryClient.getQueryData(["formio/2024/changes"]); // prettier-ignore - const result: FormioChangeRequests<"2022" | "2023" | "2024"> = + const result: FormioChangeRequests = rebateYear === "2022" ? changeRequest2022Data : rebateYear === "2023" @@ -397,9 +398,7 @@ export function useSubmissionsQueries( refetchOnWindowFocus: false, }; - const queries: UseQueryOptions< - BapAndFormioSubmissions<"2022" | "2023" | "2024"> - >[] = + const queries: UseQueryOptions>[] = rebateYear === "2022" ? [bapQuery, formioFRF2022Query, formioPRF2022Query, formioCRF2022Query] : rebateYear === "2023" From 61e8ff31335ade851cbb2e48a7ba0706c08f14fd Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Wed, 10 Jul 2024 17:19:36 -0400 Subject: [PATCH 21/29] Reorganize Submissions component to support 2024 components --- app/client/src/routes/submissions.tsx | 437 ++++++++++++++------------ 1 file changed, 233 insertions(+), 204 deletions(-) diff --git a/app/client/src/routes/submissions.tsx b/app/client/src/routes/submissions.tsx index c9eafcbe..7aa8d62b 100644 --- a/app/client/src/routes/submissions.tsx +++ b/app/client/src/routes/submissions.tsx @@ -163,6 +163,8 @@ function SubmissionsTableHeader(props: { rebateYear: RebateYear }) { ); } +// --- 2022 Submissions --- + function FRF2022Submission(props: { rebate: Rebate2022 }) { const { rebate } = props; const { frf, prf, crf } = rebate; @@ -795,6 +797,219 @@ function CRF2022Submission(props: { rebate: Rebate2022 }) { ); } +function Submissions2022() { + const content = useContentData(); + const submissionsQueries = useSubmissionsQueries("2022"); + const submissions = useSubmissions("2022"); + + if (submissionsQueries.some((query) => query.isFetching)) { + return ; + } + + if (submissionsQueries.some((query) => query.isError)) { + return ; + } + + if (submissions.length === 0) { + return ( +
+ +
+ ); + } + + return ( + <> + {content && ( + + )} + +
+ + + + {submissions.map((rebate, index) => { + return rebate.rebateYear === "2022" ? ( + + + + + {/* blank row after all submissions but the last one */} + {index !== submissions.length - 1 && ( + + + + )} + + ) : null; + })} + +
+   +
+
+ + ); +} + +// --- 2023 Submissions --- + +function ChangeRequests2023() { + const changeRequestsQuery = useChangeRequestsQuery("2023"); + const changeRequests = useChangeRequestsData("2023"); + + if (changeRequestsQuery.isFetching) { + return ; + } + + if (!changeRequests || changeRequests.length === 0) return null; + + return ( +
+ + + Your Change Requests + + + +
+ + + + + + + + + + + + + + + + {changeRequests.map((request, index) => { + const { _id, modified, data } = request; + const { + _request_form, + _bap_rebate_id, + _mongo_id, + _user_email, + request_type, + } = data; + + const date = new Date(modified).toLocaleDateString(); + const time = new Date(modified).toLocaleTimeString(); + + const formType = + _request_form === "frf" + ? "Application" + : _request_form === "prf" + ? "Payment Request" + : _request_form === "crf" + ? "Close Out" + : ""; + + return ( + + + + + + + + + + + + + + ); + })} + +
+ + + + + + + + + +
+ + {_bap_rebate_id || _mongo_id} + + + {formType} + + {request_type?.label} + {_user_email} + {date} +
+
+
+ ); +} + function FRF2023Submission(props: { rebate: Rebate2023 }) { const { rebate } = props; const { frf, prf, crf } = rebate; @@ -1242,71 +1457,6 @@ function PRF2023Submission(props: { rebate: Rebate2023 }) { // // // } -function Submissions2022() { - const content = useContentData(); - const submissionsQueries = useSubmissionsQueries("2022"); - const submissions = useSubmissions("2022"); - - if (submissionsQueries.some((query) => query.isFetching)) { - return ; - } - - if (submissionsQueries.some((query) => query.isError)) { - return ; - } - - if (submissions.length === 0) { - return ( -
- -
- ); - } - - return ( - <> - {content && ( - - )} - -
- - - - {submissions.map((rebate, index) => { - return rebate.rebateYear === "2022" ? ( - - - - - {/* blank row after all submissions but the last one */} - {index !== submissions.length - 1 && ( - - - - )} - - ) : null; - })} - -
-   -
-
- - ); -} - function Submissions2023() { const content = useContentData(); const changeRequestsQuery = useChangeRequestsQuery("2023"); @@ -1381,151 +1531,29 @@ function Submissions2023() { ); } -function ChangeRequests2023() { - const changeRequestsQuery = useChangeRequestsQuery("2023"); - const changeRequests = useChangeRequestsData("2023"); +// --- 2024 Submissions --- - if (changeRequestsQuery.isFetching) { - return ; - } - - if (!changeRequests || changeRequests.length === 0) return null; - - return ( -
- - - Your Change Requests - - - -
- - - - - - - - - - - - - - - - {changeRequests.map((request, index) => { - const { _id, modified, data } = request; - const { - _request_form, - _bap_rebate_id, - _mongo_id, - _user_email, - request_type, - } = data; - - const date = new Date(modified).toLocaleDateString(); - const time = new Date(modified).toLocaleTimeString(); - - const formType = - _request_form === "frf" - ? "Application" - : _request_form === "prf" - ? "Payment Request" - : _request_form === "crf" - ? "Close Out" - : ""; +// function ChangeRequests2024() { +// // +// } - return ( - - - +// function FRF2024Submission(props: { rebate: Rebate2023 }) { +// // +// } - +// function PRF2024Submission(props: { rebate: Rebate2023 }) { +// // +// } - +// function CRF2024Submission(props: { rebate: Rebate2023 }) { +// // +// } - +// function Submissions2024() { +// // +// } - - - - ); - })} - -
- - - - - - - - - -
- - {_bap_rebate_id || _mongo_id} - - - {formType} - - {request_type?.label} - {_user_email} - {date} -
-
-
- ); -} +// --- Submissions --- export function Submissions() { const content = useContentData(); @@ -1592,6 +1620,7 @@ export function Submissions() { {rebateYear === "2022" && } {rebateYear === "2023" && } + {/* {rebateYear === "2024" && } */} {content && ( Date: Thu, 11 Jul 2024 12:15:26 -0400 Subject: [PATCH 22/29] Add initial server app 2024 API routes and update formio and bap functions to begin to support fetching 2024 data --- app/server/app/routes/formio2024.js | 152 ++++++++++++++++++++++++++++ app/server/app/routes/help.js | 14 ++- app/server/app/routes/index.js | 1 + app/server/app/utilities/bap.js | 33 ++++-- app/server/app/utilities/formio.js | 70 ++++++++----- 5 files changed, 232 insertions(+), 38 deletions(-) create mode 100644 app/server/app/routes/formio2024.js diff --git a/app/server/app/routes/formio2024.js b/app/server/app/routes/formio2024.js new file mode 100644 index 00000000..be12d9a4 --- /dev/null +++ b/app/server/app/routes/formio2024.js @@ -0,0 +1,152 @@ +const express = require("express"); +// --- +const { + ensureAuthenticated, + storeBapComboKeys, + verifyMongoObjectId, +} = require("../middleware"); +const { + uploadS3FileMetadata, + downloadS3FileMetadata, + // + fetchFRFSubmissions, + createFRFSubmission, + fetchFRFSubmission, + updateFRFSubmission, + // + // fetchPRFSubmissions, + // createPRFSubmission, + // fetchPRFSubmission, + // updatePRFSubmission, + // deletePRFSubmission, + // + // fetchCRFSubmissions, + // createCRFSubmission, + // fetchCRFSubmission, + // updateCRFSubmission, + // + // fetchChangeRequests, + // fetchChangeRequestSchema, + // createChangeRequest, + // fetchChangeRequest, +} = require("../utilities/formio"); + +const rebateYear = "2024"; +const router = express.Router(); + +router.use(ensureAuthenticated); + +// --- download Formio S3 file metadata +router.get( + "/s3/:formType/:mongoId/:comboKey/storage/s3", + storeBapComboKeys, + (req, res) => { + downloadS3FileMetadata({ rebateYear, req, res }); + }, +); + +// --- upload Formio S3 file metadata +router.post( + "/s3/:formType/:mongoId/:comboKey/storage/s3", + storeBapComboKeys, + (req, res) => { + uploadS3FileMetadata({ rebateYear, req, res }); + }, +); + +// --- get user's 2024 FRF submissions from Formio +router.get("/frf-submissions", storeBapComboKeys, (req, res) => { + fetchFRFSubmissions({ rebateYear, req, res }); +}); + +// --- post a new 2024 FRF submission to Formio +router.post("/frf-submission", storeBapComboKeys, (req, res) => { + createFRFSubmission({ rebateYear, req, res }); +}); + +// --- get an existing 2024 FRF's schema and submission data from Formio +router.get( + "/frf-submission/:mongoId", + verifyMongoObjectId, + storeBapComboKeys, + (req, res) => { + fetchFRFSubmission({ rebateYear, req, res }); + }, +); + +// --- post an update to an existing draft 2024 FRF submission to Formio +router.post( + "/frf-submission/:mongoId", + verifyMongoObjectId, + storeBapComboKeys, + (req, res) => { + updateFRFSubmission({ rebateYear, req, res }); + }, +); + +// --- get user's 2024 PRF submissions from Formio +router.get("/prf-submissions", storeBapComboKeys, (req, res) => { + res.json([]); // TODO: replace with `fetchPRFSubmissions({ rebateYear, req, res })` when PRF is ready +}); + +// --- post a new 2024 PRF submission to Formio +// router.post("/prf-submission", storeBapComboKeys, (req, res) => { +// createPRFSubmission({ rebateYear, req, res }); +// }); + +// --- get an existing 2024 PRF's schema and submission data from Formio +// router.get("/prf-submission/:rebateId", storeBapComboKeys, async (req, res) => { +// fetchPRFSubmission({ rebateYear, req, res }); +// }); + +// --- post an update to an existing draft 2024 PRF submission to Formio +// router.post("/prf-submission/:rebateId", storeBapComboKeys, (req, res) => { +// updatePRFSubmission({ rebateYear, req, res }); +// }); + +// --- delete an existing 2024 PRF submission from Formio +// router.post("/delete-prf-submission", storeBapComboKeys, (req, res) => { +// deletePRFSubmission({ rebateYear, req, res }); +// }); + +// --- get user's 2024 CRF submissions from Formio +router.get("/crf-submissions", storeBapComboKeys, (req, res) => { + res.json([]); // TODO: replace with `fetchCRFSubmissions({ rebateYear, req, res })` when CRF is ready +}); + +// --- post a new 2024 CRF submission to Formio +// router.post("/crf-submission", storeBapComboKeys, (req, res) => { +// createCRFSubmission({ rebateYear, req, res }); +// }); + +// --- get an existing 2024 CRF's schema and submission data from Formio +// router.get("/crf-submission/:rebateId", storeBapComboKeys, async (req, res) => { +// fetchCRFSubmission({ rebateYear, req, res }); +// }); + +// --- post an update to an existing draft 2024 CRF submission to Formio +// router.post("/crf-submission/:rebateId", storeBapComboKeys, (req, res) => { +// updateCRFSubmission({ rebateYear, req, res }); +// }); + +// --- get user's 2024 Change Request form submissions from Formio +// router.get("/changes", storeBapComboKeys, (req, res) => { +// fetchChangeRequests({ rebateYear, req, res }); +// }); + +// --- get the 2024 Change Request form's schema from Formio +// router.get("/change", storeBapComboKeys, (req, res) => { +// fetchChangeRequestSchema({ rebateYear, req, res }); +// }); + +// --- post a new 2024 Change Request form submission to Formio +// router.post("/change", storeBapComboKeys, (req, res) => { +// createChangeRequest({ rebateYear, req, res }); +// }); + +// --- get an existing 2024 Change Request form's schema and submission data from Formio +// router.get("/change/:mongoId", storeBapComboKeys, async (req, res) => { +// fetchChangeRequest({ rebateYear, req, res }); +// }); + +module.exports = router; diff --git a/app/server/app/routes/help.js b/app/server/app/routes/help.js index e576bd01..816be34d 100644 --- a/app/server/app/routes/help.js +++ b/app/server/app/routes/help.js @@ -11,13 +11,21 @@ const { const { ensureAuthenticated, ensureHelpdesk } = require("../middleware"); const { getBapFormSubmissionData } = require("../utilities/bap"); +/** + * @typedef {'2022' | '2023' | '2024'} RebateYear + */ + +/** + * @typedef {'frf' | 'prf' | 'crf'} FormType + */ + const router = express.Router(); /** Confirm user is both authenticated and authorized with valid helpdesk roles. */ router.use(ensureAuthenticated); router.use(ensureHelpdesk); -/** @type {Map<'frf' | 'prf' | 'crf', 'CSB Application' | 'CSB Payment Request' | 'CSB Close Out'} */ +/** @type {Map} fields associated a form submission @@ -472,8 +480,13 @@ async function queryForBapFormSubmissionData( }, 2023: { frf: "CSB_Funding_Request_2023", - prf: null, // "CSB_Payment_Request_2023" - crf: null, // "CSB_Closeout_Request_2023" + prf: null, // TODO: "CSB_Payment_Request_2023" + crf: null, // TODO: "CSB_Closeout_Request_2023" + }, + 2024: { + frf: null, // TODO: "CSB_Funding_Request_2024" + prf: null, // TODO: "CSB_Payment_Request_2024" + crf: null, // TODO: "CSB_Closeout_Request_2024" }, }; @@ -542,7 +555,7 @@ async function queryForBapFormSubmissionData( CSB_Review_Item_ID__c: 1, // CSB Rebate ID with form/version ID (9 digits) Parent_Rebate_ID__c: 1, // CSB Rebate ID (6 digits) Record_Type_Name__c: 1, // 'CSB Funding Request' | 'CSB Payment Request' | 'CSB Close Out Request' | 'CSB Funding Request 2023' | 'CSB Payment Request 2023' | 'CSB Close Out Request 2023' - Rebate_Program_Year__c: 1, // '2022' | '2023' + Rebate_Program_Year__c: 1, // '2022' | '2023' | '2024' "Parent_CSB_Rebate__r.CSB_Funding_Request_Status__c": 1, "Parent_CSB_Rebate__r.CSB_Payment_Request_Status__c": 1, "Parent_CSB_Rebate__r.CSB_Closeout_Request_Status__c": 1, @@ -639,7 +652,7 @@ async function queryForBapFormSubmissionsStatuses(req) { CSB_Review_Item_ID__c: 1, // CSB Rebate ID with form/version ID (9 digits) Parent_Rebate_ID__c: 1, // CSB Rebate ID (6 digits) Record_Type_Name__c: 1, // 'CSB Funding Request' | 'CSB Payment Request' | 'CSB Close Out Request' | 'CSB Funding Request 2023' | 'CSB Payment Request 2023' | 'CSB Close Out Request 2023' - Rebate_Program_Year__c: 1, // '2022' | '2023' + Rebate_Program_Year__c: 1, // '2022' | '2023' | '2024' "Parent_CSB_Rebate__r.CSB_Funding_Request_Status__c": 1, "Parent_CSB_Rebate__r.CSB_Payment_Request_Status__c": 1, "Parent_CSB_Rebate__r.CSB_Closeout_Request_Status__c": 1, @@ -1476,8 +1489,8 @@ function getBapComboKeys(req, email) { * Fetches data associated with a provided form submission. * * @param {Object} param - * @param {'2022' | '2023'} param.rebateYear - * @param {'frf' | 'prf' | 'crf'} param.formType + * @param {RebateYear} param.rebateYear + * @param {FormType} param.formType * @param {string | null} param.rebateId * @param {string | null} param.mongoId * @param {express.Request} param.req @@ -1573,8 +1586,8 @@ function checkForBapDuplicates(req) { * returned from the BAP). * * @param {Object} param - * @param {'2022' | '2023'} param.rebateYear - * @param {'frf' | 'prf' | 'crf'} param.formType + * @param {RebateYear} param.rebateYear + * @param {FormType} param.formType * @param {string} param.mongoId * @param {string} param.comboKey * @param {express.Request} param.req diff --git a/app/server/app/utilities/formio.js b/app/server/app/utilities/formio.js index 57bbc191..8cbb2b02 100644 --- a/app/server/app/utilities/formio.js +++ b/app/server/app/utilities/formio.js @@ -22,28 +22,36 @@ const log = require("./logger"); const { NODE_ENV } = process.env; +/** + * @typedef {'2022' | '2023' | '2024'} RebateYear + */ + /** * @param {Object} param - * @param {'2022' | '2023'} param.rebateYear + * @param {RebateYear} param.rebateYear */ function getComboKeyFieldName({ rebateYear }) { return rebateYear === "2022" ? "bap_hidden_entity_combo_key" : rebateYear === "2023" ? "_bap_entity_combo_key" - : ""; + : rebateYear === "2024" + ? "" // TODO + : ""; } /** * @param {Object} param - * @param {'2022' | '2023'} param.rebateYear + * @param {RebateYear} param.rebateYear */ function getRebateIdFieldName({ rebateYear }) { return rebateYear === "2022" ? "hidden_bap_rebate_id" : rebateYear === "2023" ? "_bap_rebate_id" - : ""; + : rebateYear === "2024" + ? "" // TODO + : ""; } /** @@ -76,7 +84,7 @@ function modifyDatasourceComponentsUrl(schema) { /** * @param {Object} param - * @param {'2022' | '2023'} param.rebateYear + * @param {RebateYear} param.rebateYear * @param {express.Request} param.req * @param {express.Response} param.res */ @@ -455,11 +463,15 @@ function fetchDataForPRFSubmission({ rebateYear, req, res }) { return res.status(errorStatus).json({ message: errorMessage }); }); } + + if (rebateYear === "2024") { + // TODO + } } /** * @param {Object} param - * @param {'2022' | '2023'} param.rebateYear + * @param {RebateYear} param.rebateYear * @param {express.Request} param.req * @param {express.Response} param.res */ @@ -649,11 +661,19 @@ function fetchDataForCRFSubmission({ rebateYear, req, res }) { return res.status(errorStatus).json({ message: errorMessage }); }); } + + if (rebateYear === "2023") { + // TODO + } + + if (rebateYear === "2024") { + // TODO + } } /** * @param {Object} param - * @param {'2022' | '2023'} param.rebateYear + * @param {RebateYear} param.rebateYear * @param {express.Request} param.req * @param {express.Response} param.res */ @@ -734,7 +754,7 @@ function uploadS3FileMetadata({ rebateYear, req, res }) { /** * @param {Object} param - * @param {'2022' | '2023'} param.rebateYear + * @param {RebateYear} param.rebateYear * @param {express.Request} param.req * @param {express.Response} param.res */ @@ -781,7 +801,7 @@ function downloadS3FileMetadata({ rebateYear, req, res }) { /** * @param {Object} param - * @param {'2022' | '2023'} param.rebateYear + * @param {RebateYear} param.rebateYear * @param {express.Request} param.req * @param {express.Response} param.res */ @@ -820,7 +840,7 @@ function fetchFRFSubmissions({ rebateYear, req, res }) { /** * @param {Object} param - * @param {'2022' | '2023'} param.rebateYear + * @param {RebateYear} param.rebateYear * @param {express.Request} param.req * @param {express.Response} param.res */ @@ -878,7 +898,7 @@ function createFRFSubmission({ rebateYear, req, res }) { /** * @param {Object} param - * @param {'2022' | '2023'} param.rebateYear + * @param {RebateYear} param.rebateYear * @param {express.Request} param.req * @param {express.Response} param.res */ @@ -945,7 +965,7 @@ function fetchFRFSubmission({ rebateYear, req, res }) { /** * @param {Object} param - * @param {'2022' | '2023'} param.rebateYear + * @param {RebateYear} param.rebateYear * @param {express.Request} param.req * @param {express.Response} param.res */ @@ -1021,7 +1041,7 @@ function updateFRFSubmission({ rebateYear, req, res }) { /** * @param {Object} param - * @param {'2022' | '2023'} param.rebateYear + * @param {RebateYear} param.rebateYear * @param {express.Request} param.req * @param {express.Response} param.res */ @@ -1060,7 +1080,7 @@ function fetchPRFSubmissions({ rebateYear, req, res }) { /** * @param {Object} param - * @param {'2022' | '2023'} param.rebateYear + * @param {RebateYear} param.rebateYear * @param {express.Request} param.req * @param {express.Response} param.res */ @@ -1115,7 +1135,7 @@ function createPRFSubmission({ rebateYear, req, res }) { /** * @param {Object} param - * @param {'2022' | '2023'} param.rebateYear + * @param {RebateYear} param.rebateYear * @param {express.Request} param.req * @param {express.Response} param.res */ @@ -1204,7 +1224,7 @@ function fetchPRFSubmission({ rebateYear, req, res }) { /** * @param {Object} param - * @param {'2022' | '2023'} param.rebateYear + * @param {RebateYear} param.rebateYear * @param {express.Request} param.req * @param {express.Response} param.res */ @@ -1293,7 +1313,7 @@ function updatePRFSubmission({ rebateYear, req, res }) { /** * @param {Object} param - * @param {'2022' | '2023'} param.rebateYear + * @param {RebateYear} param.rebateYear * @param {express.Request} param.req * @param {express.Response} param.res */ @@ -1376,7 +1396,7 @@ function deletePRFSubmission({ rebateYear, req, res }) { /** * @param {Object} param - * @param {'2022' | '2023'} param.rebateYear + * @param {RebateYear} param.rebateYear * @param {express.Request} param.req * @param {express.Response} param.res */ @@ -1415,7 +1435,7 @@ function fetchCRFSubmissions({ rebateYear, req, res }) { /** * @param {Object} param - * @param {'2022' | '2023'} param.rebateYear + * @param {RebateYear} param.rebateYear * @param {express.Request} param.req * @param {express.Response} param.res */ @@ -1470,7 +1490,7 @@ function createCRFSubmission({ rebateYear, req, res }) { /** * @param {Object} param - * @param {'2022' | '2023'} param.rebateYear + * @param {RebateYear} param.rebateYear * @param {express.Request} param.req * @param {express.Response} param.res */ @@ -1559,7 +1579,7 @@ function fetchCRFSubmission({ rebateYear, req, res }) { /** * @param {Object} param - * @param {'2022' | '2023'} param.rebateYear + * @param {RebateYear} param.rebateYear * @param {express.Request} param.req * @param {express.Response} param.res */ @@ -1648,7 +1668,7 @@ function updateCRFSubmission({ rebateYear, req, res }) { /** * @param {Object} param - * @param {'2022' | '2023'} param.rebateYear + * @param {RebateYear} param.rebateYear * @param {express.Request} param.req * @param {express.Response} param.res */ @@ -1687,7 +1707,7 @@ function fetchChangeRequests({ rebateYear, req, res }) { /** * @param {Object} param - * @param {'2022' | '2023'} param.rebateYear + * @param {RebateYear} param.rebateYear * @param {express.Request} param.req * @param {express.Response} param.res */ @@ -1714,7 +1734,7 @@ function fetchChangeRequestSchema({ rebateYear, req, res }) { /** * @param {Object} param - * @param {'2022' | '2023'} param.rebateYear + * @param {RebateYear} param.rebateYear * @param {express.Request} param.req * @param {express.Response} param.res */ @@ -1766,7 +1786,7 @@ function createChangeRequest({ rebateYear, req, res }) { /** * @param {Object} param - * @param {'2022' | '2023'} param.rebateYear + * @param {RebateYear} param.rebateYear * @param {express.Request} param.req * @param {express.Response} param.res */ From 42e3a5a021a66ec65c9fad3749ece190a311313a Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Thu, 11 Jul 2024 14:57:35 -0400 Subject: [PATCH 23/29] Add initial FRF2024Submission component and update getComboKeyFieldName() to set field name for 2024 rebate year --- app/client/src/routes/submissions.tsx | 290 ++++++++++++++++++++++++-- app/server/app/utilities/formio.js | 2 +- 2 files changed, 277 insertions(+), 15 deletions(-) diff --git a/app/client/src/routes/submissions.tsx b/app/client/src/routes/submissions.tsx index 7aa8d62b..f4919646 100644 --- a/app/client/src/routes/submissions.tsx +++ b/app/client/src/routes/submissions.tsx @@ -13,7 +13,7 @@ import { type RebateYear, type Rebate2022, type Rebate2023, - // type Rebate2024, + type Rebate2024, } from "@/types"; import { serverUrl, @@ -163,7 +163,7 @@ function SubmissionsTableHeader(props: { rebateYear: RebateYear }) { ); } -// --- 2022 Submissions --- +/* --- 2022 Submissions --- */ function FRF2022Submission(props: { rebate: Rebate2022 }) { const { rebate } = props; @@ -862,7 +862,7 @@ function Submissions2022() { ); } -// --- 2023 Submissions --- +/* --- 2023 Submissions --- */ function ChangeRequests2023() { const changeRequestsQuery = useChangeRequestsQuery("2023"); @@ -1531,29 +1531,291 @@ function Submissions2023() { ); } -// --- 2024 Submissions --- +/* --- 2024 Submissions --- */ // function ChangeRequests2024() { // // // } -// function FRF2024Submission(props: { rebate: Rebate2023 }) { -// // -// } +function FRF2024Submission(props: { rebate: Rebate2024 }) { + const { rebate } = props; + const { frf, prf, crf } = rebate; -// function PRF2024Submission(props: { rebate: Rebate2023 }) { -// // -// } + // const { email } = useOutletContext<{ email: string }>(); + + const configData = useConfigData(); + const bapSamData = useBapSamData(); + + if (!configData || !bapSamData) return null; + + /** matched SAM.gov entity for the FRF submission */ + const entity = bapSamData.entities.find((entity) => { + const { ENTITY_STATUS__c, ENTITY_COMBO_KEY__c } = entity; + const comboKey = frf.formio.data._bap_entity_combo_key; + return ENTITY_STATUS__c === "Active" && ENTITY_COMBO_KEY__c === comboKey; + }); + + if (!entity) return null; + + // const { title, name } = getUserInfo(email, entity); + + const frfSubmissionPeriodOpen = configData.submissionPeriodOpen["2024"].frf; + + const { _user_email } = frf.formio.data; + const placeholder = true; // TODO: remove once we have UEI, EFTI, org name, and school district fields above + + const date = new Date(frf.formio.modified).toLocaleDateString(); + const time = new Date(frf.formio.modified).toLocaleTimeString(); + + const frfNeedsEdits = submissionNeedsEdits({ + formio: frf.formio, + bap: frf.bap, + }); + + const frfBapInternalStatus = frf.bap?.status || ""; + const frfFormioStatus = formioStatusMap.get(frf.formio.state); + + const frfStatus = frfNeedsEdits + ? "Edits Requested" + : bapStatusMap["2024"].frf.get(frfBapInternalStatus) || + frfFormioStatus || + ""; + + const frfSelected = frfStatus === "Selected"; + const frfSelectedButNoPRF = frfSelected && !Boolean(prf.formio); + + const prfApproved = prf.bap?.status === "Accepted"; + const prfApprovedButNoCRF = prfApproved && !Boolean(crf.formio); + + const statusTableCellClassNames = + frfFormioStatus === "Submitted" || !frfSubmissionPeriodOpen + ? "text-italic" + : ""; + + const frfUrl = `/frf/2023/${frf.formio._id}`; + + /** + * NOTE on the usage of `TextWithTooltip` below: + * When a form is first initially created, and the user has not yet clicked + * the "Next" or "Save" buttons, any fields that the Formio form definition + * sets automatically (based on hidden fields we inject on form creation) will + * not yet be part of the form submission data. As soon as the user clicks the + * "Next" or "Save" buttons the first time, those fields will be set and + * stored in the submission. Since we display some of those fields in the + * table below, we need to check if their values exist, and if they don't (for + * cases where the user has not yet advanced past the first screen of the + * form...which we believe is a bit of an edge case, as most users will likely + * do that after starting a new application), indicate to the user they need + * to first save the form for the fields to be displayed. + */ + return ( + + + {frfNeedsEdits ? ( + + ) : frf.formio.state === "submitted" || !frfSubmissionPeriodOpen ? ( + + ) : frf.formio.state === "draft" ? ( + + ) : null} + + + + {frf.bap?.rebateId ? ( + + {frf.bap.rebateId} + + ) : ( + + )} + + + + Application +
+ + {frfStatus === "Needs Clarification" ? ( + + ) : ( + <> + + {frfStatus} + + )} + + -// function CRF2024Submission(props: { rebate: Rebate2023 }) { + + <> + {Boolean(placeholder) ? ( + "TODO" + ) : ( + + )} +
+ {Boolean(placeholder) ? ( + "TODO" + ) : ( + + )} + + + + + <> + {Boolean(placeholder) ? ( + "TODO" + ) : ( + + )} +
+ {Boolean(placeholder) ? ( + "TODO" + ) : ( + + )} + + + + + {_user_email} +
+ {date} + + + {/* + + */} + + ); +} + +// function PRF2024Submission(props: { rebate: Rebate2024 }) { // // // } -// function Submissions2024() { +// function CRF2024Submission(props: { rebate: Rebate2024 }) { // // // } -// --- Submissions --- +function Submissions2024() { + const content = useContentData(); + // const changeRequestsQuery = useChangeRequestsQuery("2024"); + const submissionsQueries = useSubmissionsQueries("2024"); + const submissions = useSubmissions("2024"); + + if ( + // changeRequestsQuery.isInitialLoading || + submissionsQueries.some((query) => query.isFetching) + ) { + return ; + } + + if ( + // changeRequestsQuery.isError || + submissionsQueries.some((query) => query.isError) + ) { + return ; + } + + if (submissions.length === 0) { + return ( +
+ +
+ ); + } + + return ( + <> + {/* */} + + {content && ( + + )} + +
+ + + + {submissions.map((rebate, index) => { + return rebate.rebateYear === "2024" ? ( + + + {/* */} + {/* */} + {/* blank row after all submissions but the last one */} + {index !== submissions.length - 1 && ( + + + + )} + + ) : null; + })} + +
+   +
+
+ + ); +} + +/* --- Submissions --- */ export function Submissions() { const content = useContentData(); @@ -1620,7 +1882,7 @@ export function Submissions() { {rebateYear === "2022" && } {rebateYear === "2023" && } - {/* {rebateYear === "2024" && } */} + {rebateYear === "2024" && } {content && ( Date: Thu, 11 Jul 2024 15:19:40 -0400 Subject: [PATCH 24/29] Rename useChangeRequestsData() to useChangeRequests() --- app/client/src/routes/submissions.tsx | 4 ++-- app/client/src/utilities.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/client/src/routes/submissions.tsx b/app/client/src/routes/submissions.tsx index f4919646..38ad28d5 100644 --- a/app/client/src/routes/submissions.tsx +++ b/app/client/src/routes/submissions.tsx @@ -28,7 +28,7 @@ import { useConfigData, useBapSamData, useChangeRequestsQuery, - useChangeRequestsData, + useChangeRequests, useSubmissionsQueries, useSubmissions, submissionNeedsEdits, @@ -866,7 +866,7 @@ function Submissions2022() { function ChangeRequests2023() { const changeRequestsQuery = useChangeRequestsQuery("2023"); - const changeRequests = useChangeRequestsData("2023"); + const changeRequests = useChangeRequests("2023"); if (changeRequestsQuery.isFetching) { return ; diff --git a/app/client/src/utilities.ts b/app/client/src/utilities.ts index d45c5add..e6822942 100644 --- a/app/client/src/utilities.ts +++ b/app/client/src/utilities.ts @@ -236,7 +236,7 @@ export function useChangeRequestsQuery( * Custom hook that returns cached fetched Change Request form submissions from * Formio. */ -export function useChangeRequestsData( +export function useChangeRequests( rebateYear: Year, ): FormioChangeRequests { const queryClient = useQueryClient(); From 6d3598d93b25a009b973bc83887ae111571fd161 Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Thu, 11 Jul 2024 15:21:33 -0400 Subject: [PATCH 25/29] Update bapStatusMap with 2024 frf status mapping --- app/client/src/config.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/client/src/config.tsx b/app/client/src/config.tsx index 4773e4e3..7befd685 100644 --- a/app/client/src/config.tsx +++ b/app/client/src/config.tsx @@ -111,7 +111,11 @@ export const bapStatusMap = { crf: new Map(), // TODO }, 2024: { - frf: new Map(), // TODO + frf: new Map() + .set("Needs Clarification", "Needs Clarification") + .set("Withdrawn", "Withdrawn") + .set("Coordinator Denied", "Not Selected") + .set("Accepted", "Selected"), prf: new Map(), // TODO crf: new Map(), // TODO }, From ff0116dbc2f284d8bc54b318dd44386f65892087 Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Thu, 11 Jul 2024 15:39:49 -0400 Subject: [PATCH 26/29] Add initial FRF2024 component and route, update initial data injected into a new 2024 FRF submission to be the same as from 2023, and fix 2024 FRF URL defined in FRF2024Submission() component --- app/client/src/components/app.tsx | 12 +- app/client/src/routes/frf2024.tsx | 583 ++++++++++++++++++++++++++ app/client/src/routes/frfNew.tsx | 8 +- app/client/src/routes/submissions.tsx | 2 +- 4 files changed, 596 insertions(+), 9 deletions(-) create mode 100644 app/client/src/routes/frf2024.tsx diff --git a/app/client/src/components/app.tsx b/app/client/src/components/app.tsx index 08170074..ecfdcab4 100644 --- a/app/client/src/components/app.tsx +++ b/app/client/src/components/app.tsx @@ -37,10 +37,14 @@ import { FRFNew } from "@/routes/frfNew"; import { FRF2022 } from "@/routes/frf2022"; import { PRF2022 } from "@/routes/prf2022"; import { CRF2022 } from "@/routes/crf2022"; +import { Change2023 } from "@/routes/change2023"; import { FRF2023 } from "@/routes/frf2023"; import { PRF2023 } from "@/routes/prf2023"; // import { CRF2023 } from "@/routes/crf2023"; -import { Change2023 } from "@/routes/change2023"; +// import { Change2024 } from "@/routes/change2024"; +import { FRF2024 } from "@/routes/frf2024"; +// import { PRF2024 } from "@/routes/prf2024"; +// import { CRF2024 } from "@/routes/crf2024"; import { useDialogState, useDialogActions } from "@/contexts/dialog"; /** Custom hook to display a site-wide alert banner */ @@ -252,11 +256,15 @@ export function App() { } /> } /> + } /> } /> } /> {/* } /> */} - } /> + {/* } /> */} + } /> + {/* } /> */} + {/* } /> */} } /> diff --git a/app/client/src/routes/frf2024.tsx b/app/client/src/routes/frf2024.tsx new file mode 100644 index 00000000..bb8356e1 --- /dev/null +++ b/app/client/src/routes/frf2024.tsx @@ -0,0 +1,583 @@ +import { useEffect, useMemo, useRef } from "react"; +import { useNavigate, useOutletContext, useParams } from "react-router-dom"; +import { useQueryClient, useQuery, useMutation } from "@tanstack/react-query"; +import { Dialog } from "@headlessui/react"; +import { Formio, Form } from "@formio/react"; +import s3 from "formiojs/providers/storage/s3"; +import clsx from "clsx"; +import { cloneDeep, isEqual } from "lodash"; +import icons from "uswds/img/sprite.svg"; +// --- +import { type FormioFRF2024Submission } from "@/types"; +import { serverUrl, messages } from "@/config"; +import { + getData, + postData, + useContentData, + useConfigData, + useBapSamData, + useSubmissionsQueries, + useSubmissions, + submissionNeedsEdits, + getUserInfo, +} from "@/utilities"; +import { Loading } from "@/components/loading"; +import { Message } from "@/components/message"; +import { MarkdownContent } from "@/components/markdownContent"; +import { useDialogActions } from "@/contexts/dialog"; +import { useNotificationsActions } from "@/contexts/notifications"; + +type ServerResponse = + | { + userAccess: false; + formSchema: null; + submission: null; + } + | { + userAccess: true; + formSchema: { url: string; json: object }; + submission: FormioFRF2024Submission; + }; + +/** Custom hook to fetch and update Formio submission data */ +function useFormioSubmissionQueryAndMutation(mongoId: string | undefined) { + const queryClient = useQueryClient(); + + useEffect(() => { + queryClient.resetQueries({ queryKey: ["formio/2024/frf-submission"] }); + }, [queryClient]); + + const url = `${serverUrl}/api/formio/2024/frf-submission/${mongoId}`; + + const query = useQuery({ + queryKey: ["formio/2024/frf-submission", { id: mongoId }], + queryFn: () => { + return getData(url).then((res) => { + const comboKey = res.submission?.data._bap_entity_combo_key; + + /** + * Change the formUrl the File component's `uploadFile` uses, so the s3 + * upload PUT request is routed through the server app. + * + * https://github.com/formio/formio.js/blob/master/src/components/file/File.js#L760 + * https://github.com/formio/formio.js/blob/master/src/providers/storage/s3.js#L5 + * https://github.com/formio/formio.js/blob/master/src/providers/storage/xhr.js#L90 + */ + Formio.Providers.providers.storage.s3 = function (formio: { + formUrl: string; + [field: string]: unknown; + }) { + const s3Formio = cloneDeep(formio); + s3Formio.formUrl = `${serverUrl}/api/formio/2024/s3/frf/${mongoId}/${comboKey}`; + return s3(s3Formio); + }; + + return Promise.resolve(res); + }); + }, + refetchOnWindowFocus: false, + }); + + const mutation = useMutation({ + mutationFn: (updatedSubmission: { + data: { [field: string]: unknown }; + metadata: { [field: string]: unknown }; + state: "submitted" | "draft"; + }) => { + return postData(url, updatedSubmission); + }, + onSuccess: (res) => { + return queryClient.setQueryData( + ["formio/2024/frf-submission", { id: mongoId }], + (prevData) => { + return prevData?.submission + ? { ...prevData, submission: res } + : prevData; + }, + ); + }, + }); + + return { query, mutation }; +} + +export function FRF2024() { + const { email } = useOutletContext<{ email: string }>(); + /* ensure user verification (JWT refresh) doesn't cause form to re-render */ + return useMemo(() => { + return ; + }, [email]); +} + +function FundingRequestForm(props: { email: string }) { + const { email } = props; + + const navigate = useNavigate(); + const { id: mongoId } = useParams<"id">(); // MongoDB ObjectId string + + const content = useContentData(); + const configData = useConfigData(); + const bapSamData = useBapSamData(); + const { displayDialog } = useDialogActions(); + const { + displayInfoNotification, + displaySuccessNotification, + displayErrorNotification, + dismissNotification, + } = useNotificationsActions(); + + const submissionsQueries = useSubmissionsQueries("2024"); + const submissions = useSubmissions("2024"); + + const { query, mutation } = useFormioSubmissionQueryAndMutation(mongoId); + const { userAccess, formSchema, submission } = query.data ?? {}; + + /** + * Stores when data is being posted to the server, so a loading overlay can + * be rendered over the form, preventing the user from losing input data when + * the form is re-rendered with data returned from the server's successful + * post response. + */ + const dataIsPosting = useRef(false); + + /** + * Stores when the form is being submitted, so it can be referenced in the + * Form component's `onSubmit` event prop to prevent double submits. + */ + const formIsBeingSubmitted = useRef(false); + + /** + * Stores the form data's state right after the user clicks the Save, Submit, + * or Next button. As soon as a post request to update the data succeeds, this + * pending submission data is reset to an empty object. This pending data, + * along with the submission data returned from the server is passed into the + * Form component's `submission` prop. + */ + const pendingSubmissionData = useRef<{ [field: string]: unknown }>({}); + + /** + * Stores the last succesfully submitted data, so it can be used in the Form + * component's `onNextPage` event prop's "dirty check" which determines if + * posting of updated data is needed (so we don't make needless requests if no + * field data in the form has changed). + */ + const lastSuccesfullySubmittedData = useRef<{ [field: string]: unknown }>({}); + + if (!configData || !bapSamData) { + return ; + } + + if (submissionsQueries.some((query) => query.isFetching)) { + return ; + } + + if (submissionsQueries.some((query) => query.isError)) { + return ; + } + + if (query.isInitialLoading) { + return ; + } + + if (query.isError || !userAccess || !formSchema || !submission) { + return ; + } + + const rebate = submissions.find((r) => r.frf.formio._id === mongoId); + + const frfNeedsEdits = !rebate + ? false + : submissionNeedsEdits({ + formio: rebate.frf.formio, + bap: rebate.frf.bap, + }); + + const frfNeedsEditsAndPRFExists = frfNeedsEdits && !!rebate?.prf.formio; + + /** + * NOTE: If the FRF submission needs edits and there's a corresponding PRF + * submission, display a confirmation dialog prompting the user to delete the + * PRF submission, as it's data will no longer valid when the FRF submission's + * data is changed. + */ + if (frfNeedsEditsAndPRFExists) { + displayDialog({ + dismissable: true, + heading: "Submission Edits Requested", + description: ( + <> +

+ This Application form submission has been opened at the request of + the applicant to make edits, but before you can make edits, the + associated Payment Request form submission needs to be deleted. If + the request to make edits to your Application form submission was + made in error, contact the Clean School Bus Program helpline at{" "} + cleanschoolbus@epa.gov. +

+ +

+ If you’d like to view the Payment Request form submission before + deletion, please close this dialog box, and you will be re-directed + to the associated Payment Request form. +

+ +

+ To proceed with deleting the associated Payment Request form + submission, please select the{" "} + Delete Payment Request Form Submission button + below, and the Payment Request form submission will be deleted. The + Application form will then be open for editing. +

+ +
+
+

+ Please note: Once deleted, the Payment Request + form submission will be removed from your dashboard and cannot + be recovered. +

+
+
+ + ), + confirmText: "Delete Payment Request Form Submission", + confirmedAction: () => { + const prf = rebate.prf.formio; + + if (!prf) { + displayErrorNotification({ + id: Date.now(), + body: ( + <> +

+ Error deleting Payment Request {rebate.rebateId}. +

+

+ Please notify the helpdesk that a problem exists preventing + the deletion of Payment Request form submission{" "} + {rebate.rebateId}. +

+ + ), + }); + + // NOTE: logging rebate for helpdesk debugging purposes + console.log(rebate); + return; + } + + displayInfoNotification({ + id: Date.now(), + body: ( +

+ Deleting Payment Request {rebate.rebateId}... +

+ ), + }); + + const url = `${serverUrl}/api/formio/2024/delete-prf-submission`; + + postData(url, { + mongoId: prf._id, + rebateId: prf.data._bap_rebate_id, + comboKey: prf.data._bap_entity_combo_key, + }) + .then((_res) => { + window.location.reload(); + }) + .catch((_err) => { + displayErrorNotification({ + id: Date.now(), + body: ( + <> +

+ Error deleting Payment Request {rebate.rebateId}. +

+

+ Please reload the page to attempt the deletion again, or + contact the helpdesk if the problem persists. +

+ + ), + }); + }); + }, + dismissedAction: () => navigate(`/prf/2024/${rebate.rebateId}`), + }); + + return null; + } + + const frfSubmissionPeriodOpen = configData.submissionPeriodOpen["2024"].frf; + + const formIsReadOnly = + (submission.state === "submitted" || !frfSubmissionPeriodOpen) && + !frfNeedsEdits; + + /** matched SAM.gov entity for the Application submission */ + const entity = bapSamData.entities.find((entity) => { + const { ENTITY_COMBO_KEY__c } = entity; + return ENTITY_COMBO_KEY__c === submission.data._bap_entity_combo_key; + }); + + if (!entity) { + return ; + } + + if (entity.ENTITY_STATUS__c !== "Active") { + return ; + } + + const { title, name } = getUserInfo(email, entity); + + return ( +
+ {content && ( + + )} + +
    +
  • +
    + +
    +
    + Application ID: {submission._id} +
    +
  • + + {rebate?.frf.bap?.rebateId && ( +
  • +
    + +
    +
    + Rebate ID: {rebate.frf.bap.rebateId} +
    +
  • + )} +
+ + {}}> +
+
+
+ + + +
+
+
+ +
+
{ + if (formIsReadOnly) return; + + // account for when form is being submitted to prevent double submits + if (formIsBeingSubmitted.current) return; + if (onSubmitSubmission.state === "submitted") { + formIsBeingSubmitted.current = true; + } + + const data = { ...onSubmitSubmission.data }; + + const updatedSubmission = { + ...onSubmitSubmission, + data, + }; + + dismissNotification({ id: 0 }); + dataIsPosting.current = true; + pendingSubmissionData.current = data; + + mutation.mutate(updatedSubmission, { + onSuccess: (res, _payload, _context) => { + pendingSubmissionData.current = {}; + lastSuccesfullySubmittedData.current = cloneDeep(res.data); + + /** success notification id */ + const id = Date.now(); + + displaySuccessNotification({ + id, + body: ( +

+ {onSubmitSubmission.state === "submitted" ? ( + <> + Application {mongoId} submitted successfully. + + ) : ( + <>Draft saved successfully. + )} +

+ ), + }); + + if (onSubmitSubmission.state === "submitted") { + /** + * NOTE: we'll keep the success notification displayed and + * redirect the user to their dashboard + */ + navigate("/"); + } + + if (onSubmitSubmission.state === "draft") { + setTimeout(() => dismissNotification({ id }), 5000); + } + }, + onError: (_error, _payload, _context) => { + displayErrorNotification({ + id: Date.now(), + body: ( +

+ {onSubmitSubmission.state === "submitted" ? ( + <>Error submitting Application form. + ) : ( + <>Error saving draft. + )} +

+ ), + }); + }, + onSettled: (_data, _error, _payload, _context) => { + dataIsPosting.current = false; + formIsBeingSubmitted.current = false; + }, + }); + }} + onNextPage={(onNextPageParam: { + page: number; + submission: { + data: { [field: string]: unknown }; + metadata: { [field: string]: unknown }; + }; + }) => { + if (formIsReadOnly) return; + + const data = { ...onNextPageParam.submission.data }; + + // "dirty check" – don't post an update if no changes have been made + // to the form (ignoring current user fields) + const currentData = { ...data }; + const submittedData = { ...lastSuccesfullySubmittedData.current }; + delete currentData._user_email; + delete currentData._user_title; + delete currentData._user_name; + delete submittedData._user_email; + delete submittedData._user_title; + delete submittedData._user_name; + if (isEqual(currentData, submittedData)) return; + + const updatedSubmission = { + ...onNextPageParam.submission, + data, + state: "draft" as const, + }; + + dismissNotification({ id: 0 }); + dataIsPosting.current = true; + pendingSubmissionData.current = data; + + mutation.mutate(updatedSubmission, { + onSuccess: (res, _payload, _context) => { + pendingSubmissionData.current = {}; + lastSuccesfullySubmittedData.current = cloneDeep(res.data); + + /** success notification id */ + const id = Date.now(); + + displaySuccessNotification({ + id, + body: ( +

+ Draft saved successfully. +

+ ), + }); + + setTimeout(() => dismissNotification({ id }), 5000); + }, + onError: (_error, _payload, _context) => { + displayErrorNotification({ + id: Date.now(), + body: ( +

+ Error saving draft. +

+ ), + }); + }, + onSettled: (_data, _error, _payload, _context) => { + dataIsPosting.current = false; + }, + }); + }} + /> +
+
+ ); +} diff --git a/app/client/src/routes/frfNew.tsx b/app/client/src/routes/frfNew.tsx index 74a85dd9..64d3adca 100644 --- a/app/client/src/routes/frfNew.tsx +++ b/app/client/src/routes/frfNew.tsx @@ -72,7 +72,7 @@ function createInitialSubmissionData(options: { sam_hidden_applicant_state: PHYSICAL_ADDRESS_PROVINCE_OR_STATE__c, sam_hidden_applicant_zip_code: PHYSICAL_ADDRESS_ZIPPOSTAL_CODE__c, } - : rebateYear === "2023" + : rebateYear === "2023" || rebateYear === "2024" ? { _user_email: email, _user_title: title, @@ -94,11 +94,7 @@ function createInitialSubmissionData(options: { _bap_applicant_state: PHYSICAL_ADDRESS_PROVINCE_OR_STATE__c, _bap_applicant_zip: PHYSICAL_ADDRESS_ZIPPOSTAL_CODE__c, } - : rebateYear === "2024" - ? { - // TODO - } - : null; + : null; } export function FRFNew() { diff --git a/app/client/src/routes/submissions.tsx b/app/client/src/routes/submissions.tsx index 38ad28d5..c2bc854c 100644 --- a/app/client/src/routes/submissions.tsx +++ b/app/client/src/routes/submissions.tsx @@ -1592,7 +1592,7 @@ function FRF2024Submission(props: { rebate: Rebate2024 }) { ? "text-italic" : ""; - const frfUrl = `/frf/2023/${frf.formio._id}`; + const frfUrl = `/frf/2024/${frf.formio._id}`; /** * NOTE on the usage of `TextWithTooltip` below: From 9cfb237b674a7210b0b65069fafc552fbddb8128 Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Fri, 12 Jul 2024 11:01:47 -0400 Subject: [PATCH 27/29] Update app to support 2024 change requests --- app/client/src/components/change2024New.tsx | 370 ++++++++++++++++++++ app/client/src/routes/submissions.tsx | 171 ++++++++- app/client/src/types.ts | 2 + app/server/app/routes/formio2024.js | 32 +- 4 files changed, 545 insertions(+), 30 deletions(-) create mode 100644 app/client/src/components/change2024New.tsx diff --git a/app/client/src/components/change2024New.tsx b/app/client/src/components/change2024New.tsx new file mode 100644 index 00000000..c6dfc8c4 --- /dev/null +++ b/app/client/src/components/change2024New.tsx @@ -0,0 +1,370 @@ +import { Fragment, useRef, useState } from "react"; +import { useQuery, useMutation } from "@tanstack/react-query"; +import { Dialog, Transition } from "@headlessui/react"; +import { XMarkIcon } from "@heroicons/react/24/outline"; +import { Form } from "@formio/react"; +import clsx from "clsx"; +import icons from "uswds/img/sprite.svg"; +// --- +import { type FormType, type FormioChange2024Submission } from "@/types"; +import { serverUrl, messages } from "@/config"; +import { + getData, + postData, + useContentData, + useChangeRequestsQuery, +} from "@/utilities"; +import { Loading } from "@/components/loading"; +import { Message } from "@/components/message"; +import { MarkdownContent } from "@/components/markdownContent"; +import { useNotificationsActions } from "@/contexts/notifications"; + +type ChangeRequestData = { + formType: FormType; + comboKey: string; + rebateId: string | null; + mongoId: string; + state: "draft" | "submitted"; + email: string; + title: string; + name: string; +}; + +type ServerResponse = { url: string; json: object }; + +/** Custom hook to fetch Formio schema */ +function useFormioSchemaQuery() { + const url = `${serverUrl}/api/formio/2024/change`; + + const query = useQuery({ + queryKey: ["formio/2024/change"], + queryFn: () => getData(url), + refetchOnWindowFocus: false, + }); + + return { query }; +} + +/** Custom hook to update Formio submission submission data */ +function useFormioSubmissionMutation() { + const url = `${serverUrl}/api/formio/2024/change/`; + + const mutation = useMutation({ + mutationFn: (submission: FormioChange2024Submission) => { + return postData(url, submission); + }, + }); + + return { mutation }; +} + +export function ChangeRequest2024Button(props: { data: ChangeRequestData }) { + const { data } = props; + + const [dialogShown, setDialogShown] = useState(false); + + function closeDialog() { + setDialogShown(false); + } + + return ( + <> + + + + + ); +} + +function ChangeRequest2024Dialog(props: { + dialogShown: boolean; + closeDialog: () => void; + data: ChangeRequestData; +}) { + const { dialogShown, closeDialog, data } = props; + + /* + * NOTE: Formio form Combobox inputs won't receive click events if the + * Dialog.Panel component is used (they still receive keyboard events), so a + * div is used instead. The downside is we lose the triggering of the Dialog + * component's `onClose` event when a user clicks outside the panel. + */ + + return ( + + closeDialog()} + > + +
+ + +
+
+ + {/* */} +
+
+
+ +
+
+ +
+ +
+
+ {/*
*/} +
+
+
+
+
+ ); +} + +function ChangeRequest2024Form(props: { + data: ChangeRequestData; + closeDialog: () => void; +}) { + const { data, closeDialog } = props; + const { formType, comboKey, rebateId, mongoId, state, email, title, name } = + data; + + const content = useContentData(); + const { + displaySuccessNotification, + displayErrorNotification, + dismissNotification, + } = useNotificationsActions(); + + const changeRequestsQuery = useChangeRequestsQuery("2024"); + + const { query } = useFormioSchemaQuery(); + const { mutation } = useFormioSubmissionMutation(); + + const formSchema = query.data; + + /** + * Stores when data is being posted to the server, so a loading overlay can + * be rendered over the form, preventing the user from losing input data when + * the form is re-rendered with data returned from the server's successful + * post response. + */ + const dataIsPosting = useRef(false); + + /** + * Stores when the form is being submitted, so it can be referenced in the + * Form component's `onSubmit` event prop to prevent double submits. + */ + const formIsBeingSubmitted = useRef(false); + + /** + * Stores the form data's state right after the user clicks the Submit button. + * As soon as a post request to submit the data succeeds, this pending + * submission data is reset to an empty object. This pending data is passed + * into the Form component's `submission` prop. + */ + const pendingSubmissionData = useRef<{ [field: string]: unknown }>({}); + + if (query.isInitialLoading) { + return ; + } + + if (query.isError || !formSchema) { + return ; + } + + return ( + <> + {content && } + + {}}> +
+
+
+ + + +
+
+
+ +
+ { + // account for when form is being submitted to prevent double submits + if (formIsBeingSubmitted.current) return; + formIsBeingSubmitted.current = true; + + const data = { ...onSubmitSubmission.data }; + + dismissNotification({ id: 0 }); + dataIsPosting.current = true; + pendingSubmissionData.current = data; + + mutation.mutate(onSubmitSubmission, { + onSuccess: (res, _payload, _context) => { + pendingSubmissionData.current = {}; + + displaySuccessNotification({ + id: Date.now(), + body: ( +

+ Change Request {res._id} submitted successfully. +

+ ), + }); + + closeDialog(); + changeRequestsQuery.refetch(); + }, + onError: (_error, _payload, _context) => { + /** error notification id */ + const id = Date.now(); + + displayErrorNotification({ + id, + body: ( + <> +

+ Error creating Change Request for{" "} + + {formType.toUpperCase()} {rebateId} + + . +

+

+ Please try again. +

+ + ), + }); + + setTimeout(() => dismissNotification({ id }), 5000); + }, + onSettled: (_data, _error, _payload, _context) => { + dataIsPosting.current = false; + formIsBeingSubmitted.current = false; + }, + }); + }} + /> +
+ + ); +} diff --git a/app/client/src/routes/submissions.tsx b/app/client/src/routes/submissions.tsx index c2bc854c..b8f25633 100644 --- a/app/client/src/routes/submissions.tsx +++ b/app/client/src/routes/submissions.tsx @@ -39,6 +39,7 @@ import { Message } from "@/components/message"; import { MarkdownContent } from "@/components/markdownContent"; import { TextWithTooltip } from "@/components/tooltip"; import { ChangeRequest2023Button } from "@/components/change2023New"; +import { ChangeRequest2024Button } from "@/components/change2024New"; import { useNotificationsActions } from "@/contexts/notifications"; import { useRebateYearState, @@ -150,14 +151,14 @@ function SubmissionsTableHeader(props: { rebateYear: RebateYear }) { /> - {rebateYear === "2023" && ( + {rebateYear === "2023" || rebateYear === "2024" ? ( - )} + ) : null} ); @@ -1533,15 +1534,157 @@ function Submissions2023() { /* --- 2024 Submissions --- */ -// function ChangeRequests2024() { -// // -// } +function ChangeRequests2024() { + const changeRequestsQuery = useChangeRequestsQuery("2024"); + const changeRequests = useChangeRequests("2024"); + + if (changeRequestsQuery.isFetching) { + return ; + } + + if (!changeRequests || changeRequests.length === 0) return null; + + return ( +
+ + + Your Change Requests + + + +
+ + + + + + + + + + + + + + + + {changeRequests.map((request, index) => { + const { _id, modified, data } = request; + const { + _request_form, + _bap_rebate_id, + _mongo_id, + _user_email, + request_type, + } = data; + + const date = new Date(modified).toLocaleDateString(); + const time = new Date(modified).toLocaleTimeString(); + + const formType = + _request_form === "frf" + ? "Application" + : _request_form === "prf" + ? "Payment Request" + : _request_form === "crf" + ? "Close Out" + : ""; + + return ( + + + + + + + + + + + + + + ); + })} + +
+ + + + + + + + + +
+ + {_bap_rebate_id || _mongo_id} + + + {formType} + + {request_type?.label} + {_user_email} + {date} +
+
+
+ ); +} function FRF2024Submission(props: { rebate: Rebate2024 }) { const { rebate } = props; const { frf, prf, crf } = rebate; - // const { email } = useOutletContext<{ email: string }>(); + const { email } = useOutletContext<{ email: string }>(); const configData = useConfigData(); const bapSamData = useBapSamData(); @@ -1557,11 +1700,11 @@ function FRF2024Submission(props: { rebate: Rebate2024 }) { if (!entity) return null; - // const { title, name } = getUserInfo(email, entity); + const { title, name } = getUserInfo(email, entity); const frfSubmissionPeriodOpen = configData.submissionPeriodOpen["2024"].frf; - const { _user_email } = frf.formio.data; + const { _user_email, _bap_entity_combo_key } = frf.formio.data; const placeholder = true; // TODO: remove once we have UEI, EFTI, org name, and school district fields above const date = new Date(frf.formio.modified).toLocaleDateString(); @@ -1715,7 +1858,7 @@ function FRF2024Submission(props: { rebate: Rebate2024 }) { {date} - {/* + - */} + ); } @@ -1743,19 +1886,19 @@ function FRF2024Submission(props: { rebate: Rebate2024 }) { function Submissions2024() { const content = useContentData(); - // const changeRequestsQuery = useChangeRequestsQuery("2024"); + const changeRequestsQuery = useChangeRequestsQuery("2024"); const submissionsQueries = useSubmissionsQueries("2024"); const submissions = useSubmissions("2024"); if ( - // changeRequestsQuery.isInitialLoading || + changeRequestsQuery.isInitialLoading || submissionsQueries.some((query) => query.isFetching) ) { return ; } if ( - // changeRequestsQuery.isError || + changeRequestsQuery.isError || submissionsQueries.some((query) => query.isError) ) { return ; @@ -1771,7 +1914,7 @@ function Submissions2024() { return ( <> - {/* */} + {content && ( { // }); // --- get user's 2024 Change Request form submissions from Formio -// router.get("/changes", storeBapComboKeys, (req, res) => { -// fetchChangeRequests({ rebateYear, req, res }); -// }); +router.get("/changes", storeBapComboKeys, (req, res) => { + fetchChangeRequests({ rebateYear, req, res }); +}); // --- get the 2024 Change Request form's schema from Formio -// router.get("/change", storeBapComboKeys, (req, res) => { -// fetchChangeRequestSchema({ rebateYear, req, res }); -// }); +router.get("/change", storeBapComboKeys, (req, res) => { + fetchChangeRequestSchema({ rebateYear, req, res }); +}); // --- post a new 2024 Change Request form submission to Formio -// router.post("/change", storeBapComboKeys, (req, res) => { -// createChangeRequest({ rebateYear, req, res }); -// }); +router.post("/change", storeBapComboKeys, (req, res) => { + createChangeRequest({ rebateYear, req, res }); +}); // --- get an existing 2024 Change Request form's schema and submission data from Formio -// router.get("/change/:mongoId", storeBapComboKeys, async (req, res) => { -// fetchChangeRequest({ rebateYear, req, res }); -// }); +router.get("/change/:mongoId", storeBapComboKeys, async (req, res) => { + fetchChangeRequest({ rebateYear, req, res }); +}); module.exports = router; From c7d761a7975f6873b9fc682f9c478be145bc8e6e Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Fri, 12 Jul 2024 12:20:29 -0400 Subject: [PATCH 28/29] Add 2024 change request form component and route --- app/client/src/components/app.tsx | 4 +- app/client/src/routes/change2024.tsx | 99 ++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 app/client/src/routes/change2024.tsx diff --git a/app/client/src/components/app.tsx b/app/client/src/components/app.tsx index ecfdcab4..b92141f4 100644 --- a/app/client/src/components/app.tsx +++ b/app/client/src/components/app.tsx @@ -41,7 +41,7 @@ import { Change2023 } from "@/routes/change2023"; import { FRF2023 } from "@/routes/frf2023"; import { PRF2023 } from "@/routes/prf2023"; // import { CRF2023 } from "@/routes/crf2023"; -// import { Change2024 } from "@/routes/change2024"; +import { Change2024 } from "@/routes/change2024"; import { FRF2024 } from "@/routes/frf2024"; // import { PRF2024 } from "@/routes/prf2024"; // import { CRF2024 } from "@/routes/crf2024"; @@ -261,7 +261,7 @@ export function App() { } /> {/* } /> */} - {/* } /> */} + } /> } /> {/* } /> */} {/* } /> */} diff --git a/app/client/src/routes/change2024.tsx b/app/client/src/routes/change2024.tsx new file mode 100644 index 00000000..ed2e201b --- /dev/null +++ b/app/client/src/routes/change2024.tsx @@ -0,0 +1,99 @@ +import { useEffect } from "react"; +import { useParams } from "react-router-dom"; +import { useQueryClient, useQuery } from "@tanstack/react-query"; +import { Form } from "@formio/react"; +import icons from "uswds/img/sprite.svg"; +// --- +import { type FormioChange2024Submission } from "@/types"; +import { serverUrl, messages } from "@/config"; +import { getData, useContentData } from "@/utilities"; +import { Loading } from "@/components/loading"; +import { Message } from "@/components/message"; +import { MarkdownContent } from "@/components/markdownContent"; + +type ServerResponse = + | { + userAccess: false; + formSchema: null; + submission: null; + } + | { + userAccess: true; + formSchema: { url: string; json: object }; + submission: FormioChange2024Submission; + }; + +/** Custom hook to fetch Formio submission data */ +function useFormioSubmissionQuery(mongoId: string | undefined) { + const queryClient = useQueryClient(); + + useEffect(() => { + queryClient.resetQueries({ queryKey: ["formio/2024/change"] }); + }, [queryClient]); + + const url = `${serverUrl}/api/formio/2024/change/${mongoId}`; + + const query = useQuery({ + queryKey: ["formio/2024/change", { id: mongoId }], + queryFn: () => getData(url), + refetchOnWindowFocus: false, + }); + + return { query }; +} + +export function Change2024() { + const { id: mongoId } = useParams<"id">(); // MongoDB ObjectId string + + const content = useContentData(); + + const { query } = useFormioSubmissionQuery(mongoId); + const { userAccess, formSchema, submission } = query.data ?? {}; + + if (query.isInitialLoading) { + return ; + } + + if (query.isError || !userAccess || !formSchema || !submission) { + return ; + } + + return ( +
+ {content && ( + + )} + +
    +
  • +
    + +
    +
    + Change Request ID: {submission._id} +
    +
  • +
+ +
+ +
+
+ ); +} From 392e42163202a34109dd8c68af1f7daa38f0bb63 Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Fri, 12 Jul 2024 15:55:32 -0400 Subject: [PATCH 29/29] Define FormioSchemaAndSubmission type (that takes Submission generic type), and use it across app instead of re-defining the shape of the server response in each component that expects data in that shape --- app/client/src/components/change2023New.tsx | 4 ++-- app/client/src/components/change2024New.tsx | 4 ++-- app/client/src/routes/change2023.tsx | 19 ++++++------------- app/client/src/routes/change2024.tsx | 19 ++++++------------- app/client/src/routes/crf2022.tsx | 21 +++++++-------------- app/client/src/routes/frf2022.tsx | 21 +++++++-------------- app/client/src/routes/frf2023.tsx | 21 +++++++-------------- app/client/src/routes/frf2024.tsx | 21 +++++++-------------- app/client/src/routes/helpdesk.tsx | 10 +++++----- app/client/src/routes/prf2022.tsx | 21 +++++++-------------- app/client/src/routes/prf2023.tsx | 21 +++++++-------------- app/client/src/types.ts | 12 ++++++++++++ 12 files changed, 75 insertions(+), 119 deletions(-) diff --git a/app/client/src/components/change2023New.tsx b/app/client/src/components/change2023New.tsx index 286b7b68..44370c45 100644 --- a/app/client/src/components/change2023New.tsx +++ b/app/client/src/components/change2023New.tsx @@ -30,7 +30,7 @@ type ChangeRequestData = { name: string; }; -type ServerResponse = { url: string; json: object }; +type Response = { url: string; json: object }; /** Custom hook to fetch Formio schema */ function useFormioSchemaQuery() { @@ -38,7 +38,7 @@ function useFormioSchemaQuery() { const query = useQuery({ queryKey: ["formio/2023/change"], - queryFn: () => getData(url), + queryFn: () => getData(url), refetchOnWindowFocus: false, }); diff --git a/app/client/src/components/change2024New.tsx b/app/client/src/components/change2024New.tsx index c6dfc8c4..d6001b9e 100644 --- a/app/client/src/components/change2024New.tsx +++ b/app/client/src/components/change2024New.tsx @@ -30,7 +30,7 @@ type ChangeRequestData = { name: string; }; -type ServerResponse = { url: string; json: object }; +type Response = { url: string; json: object }; /** Custom hook to fetch Formio schema */ function useFormioSchemaQuery() { @@ -38,7 +38,7 @@ function useFormioSchemaQuery() { const query = useQuery({ queryKey: ["formio/2024/change"], - queryFn: () => getData(url), + queryFn: () => getData(url), refetchOnWindowFocus: false, }); diff --git a/app/client/src/routes/change2023.tsx b/app/client/src/routes/change2023.tsx index f6dea4a0..0e46f765 100644 --- a/app/client/src/routes/change2023.tsx +++ b/app/client/src/routes/change2023.tsx @@ -4,24 +4,17 @@ import { useQueryClient, useQuery } from "@tanstack/react-query"; import { Form } from "@formio/react"; import icons from "uswds/img/sprite.svg"; // --- -import { type FormioChange2023Submission } from "@/types"; +import { + type FormioSchemaAndSubmission, + type FormioChange2023Submission, +} from "@/types"; import { serverUrl, messages } from "@/config"; import { getData, useContentData } from "@/utilities"; import { Loading } from "@/components/loading"; import { Message } from "@/components/message"; import { MarkdownContent } from "@/components/markdownContent"; -type ServerResponse = - | { - userAccess: false; - formSchema: null; - submission: null; - } - | { - userAccess: true; - formSchema: { url: string; json: object }; - submission: FormioChange2023Submission; - }; +type Response = FormioSchemaAndSubmission; /** Custom hook to fetch Formio submission data */ function useFormioSubmissionQuery(mongoId: string | undefined) { @@ -35,7 +28,7 @@ function useFormioSubmissionQuery(mongoId: string | undefined) { const query = useQuery({ queryKey: ["formio/2023/change", { id: mongoId }], - queryFn: () => getData(url), + queryFn: () => getData(url), refetchOnWindowFocus: false, }); diff --git a/app/client/src/routes/change2024.tsx b/app/client/src/routes/change2024.tsx index ed2e201b..a340655d 100644 --- a/app/client/src/routes/change2024.tsx +++ b/app/client/src/routes/change2024.tsx @@ -4,24 +4,17 @@ import { useQueryClient, useQuery } from "@tanstack/react-query"; import { Form } from "@formio/react"; import icons from "uswds/img/sprite.svg"; // --- -import { type FormioChange2024Submission } from "@/types"; +import { + type FormioSchemaAndSubmission, + type FormioChange2024Submission, +} from "@/types"; import { serverUrl, messages } from "@/config"; import { getData, useContentData } from "@/utilities"; import { Loading } from "@/components/loading"; import { Message } from "@/components/message"; import { MarkdownContent } from "@/components/markdownContent"; -type ServerResponse = - | { - userAccess: false; - formSchema: null; - submission: null; - } - | { - userAccess: true; - formSchema: { url: string; json: object }; - submission: FormioChange2024Submission; - }; +type Response = FormioSchemaAndSubmission; /** Custom hook to fetch Formio submission data */ function useFormioSubmissionQuery(mongoId: string | undefined) { @@ -35,7 +28,7 @@ function useFormioSubmissionQuery(mongoId: string | undefined) { const query = useQuery({ queryKey: ["formio/2024/change", { id: mongoId }], - queryFn: () => getData(url), + queryFn: () => getData(url), refetchOnWindowFocus: false, }); diff --git a/app/client/src/routes/crf2022.tsx b/app/client/src/routes/crf2022.tsx index 1fe0443d..9c264a3f 100644 --- a/app/client/src/routes/crf2022.tsx +++ b/app/client/src/routes/crf2022.tsx @@ -8,7 +8,10 @@ import clsx from "clsx"; import { cloneDeep, isEqual } from "lodash"; import icons from "uswds/img/sprite.svg"; // --- -import { type FormioCRF2022Submission } from "@/types"; +import { + type FormioSchemaAndSubmission, + type FormioCRF2022Submission, +} from "@/types"; import { serverUrl, messages } from "@/config"; import { getData, @@ -26,17 +29,7 @@ import { Message } from "@/components/message"; import { MarkdownContent } from "@/components/markdownContent"; import { useNotificationsActions } from "@/contexts/notifications"; -type ServerResponse = - | { - userAccess: false; - formSchema: null; - submission: null; - } - | { - userAccess: true; - formSchema: { url: string; json: object }; - submission: FormioCRF2022Submission; - }; +type Response = FormioSchemaAndSubmission; /** Custom hook to fetch and update Formio submission data */ function useFormioSubmissionQueryAndMutation(rebateId: string | undefined) { @@ -51,7 +44,7 @@ function useFormioSubmissionQueryAndMutation(rebateId: string | undefined) { const query = useQuery({ queryKey: ["formio/2022/crf-submission", { id: rebateId }], queryFn: () => { - return getData(url).then((res) => { + return getData(url).then((res) => { const mongoId = res.submission?._id; const comboKey = res.submission?.data.bap_hidden_entity_combo_key; @@ -90,7 +83,7 @@ function useFormioSubmissionQueryAndMutation(rebateId: string | undefined) { return postData(url, updatedSubmission); }, onSuccess: (res) => { - return queryClient.setQueryData( + return queryClient.setQueryData( ["formio/2022/crf-submission", { id: rebateId }], (prevData) => { return prevData?.submission diff --git a/app/client/src/routes/frf2022.tsx b/app/client/src/routes/frf2022.tsx index 0806850d..6ad979d7 100644 --- a/app/client/src/routes/frf2022.tsx +++ b/app/client/src/routes/frf2022.tsx @@ -8,7 +8,10 @@ import clsx from "clsx"; import { cloneDeep, isEqual } from "lodash"; import icons from "uswds/img/sprite.svg"; // --- -import { type FormioFRF2022Submission } from "@/types"; +import { + type FormioSchemaAndSubmission, + type FormioFRF2022Submission, +} from "@/types"; import { serverUrl, messages } from "@/config"; import { getData, @@ -27,17 +30,7 @@ import { MarkdownContent } from "@/components/markdownContent"; import { useDialogActions } from "@/contexts/dialog"; import { useNotificationsActions } from "@/contexts/notifications"; -type ServerResponse = - | { - userAccess: false; - formSchema: null; - submission: null; - } - | { - userAccess: true; - formSchema: { url: string; json: object }; - submission: FormioFRF2022Submission; - }; +type Response = FormioSchemaAndSubmission; /** Custom hook to fetch and update Formio submission data */ function useFormioSubmissionQueryAndMutation(mongoId: string | undefined) { @@ -52,7 +45,7 @@ function useFormioSubmissionQueryAndMutation(mongoId: string | undefined) { const query = useQuery({ queryKey: ["formio/2022/frf-submission", { id: mongoId }], queryFn: () => { - return getData(url).then((res) => { + return getData(url).then((res) => { const comboKey = res.submission?.data.bap_hidden_entity_combo_key; /** @@ -101,7 +94,7 @@ function useFormioSubmissionQueryAndMutation(mongoId: string | undefined) { return postData(url, updatedSubmission); }, onSuccess: (res) => { - return queryClient.setQueryData( + return queryClient.setQueryData( ["formio/2022/frf-submission", { id: mongoId }], (prevData) => { return prevData?.submission diff --git a/app/client/src/routes/frf2023.tsx b/app/client/src/routes/frf2023.tsx index 6b366c81..f66b103e 100644 --- a/app/client/src/routes/frf2023.tsx +++ b/app/client/src/routes/frf2023.tsx @@ -8,7 +8,10 @@ import clsx from "clsx"; import { cloneDeep, isEqual } from "lodash"; import icons from "uswds/img/sprite.svg"; // --- -import { type FormioFRF2023Submission } from "@/types"; +import { + type FormioSchemaAndSubmission, + type FormioFRF2023Submission, +} from "@/types"; import { serverUrl, messages } from "@/config"; import { getData, @@ -27,17 +30,7 @@ import { MarkdownContent } from "@/components/markdownContent"; import { useDialogActions } from "@/contexts/dialog"; import { useNotificationsActions } from "@/contexts/notifications"; -type ServerResponse = - | { - userAccess: false; - formSchema: null; - submission: null; - } - | { - userAccess: true; - formSchema: { url: string; json: object }; - submission: FormioFRF2023Submission; - }; +type Response = FormioSchemaAndSubmission; /** Custom hook to fetch and update Formio submission data */ function useFormioSubmissionQueryAndMutation(mongoId: string | undefined) { @@ -52,7 +45,7 @@ function useFormioSubmissionQueryAndMutation(mongoId: string | undefined) { const query = useQuery({ queryKey: ["formio/2023/frf-submission", { id: mongoId }], queryFn: () => { - return getData(url).then((res) => { + return getData(url).then((res) => { const comboKey = res.submission?.data._bap_entity_combo_key; /** @@ -87,7 +80,7 @@ function useFormioSubmissionQueryAndMutation(mongoId: string | undefined) { return postData(url, updatedSubmission); }, onSuccess: (res) => { - return queryClient.setQueryData( + return queryClient.setQueryData( ["formio/2023/frf-submission", { id: mongoId }], (prevData) => { return prevData?.submission diff --git a/app/client/src/routes/frf2024.tsx b/app/client/src/routes/frf2024.tsx index bb8356e1..caa48565 100644 --- a/app/client/src/routes/frf2024.tsx +++ b/app/client/src/routes/frf2024.tsx @@ -8,7 +8,10 @@ import clsx from "clsx"; import { cloneDeep, isEqual } from "lodash"; import icons from "uswds/img/sprite.svg"; // --- -import { type FormioFRF2024Submission } from "@/types"; +import { + type FormioSchemaAndSubmission, + type FormioFRF2024Submission, +} from "@/types"; import { serverUrl, messages } from "@/config"; import { getData, @@ -27,17 +30,7 @@ import { MarkdownContent } from "@/components/markdownContent"; import { useDialogActions } from "@/contexts/dialog"; import { useNotificationsActions } from "@/contexts/notifications"; -type ServerResponse = - | { - userAccess: false; - formSchema: null; - submission: null; - } - | { - userAccess: true; - formSchema: { url: string; json: object }; - submission: FormioFRF2024Submission; - }; +type Response = FormioSchemaAndSubmission; /** Custom hook to fetch and update Formio submission data */ function useFormioSubmissionQueryAndMutation(mongoId: string | undefined) { @@ -52,7 +45,7 @@ function useFormioSubmissionQueryAndMutation(mongoId: string | undefined) { const query = useQuery({ queryKey: ["formio/2024/frf-submission", { id: mongoId }], queryFn: () => { - return getData(url).then((res) => { + return getData(url).then((res) => { const comboKey = res.submission?.data._bap_entity_combo_key; /** @@ -87,7 +80,7 @@ function useFormioSubmissionQueryAndMutation(mongoId: string | undefined) { return postData(url, updatedSubmission); }, onSuccess: (res) => { - return queryClient.setQueryData( + return queryClient.setQueryData( ["formio/2024/frf-submission", { id: mongoId }], (prevData) => { return prevData?.submission diff --git a/app/client/src/routes/helpdesk.tsx b/app/client/src/routes/helpdesk.tsx index 9934b5c9..a57b606c 100644 --- a/app/client/src/routes/helpdesk.tsx +++ b/app/client/src/routes/helpdesk.tsx @@ -47,7 +47,7 @@ import { useRebateYearActions, } from "@/contexts/rebateYear"; -type ServerResponse = +type Response = | { formSchema: null; formio: null; @@ -114,7 +114,7 @@ function ResultTableRow(props: { SetStateAction<{ fetched: boolean; results: SubmissionAction[] }> >; submissionMutation: UseMutationResult< - ServerResponse["formio"], + Response["formio"], unknown, DraftSubmission, unknown @@ -390,17 +390,17 @@ export function Helpdesk() { const submissionQuery = useQuery({ queryKey: ["helpdesk/submission"], - queryFn: () => getData(submissionUrl), + queryFn: () => getData(submissionUrl), onSuccess: (_res) => setResultDisplayed(true), enabled: false, }); const submissionMutation = useMutation({ mutationFn: (submission: DraftSubmission) => { - return postData(submissionUrl, submission); + return postData(submissionUrl, submission); }, onSuccess: (res) => { - queryClient.setQueryData( + queryClient.setQueryData( ["helpdesk/submission"], (prevData) => { return prevData?.formio diff --git a/app/client/src/routes/prf2022.tsx b/app/client/src/routes/prf2022.tsx index 56a0403c..af77b27d 100644 --- a/app/client/src/routes/prf2022.tsx +++ b/app/client/src/routes/prf2022.tsx @@ -8,7 +8,10 @@ import clsx from "clsx"; import { cloneDeep, isEqual } from "lodash"; import icons from "uswds/img/sprite.svg"; // --- -import { type FormioPRF2022Submission } from "@/types"; +import { + type FormioSchemaAndSubmission, + type FormioPRF2022Submission, +} from "@/types"; import { serverUrl, messages } from "@/config"; import { getData, @@ -26,17 +29,7 @@ import { Message } from "@/components/message"; import { MarkdownContent } from "@/components/markdownContent"; import { useNotificationsActions } from "@/contexts/notifications"; -type ServerResponse = - | { - userAccess: false; - formSchema: null; - submission: null; - } - | { - userAccess: true; - formSchema: { url: string; json: object }; - submission: FormioPRF2022Submission; - }; +type Response = FormioSchemaAndSubmission; /** Custom hook to fetch and update Formio submission data */ function useFormioSubmissionQueryAndMutation(rebateId: string | undefined) { @@ -51,7 +44,7 @@ function useFormioSubmissionQueryAndMutation(rebateId: string | undefined) { const query = useQuery({ queryKey: ["formio/2022/prf-submission", { id: rebateId }], queryFn: () => { - return getData(url).then((res) => { + return getData(url).then((res) => { const mongoId = res.submission?._id; const comboKey = res.submission?.data.bap_hidden_entity_combo_key; @@ -90,7 +83,7 @@ function useFormioSubmissionQueryAndMutation(rebateId: string | undefined) { return postData(url, updatedSubmission); }, onSuccess: (res) => { - return queryClient.setQueryData( + return queryClient.setQueryData( ["formio/2022/prf-submission", { id: rebateId }], (prevData) => { return prevData?.submission diff --git a/app/client/src/routes/prf2023.tsx b/app/client/src/routes/prf2023.tsx index 91592dbd..55fc4a16 100644 --- a/app/client/src/routes/prf2023.tsx +++ b/app/client/src/routes/prf2023.tsx @@ -8,7 +8,10 @@ import clsx from "clsx"; import { cloneDeep, isEqual } from "lodash"; import icons from "uswds/img/sprite.svg"; // --- -import { type FormioPRF2023Submission } from "@/types"; +import { + type FormioSchemaAndSubmission, + type FormioPRF2023Submission, +} from "@/types"; import { serverUrl, messages } from "@/config"; import { getData, @@ -26,17 +29,7 @@ import { Message } from "@/components/message"; import { MarkdownContent } from "@/components/markdownContent"; import { useNotificationsActions } from "@/contexts/notifications"; -type ServerResponse = - | { - userAccess: false; - formSchema: null; - submission: null; - } - | { - userAccess: true; - formSchema: { url: string; json: object }; - submission: FormioPRF2023Submission; - }; +type Response = FormioSchemaAndSubmission; /** Custom hook to fetch and update Formio submission data */ function useFormioSubmissionQueryAndMutation(rebateId: string | undefined) { @@ -51,7 +44,7 @@ function useFormioSubmissionQueryAndMutation(rebateId: string | undefined) { const query = useQuery({ queryKey: ["formio/2023/prf-submission", { id: rebateId }], queryFn: () => { - return getData(url).then((res) => { + return getData(url).then((res) => { const mongoId = res.submission?._id; const comboKey = res.submission?.data._bap_entity_combo_key; @@ -90,7 +83,7 @@ function useFormioSubmissionQueryAndMutation(rebateId: string | undefined) { return postData(url, updatedSubmission); }, onSuccess: (res) => { - return queryClient.setQueryData( + return queryClient.setQueryData( ["formio/2023/prf-submission", { id: rebateId }], (prevData) => { return prevData?.submission diff --git a/app/client/src/types.ts b/app/client/src/types.ts index 691655db..8c42b8b7 100644 --- a/app/client/src/types.ts +++ b/app/client/src/types.ts @@ -308,6 +308,18 @@ type FormioChange2024Data = { request_type: { label: string; value: string }; }; +export type FormioSchemaAndSubmission = + | { + userAccess: false; + formSchema: null; + submission: null; + } + | { + userAccess: true; + formSchema: { url: string; json: object }; + submission: Submission; + }; + export type FormioFRF2022Submission = FormioSubmission & { data: FormioFRF2022Data; };