From 0b76490f0fa8c3e484583950f06f596dac204c9f Mon Sep 17 00:00:00 2001 From: 13bfrancis <40218571+13bfrancis@users.noreply.github.com> Date: Mon, 13 Nov 2023 14:51:49 -0500 Subject: [PATCH] Squashed commit of the following: commit 7563b2529d986ec74fd5849b3f5e95b78cff99d8 Author: 13bfrancis <40218571+13bfrancis@users.noreply.github.com> Date: Thu Nov 9 12:29:20 2023 -0500 fix build error commit e3c2c18eefc75293bc63964b95640bad7f01a465 Author: 13bfrancis <40218571+13bfrancis@users.noreply.github.com> Date: Thu Nov 9 12:12:41 2023 -0500 fix errors with sink commit 50e4f8600301e5a56fdd99354b78cec1b4f54ef2 Author: 13bfrancis <40218571+13bfrancis@users.noreply.github.com> Date: Wed Nov 8 15:43:36 2023 -0500 fix index -1 error commit d489faa9f3be72ee145afdd8928dd4f795607424 Author: 13bfrancis <40218571+13bfrancis@users.noreply.github.com> Date: Wed Nov 8 15:10:45 2023 -0500 fix errors and lets reindex commit 9976017f6162cf35e80fdc0e42e986032494cec6 Author: 13bfrancis <40218571+13bfrancis@users.noreply.github.com> Date: Wed Nov 8 11:03:24 2023 -0500 fix typescript error for tombstone commit 2f6e865deae168935d6ef3a173ba32fe9abb33f1 Author: 13bfrancis <40218571+13bfrancis@users.noreply.github.com> Date: Wed Nov 8 09:53:04 2023 -0500 finished up flow (fingers crossed) commit 0afb047eb75e56f57f0f995c2726dbd6c5b4fc30 Author: 13bfrancis <40218571+13bfrancis@users.noreply.github.com> Date: Wed Nov 8 09:09:52 2023 -0500 fix breadcrumb type error commit 053441fdae06e6cd9fb0baa7997b9b796651b01b Author: 13bfrancis <40218571+13bfrancis@users.noreply.github.com> Date: Wed Nov 8 09:06:13 2023 -0500 remove action-type from schema (not needed) commit 00eff86febf6c27e1edbfe963346acb62633153d Author: 13bfrancis <40218571+13bfrancis@users.noreply.github.com> Date: Wed Nov 8 09:04:18 2023 -0500 add functionality for sinking actions to opensearch commit 43eaf995a5333e283a4732db947e1ec17a595db0 Author: Mike Dial Date: Tue Nov 7 14:47:25 2023 -0500 bringing in brian commit d8c4af484bdae439a55cb0e28a0b7181c9c430fa Author: Mike Dial Date: Tue Nov 7 14:27:13 2023 -0500 fix thing commit b4bbbeb8aa265e5541ac9feddafa008a24a91f85 Author: Mike Dial Date: Tue Nov 7 14:19:37 2023 -0500 brians lib commit 8b520a5b079122cdb6a440fa3e90d104a7f5e601 Author: Mike Dial Date: Tue Nov 7 14:15:19 2023 -0500 yut commit 1a9295266d3fe315aea70eaec595e0c9cd932f8d Merge: c045e365 35b4780f Author: Mike Dial Date: Tue Nov 7 13:42:17 2023 -0500 Merge branch 'master' into issuerai commit c045e36585e371aaaaee5a8333df07d4696c46fd Author: Mike Dial Date: Tue Nov 7 13:41:20 2023 -0500 sink commit f2d7ab62fe5a1af123e38346a2360b2cb4977efb Author: Mike Dial Date: Tue Nov 7 09:38:56 2023 -0500 basic func commit e164a3ea64116e149c71bdf14e844c63e1c77799 Author: Mike Dial Date: Tue Nov 7 06:51:17 2023 -0500 nothing commit 9970b9c827915fde5f457464702e9fba0b1bee1c Author: Mike Dial Date: Tue Nov 7 06:48:08 2023 -0500 form work commit 9943c1763ba931ac87965a395e052510550780bc Author: Mike Dial Date: Tue Nov 7 06:02:30 2023 -0500 base commit 76081ac99638c0eb767c05ff8eef4f820a0383b7 Author: Mike Dial Date: Tue Nov 7 05:40:31 2023 -0500 basic routing setup commit 5917321096f347869f2a8e32127a35cca78df8c0 Author: Mike Dial Date: Tue Nov 7 05:35:31 2023 -0500 Show issue rai for all records for cms user --- .../action-types/withdraw-record.ts | 7 + src/packages/shared-types/actions.ts | 1 + src/packages/shared-types/index.ts | 1 + src/packages/shared-types/onemac.ts | 4 +- src/packages/shared-types/seatool.ts | 4 +- src/services/api/handlers/action.ts | 75 +++++ .../api/handlers/getPackageActions.ts | 11 +- src/services/api/handlers/packageActions.ts | 81 ++++++ src/services/api/handlers/submit.ts | 4 +- src/services/api/libs/kafka.ts | 43 +++ src/services/api/serverless.yml | 24 ++ src/services/data/handlers/sink.ts | 43 ++- .../ui/src/pages/actions/IssueRai.tsx | 260 ++++++++++++++++++ src/services/ui/src/pages/actions/index.tsx | 3 + .../ui/src/pages/form/medicaid-form.tsx | 1 + .../ui/src/utils/actionLabelMapper.ts | 2 + 16 files changed, 549 insertions(+), 15 deletions(-) create mode 100644 src/packages/shared-types/action-types/withdraw-record.ts create mode 100644 src/services/api/handlers/action.ts create mode 100644 src/services/api/handlers/packageActions.ts create mode 100644 src/services/api/libs/kafka.ts create mode 100644 src/services/ui/src/pages/actions/IssueRai.tsx diff --git a/src/packages/shared-types/action-types/withdraw-record.ts b/src/packages/shared-types/action-types/withdraw-record.ts new file mode 100644 index 0000000000..f42ad9a7b4 --- /dev/null +++ b/src/packages/shared-types/action-types/withdraw-record.ts @@ -0,0 +1,7 @@ +import { z } from "zod"; + +export const withdrawRecordSchema = z.object({ + raiWithdrawEnabled: z.boolean(), +}); + +export type WithdrawRecord = z.infer; diff --git a/src/packages/shared-types/actions.ts b/src/packages/shared-types/actions.ts index 10d55e3ebf..1b89727b6d 100644 --- a/src/packages/shared-types/actions.ts +++ b/src/packages/shared-types/actions.ts @@ -1,4 +1,5 @@ export enum Action { ENABLE_RAI_WITHDRAW = "enable-rai-withdraw", DISABLE_RAI_WITHDRAW = "disable-rai-withdraw", + ISSUE_RAI = "issue-rai", } diff --git a/src/packages/shared-types/index.ts b/src/packages/shared-types/index.ts index 8774689af9..a0e34a527d 100644 --- a/src/packages/shared-types/index.ts +++ b/src/packages/shared-types/index.ts @@ -6,3 +6,4 @@ export * from "./onemac"; export * from "./opensearch"; export * from "./uploads"; export * from "./actions"; +export * from "./action-types/withdraw-record"; diff --git a/src/packages/shared-types/onemac.ts b/src/packages/shared-types/onemac.ts index f8d7df779f..56d59b7f29 100644 --- a/src/packages/shared-types/onemac.ts +++ b/src/packages/shared-types/onemac.ts @@ -17,12 +17,13 @@ export const onemacSchema = z.object({ submitterName: z.string(), submitterEmail: z.string(), attachments: z.array(onemacAttachmentSchema).nullish(), + raiWithdrawEnabled: z.boolean().optional(), raiResponses: z .array( z.object({ additionalInformation: z.string().nullable().default(null), submissionTimestamp: z.number(), - attachments: z.array(onemacAttachmentSchema), + attachments: z.array(onemacAttachmentSchema).nullish(), }) ) .nullish(), @@ -62,6 +63,7 @@ export const transformOnemac = (id: string) => { key, }; }) ?? null, + raiWithdrawEnabled: data.raiWithdrawEnabled, raiResponses: data.raiResponses?.map((response) => { return { diff --git a/src/packages/shared-types/seatool.ts b/src/packages/shared-types/seatool.ts index 3ea5dcd1eb..22f4bb78cb 100644 --- a/src/packages/shared-types/seatool.ts +++ b/src/packages/shared-types/seatool.ts @@ -109,7 +109,7 @@ export const seatoolSchema = z.object({ SPW_STATUS: z .array( z.object({ - SPW_STATUS_DESC: z.string().nullable(), + SPW_STATUS_DESC: z.string().nullish(), }) ) .nullable(), @@ -144,7 +144,7 @@ export const transformSeatoolData = (id: string) => { const { leadAnalystName, leadAnalystOfficerId } = getLeadAnalyst(data); const { raiReceivedDate, raiRequestedDate } = getRaiDate(data); const { stateStatus, cmsStatus } = getStatus( - data.SPW_STATUS?.[0].SPW_STATUS_DESC + data.SPW_STATUS?.at(-1)?.SPW_STATUS_DESC ); return { id, diff --git a/src/services/api/handlers/action.ts b/src/services/api/handlers/action.ts new file mode 100644 index 0000000000..8c99a38da8 --- /dev/null +++ b/src/services/api/handlers/action.ts @@ -0,0 +1,75 @@ +import { response } from "../libs/handler"; +import { APIGatewayEvent } from "aws-lambda"; +import { getPackage } from "../libs/package/getPackage"; +import { + getAuthDetails, + isAuthorized, + lookupUserAttributes, +} from "../libs/auth/user"; +import { packageActionsForResult } from "./getPackageActions"; +import { Action } from "shared-types"; +import { issueRai, toggleRaiResponseWithdraw } from "./packageActions"; + +export const handler = async (event: APIGatewayEvent) => { + try { + const actionType = event.pathParameters.actionType as Action; + const body = JSON.parse(event.body); + console.log(actionType); + console.log(body); + + // Check auth + const result = await getPackage(body.id); + const passedStateAuth = await isAuthorized(event, result._source.state); + if (!passedStateAuth) + return response({ + statusCode: 401, + body: { message: "Not authorized to view resources from this state" }, + }); + if (!result.found) + return response({ + statusCode: 404, + body: { message: "No record found for the given id" }, + }); + const authDetails = getAuthDetails(event); + const userAttr = await lookupUserAttributes( + authDetails.userId, + authDetails.poolId + ); + + // Check that the package action is available + const actions: Action[] = packageActionsForResult(userAttr, result); + if (!actions.includes(actionType)) { + return response({ + statusCode: 401, + body: { + message: `You are not authorized to perform ${actionType} on ${body.id}`, + }, + }); + } + + // Call package action + switch (actionType) { + case Action.ISSUE_RAI: + await issueRai(body.id, Date.now()); + break; + case Action.ENABLE_RAI_WITHDRAW: + await toggleRaiResponseWithdraw(body, true); + break; + case Action.DISABLE_RAI_WITHDRAW: + await toggleRaiResponseWithdraw(body, false); + break; + default: + throw `No ${actionType} action available`; + } + return response({ + statusCode: 200, + body: { message: "success" }, + }); + } catch (error) { + console.error({ error }); + return response({ + statusCode: 500, + body: { message: "Internal server error" }, + }); + } +}; diff --git a/src/services/api/handlers/getPackageActions.ts b/src/services/api/handlers/getPackageActions.ts index db458a60d9..87fb4d1bc0 100644 --- a/src/services/api/handlers/getPackageActions.ts +++ b/src/services/api/handlers/getPackageActions.ts @@ -15,13 +15,20 @@ type GetPackageActionsBody = { /** Generates an array of allowed actions from a combination of user attributes * and OS result data */ -const packageActionsForResult = ( +export const packageActionsForResult = ( user: CognitoUserAttributes, result: ItemResult ): Action[] => { const actions = []; if (isCmsUser(user)) { - actions.push(Action.ENABLE_RAI_WITHDRAW); + if (!result._source.raiWithdrawEnabled) { + // result._source.raiReceivedDate && + actions.push(Action.ENABLE_RAI_WITHDRAW); + } + if (result._source.raiWithdrawEnabled) { + actions.push(Action.DISABLE_RAI_WITHDRAW); + } + actions.push(Action.ISSUE_RAI); } return actions; }; diff --git a/src/services/api/handlers/packageActions.ts b/src/services/api/handlers/packageActions.ts new file mode 100644 index 0000000000..53299788bc --- /dev/null +++ b/src/services/api/handlers/packageActions.ts @@ -0,0 +1,81 @@ +import * as sql from "mssql"; + +const user = process.env.dbUser; +const password = process.env.dbPassword; +const server = process.env.dbIp; +const port = parseInt(process.env.dbPort); +const config = { + user: user, + password: password, + server: server, + port: port, + database: "SEA", +}; + +import { Action, OneMacSink, transformOnemac } from "shared-types"; +import { produceMessage } from "../libs/kafka"; +import { response } from "../libs/handler"; + +const TOPIC_NAME = process.env.topicName; + +export async function issueRai(id: string, timestamp: number) { + console.log("CMS issuing a new RAI"); + const pool = await sql.connect(config); + const query = ` + Insert into SEA.dbo.RAI (ID_Number, RAI_Requested_Date) + values ('${id}' + ,dateadd(s, convert(int, left(${timestamp}, 10)), cast('19700101' as datetime))) + `; + // Prepare the request + const request = pool.request(); + request.input("ID_Number", sql.VarChar, id); + request.input("RAI_Requested_Date", sql.DateTime, new Date(timestamp)); + + const result = await sql.query(query); + console.log(result); + await pool.close(); +} + +export async function withdrawRai(id, timestamp) { + console.log("CMS withdrawing an RAI"); +} + +export async function respondToRai(id, timestamp) { + console.log("State respnding to RAI"); +} + +export async function withdrawPackage(id, timestamp) { + console.log("State withdrawing a package."); +} + +export async function toggleRaiResponseWithdraw( + body: { id: string }, + toggle: boolean +) { + const { id } = body; + try { + await produceMessage( + TOPIC_NAME, + id, + JSON.stringify({ + raiWithdrawEnabled: toggle, + actionType: toggle + ? Action.ENABLE_RAI_WITHDRAW + : Action.DISABLE_RAI_WITHDRAW, + }) + ); + + return response({ + statusCode: 200, + body: { + message: "record successfully submitted", + }, + }); + } catch (err) { + console.log(err); + + return response({ + statusCode: 500, + }); + } +} diff --git a/src/services/api/handlers/submit.ts b/src/services/api/handlers/submit.ts index bd60a40857..adb82ff211 100644 --- a/src/services/api/handlers/submit.ts +++ b/src/services/api/handlers/submit.ts @@ -15,7 +15,7 @@ const config = { database: "SEA", }; -import { Kafka, KafkaMessage } from "kafkajs"; +import { Kafka, Message } from "kafkajs"; import { OneMacSink, transformOnemac } from "shared-types"; const kafka = new Kafka({ @@ -117,7 +117,7 @@ async function produceMessage(topic, key, value) { await producer.connect(); console.log("connected"); - const message: KafkaMessage = { + const message: Message = { key: key, value: value, partition: 0, diff --git a/src/services/api/libs/kafka.ts b/src/services/api/libs/kafka.ts new file mode 100644 index 0000000000..d7dcff28cb --- /dev/null +++ b/src/services/api/libs/kafka.ts @@ -0,0 +1,43 @@ +import { Kafka, Message } from "kafkajs"; + +const kafka = new Kafka({ + clientId: "submit", + brokers: process.env.brokerString.split(","), + retry: { + initialRetryTime: 300, + retries: 8, + }, + ssl: { + rejectUnauthorized: false, + }, +}); + +export const producer = kafka.producer(); + +export async function produceMessage( + topic: string, + key: string, + value: string +) { + await producer.connect(); + + const message: Message = { + key: key, + value: value, + partition: 0, + headers: { source: "micro" }, + }; + console.log(message); + + try { + await producer.send({ + topic, + messages: [message], + }); + console.log("Message sent successfully"); + } catch (error) { + console.error("Error sending message:", error); + } finally { + await producer.disconnect(); + } +} diff --git a/src/services/api/serverless.yml b/src/services/api/serverless.yml index a45935386b..680b735c0c 100644 --- a/src/services/api/serverless.yml +++ b/src/services/api/serverless.yml @@ -195,6 +195,30 @@ functions: subnetIds: >- ${self:custom.vpc.privateSubnets} provisionedConcurrency: ${param:submitProvisionedConcurrency} + action: + handler: handlers/action.handler + maximumRetryAttempts: 0 + environment: + region: ${self:provider.region} + osDomain: ${param:osDomain} + dbIp: ${self:custom.dbInfo.ip} + dbPort: ${self:custom.dbInfo.port} + dbUser: ${self:custom.dbInfo.user} + dbPassword: ${self:custom.dbInfo.password} + topicName: ${param:topicName} + brokerString: ${self:custom.brokerString} + events: + - http: + path: /action/{actionType} + method: post + cors: true + authorizer: aws_iam + vpc: + securityGroupIds: + - Ref: SecurityGroup + subnetIds: >- + ${self:custom.vpc.privateSubnets} + provisionedConcurrency: ${param:submitProvisionedConcurrency} # reuse submit's concurrency resources: Resources: ApiGateway400ErrorCount: diff --git a/src/services/data/handlers/sink.ts b/src/services/data/handlers/sink.ts index c0bd9c5d46..35cdf16076 100644 --- a/src/services/data/handlers/sink.ts +++ b/src/services/data/handlers/sink.ts @@ -11,6 +11,7 @@ import { OneMacTransform, transformOnemac, } from "shared-types/onemac"; +import { Action, WithdrawRecord, withdrawRecordSchema } from "shared-types"; if (!process.env.osDomain) { throw "ERROR: process.env.osDomain is required,"; @@ -92,8 +93,11 @@ export const seatool: Handler = async (event) => { }; export const onemac: Handler = async (event) => { - const oneMacRecords: (OneMacTransform | OneMacRecordsToDelete)[] = []; - const docObject: Record = {}; + const oneMacRecords: ( + | OneMacTransform + | OneMacRecordsToDelete + | (WithdrawRecord & { id: string }) + )[] = []; for (const recordKey of Object.keys(event.records)) { for (const onemacRecord of event.records[recordKey] as { @@ -105,7 +109,32 @@ export const onemac: Handler = async (event) => { if (value) { const id: string = decode(key); const record = { id, ...JSON.parse(decode(value)) }; - if ( + const isActionType = "actionType" in record; + + if (isActionType) { + switch (record.actionType as Action) { + case Action.ENABLE_RAI_WITHDRAW: + case Action.DISABLE_RAI_WITHDRAW: { + const result = withdrawRecordSchema.safeParse(record); + if (result.success) { + // write to opensearch + // account for compaction + oneMacRecords.push({ + id, + ...result.data, + }); + } else { + console.log( + `ERROR: Invalid Payload for this action type (${record.actionType})` + ); + } + + break; + } + case Action.ISSUE_RAI: + return; + } + } else if ( record && // testing if we have a record (record.origin === "micro" || // testing if this is a micro record (record.sk === "Package" && // testing if this is a legacy onemac package record @@ -121,7 +150,7 @@ export const onemac: Handler = async (event) => { result.error.message ); } else { - docObject[id] = result.data; + oneMacRecords.push(result.data); } } } else { @@ -129,6 +158,7 @@ export const onemac: Handler = async (event) => { const oneMacTombstone: OneMacRecordsToDelete = { id, additionalInformation: undefined, + raiWithdrawEnabled: undefined, attachments: undefined, submitterEmail: undefined, submitterName: undefined, @@ -136,7 +166,7 @@ export const onemac: Handler = async (event) => { raiResponses: undefined, }; - docObject[id] = oneMacTombstone; + oneMacRecords.push(oneMacTombstone); console.log( `Record ${id} has been nullified with the following data: `, @@ -145,9 +175,6 @@ export const onemac: Handler = async (event) => { } } } - for (const [, b] of Object.entries(docObject)) { - oneMacRecords.push(b); - } try { await os.bulkUpdateData(osDomain, "main", oneMacRecords); } catch (error) { diff --git a/src/services/ui/src/pages/actions/IssueRai.tsx b/src/services/ui/src/pages/actions/IssueRai.tsx new file mode 100644 index 0000000000..badc89f60c --- /dev/null +++ b/src/services/ui/src/pages/actions/IssueRai.tsx @@ -0,0 +1,260 @@ +import { useParams } from "react-router-dom"; +import * as I from "@/components/Inputs"; +import { API } from "aws-amplify"; +import { useState } from "react"; +import { type SubmitHandler, useForm } from "react-hook-form"; +import { z } from "zod"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { useGetUser } from "@/api/useGetUser"; +// import { BREAD_CRUMB_CONFIG_PACKAGE_DETAILS } from "@/components/BreadCrumb/bread-crumb-config"; +import { + SimplePageContainer, + Alert, + LoadingSpinner, + Modal, + BreadCrumbs, +} from "@/components"; +import { FAQ_TARGET, ROUTES } from "@/routes"; +import { Link, useNavigate } from "react-router-dom"; + +const formSchema = z.object({ + additionalInformation: z.string().max(4000).optional(), +}); +export type IssueRaiFormSchema = z.infer; + +export const IssueRai = () => { + const { id, type } = useParams<{ + id: string; + type: string; + }>(); + const form = useForm({ + resolver: zodResolver(formSchema), + }); + const { data: user } = useGetUser(); + const [successModalIsOpen, setSuccessModalIsOpen] = useState(false); + const [errorModalIsOpen, setErrorModalIsOpen] = useState(false); + const [cancelModalIsOpen, setCancelModalIsOpen] = useState(false); + + const handleSubmit: SubmitHandler = async (data) => { + console.log(data); + const dataToSubmit = { + id, + additionalInformation: data?.additionalInformation ?? null, + }; + + let actionResponse; + try { + console.log(dataToSubmit); + actionResponse = await API.post("os", "/action/issue-rai", { + body: dataToSubmit, + }); + console.log(actionResponse); + // setSuccessModalIsOpen(true); + console.log("END OF TRY"); + } catch (err) { + console.log(err); + setErrorModalIsOpen(true); + console.log("CATCH"); + } + }; + + return ( + + {/* */} + +
+
+

Issue RAI

+

+ Indicates a required field +

+

+ Once you submit this form, a confirmation email is sent to you and + to the original submitter.{" "} + + If you leave this page, you will lose your progress on this + form. + +

+
+ {/*-------------------------------------------------------- */} + ( + +

+ Additional Information +

+ + Add anything else you would like to share with the state + regarding this RAI. + + + 4,000 characters allowed +
+ )} + /> + {/*-------------------------------------------------------- */} +
+ + Once you submit this form, a confirmation email is sent to you and + to the original submitter. + +
+ {Object.keys(form.formState.errors).length !== 0 ? ( + + Missing or malformed information. Please see errors above. + + ) : null} + {form.formState.isSubmitting ? ( +
+ +
+ ) : null} +
+ + Submit + + setCancelModalIsOpen(true)} + className="px-12" + > + Cancel + + } + /> + + } + /> + + } + /> +
+ +
+
+ ); +}; + +type SuccessModalProps = { + id: string; +}; +const SuccessModalContent = ({ id }: SuccessModalProps) => { + const navigate = useNavigate(); + return ( +
+
+
Submission Success!
+

+ RAI for {id} was successfully issued. +
+ Please be aware that it may take up to a minute for this action to be + reflected in the dashboard. +

+
+ navigate(ROUTES.DASHBOARD)} + > + Go to Dashboard + +
+ ); +}; + +type ErrorModalProps = { id: string; setModalIsOpen: (open: boolean) => void }; +const ErrorModalContent = ({ id, setModalIsOpen }: ErrorModalProps) => { + return ( +
+
+
Submission Error:
+

+ An error occurred during issue. +
+ You may close this window and try again, however, this likely requires + support. +
+
+ Please contact the{" "} + + helpdesk + {" "} + . You may include the following in your support request:
+
+

    +
  • SPA ID: {id}
  • +
  • Timestamp: {Date.now()}
  • +
+

+
+ setModalIsOpen(false)} + > + Close + +
+ ); +}; + +type CancelModalProps = { setCancelModalIsOpen: (open: boolean) => void }; +const CancelModalContent = ({ setCancelModalIsOpen }: CancelModalProps) => { + const navigate = useNavigate(); + return ( +
+
+
Are you sure you want to cancel?
+

If you leave this page, you will lose your progress on this form.

+
+
+ navigate(ROUTES.DASHBOARD)} + > + Yes + +
+ setCancelModalIsOpen(false)} + > + No, Return to Form + +
+
+
+ ); +}; diff --git a/src/services/ui/src/pages/actions/index.tsx b/src/services/ui/src/pages/actions/index.tsx index 70666e98f2..a99466f07c 100644 --- a/src/services/ui/src/pages/actions/index.tsx +++ b/src/services/ui/src/pages/actions/index.tsx @@ -1,6 +1,7 @@ import { Navigate, useParams } from "react-router-dom"; import { ROUTES } from "@/routes"; import { ToggleRaiResponseWithdraw } from "@/pages/actions/ToggleRaiResponseWithdraw"; +import { IssueRai } from "@/pages/actions/IssueRai"; import { Action } from "shared-types"; export const ActionFormIndex = () => { @@ -9,6 +10,8 @@ export const ActionFormIndex = () => { case Action.ENABLE_RAI_WITHDRAW: case Action.DISABLE_RAI_WITHDRAW: return ; + case Action.ISSUE_RAI: + return ; default: // TODO: Better error communication instead of navigate? // "Hey, this action doesn't exist. Click to go back to the Dashboard." diff --git a/src/services/ui/src/pages/form/medicaid-form.tsx b/src/services/ui/src/pages/form/medicaid-form.tsx index 2b59d97564..7561998d12 100644 --- a/src/services/ui/src/pages/form/medicaid-form.tsx +++ b/src/services/ui/src/pages/form/medicaid-form.tsx @@ -168,6 +168,7 @@ export const MedicaidForm = () => { origin: "micro", authority: "medicaid spa", raiResponses: [], + raiWithdrawEnabled: false, submitterEmail: user?.user?.email ?? "N/A", submitterName: `${user?.user?.given_name} ${user?.user?.family_name}` ?? "N/A", diff --git a/src/services/ui/src/utils/actionLabelMapper.ts b/src/services/ui/src/utils/actionLabelMapper.ts index 858d709ea8..9234e3ac41 100644 --- a/src/services/ui/src/utils/actionLabelMapper.ts +++ b/src/services/ui/src/utils/actionLabelMapper.ts @@ -6,5 +6,7 @@ export const mapActionLabel = (a: Action) => { return "Enable Formal RAI Response Withdraw"; case Action.DISABLE_RAI_WITHDRAW: return "Disable Formal RAI Response Withdraw"; + case Action.ISSUE_RAI: + return "Issue RAI"; } };