diff --git a/bin/cli/src/commands/deploy.ts b/bin/cli/src/commands/deploy.ts index a855ef96d2..a4f6450647 100644 --- a/bin/cli/src/commands/deploy.ts +++ b/bin/cli/src/commands/deploy.ts @@ -1,5 +1,9 @@ import { Argv } from "yargs"; -import { LabeledProcessRunner, writeUiEnvFile } from "../lib/"; +import { + checkIfAuthenticated, + LabeledProcessRunner, + writeUiEnvFile, +} from "../lib/"; import path from "path"; import { execSync } from "child_process"; import { @@ -17,6 +21,7 @@ export const deploy = { return yargs.option("stage", { type: "string", demandOption: true }); }, handler: async (options: { stage: string; stack?: string }) => { + await checkIfAuthenticated(); await runner.run_command_and_output( "CDK Deploy", ["cdk", "deploy", "-c", `stage=${options.stage}`, "--all"], diff --git a/bin/cli/src/commands/destroy.ts b/bin/cli/src/commands/destroy.ts index 0cc5669185..645ee768a5 100644 --- a/bin/cli/src/commands/destroy.ts +++ b/bin/cli/src/commands/destroy.ts @@ -4,7 +4,7 @@ import { DeleteStackCommand, waitUntilStackDeleteComplete, } from "@aws-sdk/client-cloudformation"; -import { confirmDestroyCommand } from "../lib"; +import { checkIfAuthenticated, confirmDestroyCommand } from "../lib"; const waitForStackDeleteComplete = async ( client: CloudFormationClient, @@ -37,6 +37,8 @@ export const destroy = { wait: boolean; verify: boolean; }) => { + await checkIfAuthenticated(); + const stackName = `${process.env.PROJECT}-${stage}`; if (/prod/i.test(stage)) { diff --git a/bin/cli/src/commands/e2e.ts b/bin/cli/src/commands/e2e.ts index 845ab133e1..0874957631 100644 --- a/bin/cli/src/commands/e2e.ts +++ b/bin/cli/src/commands/e2e.ts @@ -1,5 +1,5 @@ import { Argv } from "yargs"; -import { LabeledProcessRunner } from "../lib"; +import { checkIfAuthenticated, LabeledProcessRunner } from "../lib"; const runner = new LabeledProcessRunner(); @@ -13,6 +13,7 @@ export const e2e = { default: false, }), handler: async ({ ui }: { ui: boolean }) => { + await checkIfAuthenticated(); await runner.run_command_and_output( "Install playwright", ["bun", "playwright", "install", "--with-deps"], diff --git a/bin/cli/src/commands/get-cost.ts b/bin/cli/src/commands/get-cost.ts index 0e4bb1a5b9..ab837c1f54 100644 --- a/bin/cli/src/commands/get-cost.ts +++ b/bin/cli/src/commands/get-cost.ts @@ -3,6 +3,7 @@ import { CostExplorerClient, GetCostAndUsageCommand, } from "@aws-sdk/client-cost-explorer"; +import { checkIfAuthenticated } from "../lib"; export const getCost = { command: "get-cost", @@ -11,6 +12,8 @@ export const getCost = { return yargs.option("stage", { type: "string", demandOption: true }); }, handler: async (options: { stage: string; stack?: string }) => { + await checkIfAuthenticated(); + const tags = { PROJECT: [process.env.PROJECT!], STAGE: [options.stage], diff --git a/bin/cli/src/commands/logs.ts b/bin/cli/src/commands/logs.ts index b62dada39b..62d1998e1c 100644 --- a/bin/cli/src/commands/logs.ts +++ b/bin/cli/src/commands/logs.ts @@ -1,5 +1,5 @@ import { Argv } from "yargs"; -import { LabeledProcessRunner } from "../lib/"; +import { checkIfAuthenticated, LabeledProcessRunner } from "../lib/"; import simpleGit from "simple-git"; import { ResourceGroupsTaggingAPIClient, @@ -29,6 +29,8 @@ export const logs = { demandOption: true, }), handler: async (options: { stage?: string; functionName: string }) => { + await checkIfAuthenticated(); + let { stage, functionName } = options; if (!stage) { const git = simpleGit(); diff --git a/bin/cli/src/commands/open.ts b/bin/cli/src/commands/open.ts index 3838f7ced8..1672fd6169 100644 --- a/bin/cli/src/commands/open.ts +++ b/bin/cli/src/commands/open.ts @@ -1,5 +1,5 @@ import { Argv } from "yargs"; -import { openUrl } from "../lib"; +import { checkIfAuthenticated, openUrl } from "../lib"; import { GetParameterCommand, SSMClient } from "@aws-sdk/client-ssm"; const createOpenCommand = ( @@ -12,6 +12,7 @@ const createOpenCommand = ( builder: (yargs: Argv) => yargs.option("stage", { type: "string", demandOption: true }), handler: async ({ stage }: { stage: string }) => { + await checkIfAuthenticated(); const url = JSON.parse( ( await new SSMClient({ region: "us-east-1" }).send( diff --git a/bin/cli/src/commands/ui.ts b/bin/cli/src/commands/ui.ts index 977d5a6251..41113315d3 100644 --- a/bin/cli/src/commands/ui.ts +++ b/bin/cli/src/commands/ui.ts @@ -1,5 +1,9 @@ import { Argv } from "yargs"; -import { LabeledProcessRunner, writeUiEnvFile } from "../lib"; +import { + checkIfAuthenticated, + LabeledProcessRunner, + writeUiEnvFile, +} from "../lib"; const runner = new LabeledProcessRunner(); @@ -10,6 +14,7 @@ export const ui = { return yargs.option("stage", { type: "string", demandOption: true }); }, handler: async (options: { stage: string }) => { + await checkIfAuthenticated(); await writeUiEnvFile(options.stage, true); await runner.run_command_and_output( `Build`, diff --git a/bin/cli/src/lib/index.ts b/bin/cli/src/lib/index.ts index 520601fc8c..7a2c495644 100644 --- a/bin/cli/src/lib/index.ts +++ b/bin/cli/src/lib/index.ts @@ -1,4 +1,5 @@ export * from "./open-url"; export * from "./runner"; +export * from "./sts"; export * from "./utils"; export * from "./write-ui-env-file"; diff --git a/bin/cli/src/lib/sts.ts b/bin/cli/src/lib/sts.ts new file mode 100644 index 0000000000..66b3aac552 --- /dev/null +++ b/bin/cli/src/lib/sts.ts @@ -0,0 +1,27 @@ +import { STSClient, GetCallerIdentityCommand } from "@aws-sdk/client-sts"; + +export async function checkIfAuthenticated(): Promise { + try { + const client = new STSClient({ region: process.env.REGION_A }); + const command = new GetCallerIdentityCommand({}); + await client.send(command); + } catch (error) { + if (error instanceof Error) { + if ( + error.message.includes("Could not load credentials from any providers") + ) { + console.error( + `\x1b[31m\x1b[1mERROR: This command requires AWS credentials available to your terminal. Please configure AWS credentials and try again.\x1b[0m`, + ); + } else { + console.error( + "Error occurred while checking authentication:", + error.message, + ); + } + } else { + console.error("An unknown error occurred:", error); + } + process.exit(1); + } +} diff --git a/bin/cli/src/run.ts b/bin/cli/src/run.ts index 4d4d461a12..bbc6e96751 100644 --- a/bin/cli/src/run.ts +++ b/bin/cli/src/run.ts @@ -14,6 +14,11 @@ import { } from "./commands"; yargs + .fail((msg, err, _) => { + if (err) throw err; + if (msg) console.error(msg); + process.exit(1); + }) .command(deploy) .command(destroy) .command(docs) diff --git a/lib/lambda/action.ts b/lib/lambda/action.ts index b98fc315e2..5f374d8cd7 100644 --- a/lib/lambda/action.ts +++ b/lib/lambda/action.ts @@ -18,21 +18,8 @@ import { completeIntake, removeAppkChild, } from "./package-actions"; -import { setupWriteService } from "./package-actions/setup-write-service"; - -const checkIfActionType = ( - potentialActionType: unknown, -): potentialActionType is Action => { - if (potentialActionType) { - return true; - } - return false; -}; export const handler = async (event: APIGatewayEvent) => { - if (typeof globalThis.packageActionWriteService === "undefined") { - global.packageActionWriteService = await setupWriteService(); - } if (!event.pathParameters || !event.pathParameters.actionType) { return response({ statusCode: 400, @@ -94,10 +81,10 @@ export const handler = async (event: APIGatewayEvent) => { await respondToRai(body, result._source); break; case Action.ENABLE_RAI_WITHDRAW: - await toggleRaiResponseWithdraw(body, true); + await toggleRaiResponseWithdraw({ toggle: true, ...body }); break; case Action.DISABLE_RAI_WITHDRAW: - await toggleRaiResponseWithdraw(body, false); + await toggleRaiResponseWithdraw(body); break; case Action.WITHDRAW_RAI: await withdrawRai(body, result._source); diff --git a/lib/lambda/package-actions/complete-intake/complete-intake.ts b/lib/lambda/package-actions/complete-intake/complete-intake.ts index 21f8156a89..cf27f28a2f 100644 --- a/lib/lambda/package-actions/complete-intake/complete-intake.ts +++ b/lib/lambda/package-actions/complete-intake/complete-intake.ts @@ -1,12 +1,9 @@ import { completeIntakeSchema, Action } from "shared-types"; import { response } from "../../../libs/handler-lib"; import { TOPIC_NAME } from "../consts"; -import { type PackageActionWriteService } from "../services/package-action-write-service"; +import { completeIntakeAction } from "../services/package-action-write-service"; -export async function completeIntake( - body: any, - packageActionWriteService: PackageActionWriteService = globalThis.packageActionWriteService, -) { +export async function completeIntake(body: any) { console.log("CMS performing intake for a record."); const result = completeIntakeSchema.safeParse(body); @@ -27,7 +24,7 @@ export async function completeIntake( const now = new Date().getTime(); - await packageActionWriteService.completeIntake({ + await completeIntakeAction({ timestamp: now, action: Action.COMPLETE_INTAKE, cpoc: result.data.cpoc, diff --git a/lib/lambda/package-actions/issue-rai/issue-rai.ts b/lib/lambda/package-actions/issue-rai/issue-rai.ts index 2f12d9c7f7..1c1d628517 100644 --- a/lib/lambda/package-actions/issue-rai/issue-rai.ts +++ b/lib/lambda/package-actions/issue-rai/issue-rai.ts @@ -2,12 +2,9 @@ import { RaiIssue, raiIssueSchema, Action, SEATOOL_STATUS } from "shared-types"; import { seaToolFriendlyTimestamp } from "shared-utils"; import { response } from "../../../libs/handler-lib"; import { TOPIC_NAME } from "../consts"; -import { type PackageActionWriteService } from "../services/package-action-write-service"; +import { issueRaiAction } from "../services/package-action-write-service"; -export async function issueRai( - body: RaiIssue, - packageActionWriteService: PackageActionWriteService = globalThis.packageActionWriteService, -) { +export async function issueRai(body: RaiIssue) { console.log("CMS issuing a new RAI"); const now = new Date().getTime(); const today = seaToolFriendlyTimestamp(); @@ -27,7 +24,7 @@ export async function issueRai( }); } - await packageActionWriteService.issueRai({ + await issueRaiAction({ ...result.data, action: Action.ISSUE_RAI, id: result.data.id, diff --git a/lib/lambda/package-actions/remove-appk-child/remove-appk-child.ts b/lib/lambda/package-actions/remove-appk-child/remove-appk-child.ts index 41255f05b6..1423c36101 100644 --- a/lib/lambda/package-actions/remove-appk-child/remove-appk-child.ts +++ b/lib/lambda/package-actions/remove-appk-child/remove-appk-child.ts @@ -7,6 +7,7 @@ import { import { seaToolFriendlyTimestamp } from "shared-utils"; import { response } from "../../../libs/handler-lib"; import { TOPIC_NAME } from "../consts"; +import { removeAppkChildAction } from "../services/package-action-write-service"; export async function removeAppkChild(doc: opensearch.main.Document) { const result = removeAppkChildSchema.safeParse(doc); @@ -22,7 +23,7 @@ export async function removeAppkChild(doc: opensearch.main.Document) { const now = new Date().getTime(); const today = seaToolFriendlyTimestamp(); - await packageActionWriteService.removeAppkChild({ + await removeAppkChildAction({ ...result.data, action: Action.REMOVE_APPK_CHILD, id: result.data.id, diff --git a/lib/lambda/package-actions/respond-to-rai/respond-to-rai.test.ts b/lib/lambda/package-actions/respond-to-rai/respond-to-rai.test.ts index 618aa3eafd..d7d0da72a9 100644 --- a/lib/lambda/package-actions/respond-to-rai/respond-to-rai.test.ts +++ b/lib/lambda/package-actions/respond-to-rai/respond-to-rai.test.ts @@ -1,10 +1,14 @@ import { respondToRai } from "./respond-to-rai"; import { vi, describe, it, expect, beforeEach } from "vitest"; -import { MockPackageActionWriteService } from "../services/package-action-write-service"; -import { Action, raiResponseSchema } from "shared-types"; +import { raiResponseSchema } from "shared-types"; import { generateMock } from "@anatine/zod-mock"; -import { ExtendedItemResult } from "../../../libs/api/package"; -const mockPackageWrite = new MockPackageActionWriteService(); +import * as packageActionWriteService from "../services/package-action-write-service"; + +vi.mock("../services/package-action-write-service", () => { + return { + respondToRaiAction: vi.fn(), + }; +}); describe("respondToRai", async () => { beforeEach(() => { @@ -19,52 +23,42 @@ describe("respondToRai", async () => { raiReceivedDate: "999", raiWithdrawnDate: "999", }, - mockPackageWrite, ); expect(response.statusCode).toBe(400); }); it("should return a 400 when no requested date is sent", async () => { const mockData = generateMock(raiResponseSchema); - const response = await respondToRai( - mockData, - { - raiRequestedDate: null, - raiReceivedDate: null, - raiWithdrawnDate: null, - }, - mockPackageWrite, - ); + const response = await respondToRai(mockData, { + raiRequestedDate: null, + raiReceivedDate: null, + raiWithdrawnDate: null, + }); expect(response.statusCode).toBe(400); }); it("should return a 400 when a bad requestDate is sent", async () => { const mockData = generateMock(raiResponseSchema); - const response = await respondToRai( - mockData, - { - raiRequestedDate: "123456789", // should be an isoString - raiReceivedDate: null, - raiWithdrawnDate: null, - }, - mockPackageWrite, - ); + const response = await respondToRai(mockData, { + raiRequestedDate: "123456789", // should be an isoString + raiReceivedDate: null, + raiWithdrawnDate: null, + }); expect(response.statusCode).toBe(400); expect(JSON.parse(response.body).message).toBe("Event validation error"); }); it("should return a 200 when a good payload is sent", async () => { - const packageWriteSpy = vi.spyOn(mockPackageWrite, "respondToRai"); - const mockData = generateMock(raiResponseSchema); - const response = await respondToRai( - mockData, - { - raiRequestedDate: new Date().toISOString(), - raiReceivedDate: null, - raiWithdrawnDate: null, - }, - mockPackageWrite, + const packageWriteSpy = vi.spyOn( + packageActionWriteService, + "respondToRaiAction", ); + const mockData = generateMock(raiResponseSchema); + const response = await respondToRai(mockData, { + raiRequestedDate: new Date().toISOString(), + raiReceivedDate: null, + raiWithdrawnDate: null, + }); expect(packageWriteSpy).toHaveBeenCalledOnce(); expect(response.statusCode).toBe(200); }); diff --git a/lib/lambda/package-actions/respond-to-rai/respond-to-rai.ts b/lib/lambda/package-actions/respond-to-rai/respond-to-rai.ts index ca413bbc13..a3bf599e63 100644 --- a/lib/lambda/package-actions/respond-to-rai/respond-to-rai.ts +++ b/lib/lambda/package-actions/respond-to-rai/respond-to-rai.ts @@ -3,7 +3,7 @@ import { seaToolFriendlyTimestamp } from "shared-utils"; import { response } from "../../../libs/handler-lib"; import { TOPIC_NAME } from "../consts"; import { ExtendedItemResult } from "../../../libs/api/package"; -import { PackageWriteClass } from "../services/package-action-write-service"; +import { respondToRaiAction } from "../services/package-action-write-service"; export async function respondToRai( body: any, @@ -11,7 +11,6 @@ export async function respondToRai( ExtendedItemResult["_source"], "raiReceivedDate" | "raiRequestedDate" | "raiWithdrawnDate" >, - packageActionWriteService: PackageWriteClass = globalThis.packageActionWriteService, ) { console.log("State responding to RAI"); if (!document.raiRequestedDate) { @@ -45,7 +44,7 @@ export async function respondToRai( }); } try { - await packageActionWriteService.respondToRai({ + await respondToRaiAction({ ...result.data, action: Action.RESPOND_TO_RAI, id: result.data.id, diff --git a/lib/lambda/package-actions/services/mako-write-service.ts b/lib/lambda/package-actions/services/mako-write-service.ts index 2080b43c9c..07c697488f 100644 --- a/lib/lambda/package-actions/services/mako-write-service.ts +++ b/lib/lambda/package-actions/services/mako-write-service.ts @@ -1,5 +1,6 @@ import { type Action } from "shared-types"; import { getNextBusinessDayTimestamp } from "shared-utils"; +import { produceMessage } from "../../../libs/api/kafka"; export type MessageProducer = ( topic: string, @@ -51,147 +52,146 @@ export type WithdrawPackageDto = { action: Action; } & Record; -export class MakoWriteService { - #messageProducer: MessageProducer; - - constructor(messageProducer: MessageProducer) { - this.#messageProducer = messageProducer; - } +export type UpdateIdDto = { + topicName: string; + id: string; + newId: string; + action: Action; +} & Record; - async completeIntake({ - action, - id, - timestamp, +export const completeIntakeMako = async ({ + action, + id, + timestamp, + topicName, + ...data +}: CompleteIntakeDto) => + produceMessage( topicName, - ...data - }: CompleteIntakeDto) { - await this.#messageProducer( - topicName, - id, - JSON.stringify({ - actionType: action, - timestamp, - ...data, - }), - ); - } - - async issueRai({ action, id, topicName, ...data }: IssueRaiDto) { - await this.#messageProducer( - topicName, - id, - JSON.stringify({ - ...data, - id, - actionType: action, - }), - ); - } - - async respondToRai({ - action, id, - responseDate, + JSON.stringify({ + actionType: action, + timestamp, + ...data, + }), + ); + +export const issueRaiMako = async ({ + action, + id, + topicName, + ...data +}: IssueRaiDto) => + produceMessage( topicName, - ...data - }: RespondToRaiDto) { - await this.#messageProducer( - topicName, - id, - JSON.stringify({ - ...data, - id, - responseDate, - actionType: action, - notificationMetadata: { - submissionDate: getNextBusinessDayTimestamp(), - }, - }), - ); - } - - async withdrawRai({ action, id, topicName, ...data }: WithdrawRaiDto) { - await this.#messageProducer( - topicName, - id, - JSON.stringify({ - ...data, - id, - actionType: action, - notificationMetadata: { - submissionDate: getNextBusinessDayTimestamp(), - }, - }), - ); - } - - async toggleRaiResponseWithdraw({ - action, id, + JSON.stringify({ + ...data, + id, + actionType: action, + }), + ); + +export const respondToRaiMako = async ({ + action, + id, + responseDate, + topicName, + ...data +}: RespondToRaiDto) => + produceMessage( topicName, - ...data - }: ToggleRaiResponseDto) { - await this.#messageProducer( - topicName, + id, + JSON.stringify({ + ...data, id, - JSON.stringify({ - ...data, - id, - actionType: action, - }), - ); - } - - async removeAppkChild({ - action, + responseDate, + actionType: action, + notificationMetadata: { + submissionDate: getNextBusinessDayTimestamp(), + }, + }), + ); + +export const withdrawRaiMako = async ({ + action, + id, + topicName, + ...data +}: WithdrawRaiDto) => + produceMessage( + topicName, id, + JSON.stringify({ + ...data, + id, + actionType: action, + notificationMetadata: { + submissionDate: getNextBusinessDayTimestamp(), + }, + }), + ); + +export const toggleRaiResponseWithdrawMako = async ({ + action, + id, + topicName, + ...data +}: ToggleRaiResponseDto) => + produceMessage( topicName, - ...data - }: RemoveAppkChildDto) { - await this.#messageProducer( - topicName, + id, + JSON.stringify({ + ...data, id, - JSON.stringify({ - ...data, - id, - actionType: action, - }), - ); - } - - async withdrawPackage({ - action, + actionType: action, + }), + ); + +export const removeAppkChildMako = async ({ + action, + id, + topicName, + ...data +}: RemoveAppkChildDto) => + produceMessage( + topicName, id, + JSON.stringify({ + ...data, + id, + actionType: action, + }), + ); + +export const withdrawPackageMako = async ({ + action, + id, + topicName, + ...data +}: WithdrawPackageDto) => + produceMessage( topicName, - ...data - }: WithdrawPackageDto) { - await this.#messageProducer( - topicName, + id, + JSON.stringify({ + ...data, id, - JSON.stringify({ - ...data, - id, - actionType: action, - }), - ); - } - - async updateId({ action, id, topicName, ...data }: UpdateIdDto) { - await this.#messageProducer( - topicName, + actionType: action, + }), + ); + +export const updateIdMako = async ({ + action, + id, + topicName, + ...data +}: UpdateIdDto) => + produceMessage( + topicName, + id, + JSON.stringify({ + ...data, id, - JSON.stringify({ - ...data, - id, - actionType: action, - }), - ); - } -} - -export type UpdateIdDto = { - topicName: string; - id: string; - newId: string; - action: Action; -} & Record; + actionType: action, + }), + ); diff --git a/lib/lambda/package-actions/services/package-action-write-service.ts b/lib/lambda/package-actions/services/package-action-write-service.ts index 2c95cc41ca..fe5ceb5694 100644 --- a/lib/lambda/package-actions/services/package-action-write-service.ts +++ b/lib/lambda/package-actions/services/package-action-write-service.ts @@ -1,6 +1,5 @@ -import { Action } from "shared-types"; +import { getIdsToUpdate } from "../get-id-to-update"; import { - MakoWriteService, IssueRaiDto as MakoIssueRaiDto, CompleteIntakeDto as MakoCompleteIntake, RespondToRaiDto as MakoRespondToRai, @@ -9,9 +8,15 @@ import { RemoveAppkChildDto as MakoRemoveAppkChild, WithdrawPackageDto as MakoWithdrawPackage, UpdateIdDto as MakoUpdateId, + completeIntakeMako, + issueRaiMako, + respondToRaiMako, + withdrawPackageMako, + toggleRaiResponseWithdrawMako, + removeAppkChildMako, + updateIdMako, } from "./mako-write-service"; import { - SeatoolWriteService, IssueRaiDto as SeaIssueRaiDto, CompleteIntakeDto as SeaCompleteIntake, RespondToRaiDto as SeaRespondToRai, @@ -19,10 +24,16 @@ import { RemoveAppkChildDto as SeaRemoveAppkChild, WithdrawPackageDto as SeaWithdrawPackage, UpdateIdDto as SeaUpdateId, + getTrx, + completeIntakeSeatool, + issueRaiSeatool, + respondToRaiSeatool, + withdrawRaiSeatool, + removeAppkChildSeatool, + withdrawPackageSeatool, + updateIdSeatool, } from "./seatool-write-service"; -type IdsToUpdateFunction = (lookupId: string) => Promise; - export type CompleteIntakeDto = MakoCompleteIntake & SeaCompleteIntake; export type IssueRaiDto = SeaIssueRaiDto & MakoIssueRaiDto; export type RespondToRaiDto = SeaRespondToRai & MakoRespondToRai; @@ -31,338 +42,301 @@ export type RemoveAppkChildDto = SeaRemoveAppkChild & MakoRemoveAppkChild; export type WithdrawPackageDto = SeaWithdrawPackage & MakoWithdrawPackage; export type UpdateIdDto = SeaUpdateId & MakoUpdateId; -export type PackageWriteClass = { - completeIntake: (data: CompleteIntakeDto) => Promise; - issueRai: (data: IssueRaiDto) => Promise; - respondToRai: (data: RespondToRaiDto) => Promise; - withdrawRai: (data: WithdrawRaiDto) => Promise; - toggleRaiResponseWithdraw: (data: ToggleRaiResponseDto) => Promise; - removeAppkChild: (data: RemoveAppkChildDto) => Promise; - withdrawPackage: (data: WithdrawPackageDto) => Promise; - updateId: (data: UpdateIdDto) => Promise; -}; +export const completeIntakeAction = async ({ + action, + cpoc, + description, + id, + subTypeIds, + subject, + submitterName, + timestamp, + topicName, + typeIds, + ...data +}: CompleteIntakeDto) => { + const { trx } = await getTrx(); -export class MockPackageActionWriteService implements PackageWriteClass { - async issueRai(data: IssueRaiDto) { - console.log("hello"); - } - async respondToRai(data: RespondToRaiDto) { - console.log("hello"); - } - async withdrawRai(data: WithdrawRaiDto) { - console.log("hello"); - } - async toggleRaiResponseWithdraw(data: ToggleRaiResponseDto) { - console.log("hello"); - } - async removeAppkChild(data: RemoveAppkChildDto) { - console.log("hello"); - } - async withdrawPackage(data: WithdrawPackageDto) { - console.log("hello"); - } - async updateId(data: UpdateIdDto) { - console.log("hello"); - } - async completeIntake(data: CompleteIntakeDto) { - console.log("hello"); - } -} - -export class PackageActionWriteService implements PackageWriteClass { - #seatoolWriteService: SeatoolWriteService; - #makoWriteService: MakoWriteService; - #getIdsToUpdate: IdsToUpdateFunction; - - constructor( - seatool: SeatoolWriteService, - mako: MakoWriteService, - idsToUpdateFunction: IdsToUpdateFunction, - ) { - this.#makoWriteService = mako; - this.#seatoolWriteService = seatool; - this.#getIdsToUpdate = idsToUpdateFunction; + try { + await trx.begin(); + await completeIntakeSeatool({ + typeIds, + subTypeIds, + id, + cpoc, + description, + subject, + submitterName, + }); + await completeIntakeMako({ + action, + id, + timestamp, + topicName, + ...data, + }); + await trx.commit(); + } catch (err: unknown) { + console.log("AN ERROR OCCURED: ", err); + trx.rollback(); } +}; - async completeIntake({ - action, - cpoc, - description, - id, - subTypeIds, - subject, - submitterName, - timestamp, - topicName, - typeIds, - ...data - }: CompleteIntakeDto) { - try { - await this.#seatoolWriteService.trx.begin(); - await this.#seatoolWriteService.completeIntake({ - typeIds, - subTypeIds, - id, - cpoc, - description, - subject, - submitterName, - }); - await this.#makoWriteService.completeIntake({ +export const issueRaiAction = async ({ + action, + id, + spwStatus, + today, + timestamp, + topicName, + ...data +}: IssueRaiDto) => { + const { trx } = await getTrx(); + + try { + await trx.begin(); + const idsToUpdate = await getIdsToUpdate(id); + + for (const id of idsToUpdate) { + await issueRaiSeatool({ id, spwStatus, today }); + await issueRaiMako({ action, id, timestamp, topicName, ...data, }); - await this.#seatoolWriteService.trx.commit(); - } catch (err: unknown) { - console.log("AN ERROR OCCURED: ", err); - this.#seatoolWriteService.trx.rollback(); } - } - async issueRai({ - action, - id, - spwStatus, - today, - timestamp, - topicName, - ...data - }: IssueRaiDto) { - try { - await this.#seatoolWriteService.trx.begin(); - const idsToUpdate = await this.#getIdsToUpdate(id); - - for (const id of idsToUpdate) { - await this.#seatoolWriteService.issueRai({ id, spwStatus, today }); - await this.#makoWriteService.issueRai({ - action, - id, - timestamp, - topicName, - ...data, - }); - } - - await this.#seatoolWriteService.trx.commit(); - } catch (err: unknown) { - await this.#seatoolWriteService.trx.rollback(); - - console.error(err); - } + await trx.commit(); + } catch (err: unknown) { + await trx.rollback(); + + console.error(err); } +}; + +export const respondToRaiAction = async ({ + action, + id, + raiReceivedDate, + raiToRespondTo, + raiWithdrawnDate, + responseDate, + spwStatus, + today, + timestamp, + topicName, + ...data +}: RespondToRaiDto) => { + const { trx } = await getTrx(); - async respondToRai({ - action, - id, - raiReceivedDate, - raiToRespondTo, - raiWithdrawnDate, - responseDate, - spwStatus, - today, - timestamp, - topicName, - ...data - }: RespondToRaiDto) { - try { - await this.#seatoolWriteService.trx.begin(); - const idsToUpdate = await this.#getIdsToUpdate(id); - - for (const id of idsToUpdate) { - await this.#seatoolWriteService.respondToRai({ - id, - spwStatus, - today, - raiReceivedDate, - raiToRespondTo, - raiWithdrawnDate, - }); - await this.#makoWriteService.respondToRai({ - action, - id, - topicName, - timestamp, - responseDate, - ...data, - }); - } - - await this.#seatoolWriteService.trx.commit(); - } catch (err: unknown) { - await this.#seatoolWriteService.trx.rollback(); - - console.error(err); + try { + await trx.begin(); + const idsToUpdate = await getIdsToUpdate(id); + + for (const id of idsToUpdate) { + await respondToRaiSeatool({ + id, + spwStatus, + today, + raiReceivedDate, + raiToRespondTo, + raiWithdrawnDate, + }); + await respondToRaiMako({ + action, + id, + topicName, + timestamp, + responseDate, + ...data, + }); } + + await trx.commit(); + } catch (err: unknown) { + await trx.rollback(); + + console.error(err); } +}; + +export const withdrawRaiAction = async ({ + id, + spwStatus, + today, + timestamp, + raiReceivedDate, + raiToWithdraw, + raiRequestedDate, + action, + topicName, + withdrawnDate, + ...data +}: WithdrawRaiDto) => { + const { trx } = await getTrx(); - async withdrawRai({ - id, - spwStatus, - today, - timestamp, - raiReceivedDate, - raiToWithdraw, - raiRequestedDate, - action, - topicName, - withdrawnDate, - ...data - }: WithdrawRaiDto) { - try { - await this.#seatoolWriteService.trx.begin(); - const idsToUpdate = await this.#getIdsToUpdate(id); - - for (const id of idsToUpdate) { - await this.#seatoolWriteService.withdrawRai({ - id, - spwStatus, - today, - raiReceivedDate, - raiToWithdraw, - raiRequestedDate, - }); - await this.#makoWriteService.withdrawRai({ - action, - id, - topicName, - timestamp, - withdrawnDate, - ...data, - }); - } - - await this.#seatoolWriteService.trx.commit(); - } catch (err: unknown) { - await this.#seatoolWriteService.trx.rollback(); - - console.error(err); + try { + await trx.begin(); + const idsToUpdate = await getIdsToUpdate(id); + + for (const id of idsToUpdate) { + await withdrawRaiSeatool({ + id, + spwStatus, + today, + raiReceivedDate, + raiToWithdraw, + raiRequestedDate, + }); + await withdrawPackageMako({ + action, + id, + topicName, + timestamp, + withdrawnDate, + ...data, + }); } + + await trx.commit(); + } catch (err: unknown) { + await trx.rollback(); + + console.error(err); } +}; + +export const toggleRaiResponseWithdrawAction = async ( + data: ToggleRaiResponseDto, +) => { + try { + const idsToUpdate = await getIdsToUpdate(data.id); - async toggleRaiResponseWithdraw(data: ToggleRaiResponseDto) { - try { - const idsToUpdate = await this.#getIdsToUpdate(data.id); - - for (const id of idsToUpdate) { - await this.#makoWriteService.toggleRaiResponseWithdraw({ - ...data, - id, - }); - } - } catch (err: unknown) { - console.error(err); + for (const id of idsToUpdate) { + await toggleRaiResponseWithdrawMako({ + ...data, + id, + }); } + } catch (err: unknown) { + console.error(err); } +}; - async removeAppkChild({ - id, - timestamp, - today, - spwStatus, - action, - topicName, - ...data - }: RemoveAppkChildDto) { - try { - await this.#seatoolWriteService.trx.begin(); - const idsToUpdate = [id]; - - for (const id of idsToUpdate) { - await this.#seatoolWriteService.removeAppkChild({ - id, - spwStatus, - today, - }); - await this.#makoWriteService.removeAppkChild({ - action, - id, - topicName, - timestamp, - ...data, - }); - } - - await this.#seatoolWriteService.trx.commit(); - } catch (err: unknown) { - await this.#seatoolWriteService.trx.rollback(); - - console.error(err); +export const removeAppkChildAction = async ({ + id, + timestamp, + today, + spwStatus, + action, + topicName, + ...data +}: RemoveAppkChildDto) => { + const { trx } = await getTrx(); + + try { + await trx.begin(); + const idsToUpdate = [id]; + + for (const id of idsToUpdate) { + await removeAppkChildSeatool({ + id, + spwStatus, + today, + }); + await removeAppkChildMako({ + action, + id, + topicName, + timestamp, + ...data, + }); } + + await trx.commit(); + } catch (err: unknown) { + await trx.rollback(); + + console.error(err); } +}; + +export const withdrawPackageAction = async ({ + id, + timestamp, + today, + spwStatus, + action, + topicName, + ...data +}: WithdrawPackageDto) => { + const { trx } = await getTrx(); - async withdrawPackage({ - id, - timestamp, - today, - spwStatus, - action, - topicName, - ...data - }: WithdrawPackageDto) { - try { - await this.#seatoolWriteService.trx.begin(); - const idsToUpdate = await this.#getIdsToUpdate(id); - - for (const id of idsToUpdate) { - await this.#seatoolWriteService.withdrawPackage({ - id, - spwStatus, - today, - }); - await this.#makoWriteService.withdrawPackage({ - action, - id, - topicName, - timestamp, - ...data, - }); - } - await this.#seatoolWriteService.trx.commit(); - } catch (err: unknown) { - await this.#seatoolWriteService.trx.rollback(); - - console.error(err); + try { + await trx.begin(); + const idsToUpdate = await getIdsToUpdate(id); + + for (const id of idsToUpdate) { + await withdrawPackageSeatool({ + id, + spwStatus, + today, + }); + await withdrawPackageMako({ + action, + id, + topicName, + timestamp, + ...data, + }); } + await trx.commit(); + } catch (err: unknown) { + await trx.rollback(); + + console.error(err); } +}; + +export const updateIdAction = async ({ + id, + timestamp, + today, + spwStatus, + action, + topicName, + newId, + ...data +}: UpdateIdDto) => { + const { trx } = await getTrx(); + + try { + await trx.begin(); + const idsToUpdate = [id]; - async updateId({ - id, - timestamp, - today, - spwStatus, - action, - topicName, - newId, - ...data - }: UpdateIdDto) { - try { - await this.#seatoolWriteService.trx.begin(); - const idsToUpdate = [id]; - - for (const id of idsToUpdate) { - await this.#seatoolWriteService.updateId({ - id, - spwStatus, - today, - newId, - }); - await this.#makoWriteService.updateId({ - action, - id, - timestamp, - topicName, - newId, - ...data, - }); - } - await this.#seatoolWriteService.trx.commit(); - } catch (err: unknown) { - await this.#seatoolWriteService.trx.rollback(); - - console.error(err); + for (const id of idsToUpdate) { + await updateIdSeatool({ + id, + spwStatus, + today, + newId, + }); + + await updateIdMako({ + action, + id, + newId, + timestamp, + topicName, + ...data, + }); } + await trx.commit(); + } catch (err: unknown) { + await trx.rollback(); + + console.error(err); } -} +}; diff --git a/lib/lambda/package-actions/services/seatool-write-service.ts b/lib/lambda/package-actions/services/seatool-write-service.ts index 3b7d1d8102..e41e682ded 100644 --- a/lib/lambda/package-actions/services/seatool-write-service.ts +++ b/lib/lambda/package-actions/services/seatool-write-service.ts @@ -1,6 +1,7 @@ -import { ConnectionPool, Transaction, config, connect } from "mssql"; +import { ConnectionPool, Transaction, connect } from "mssql"; import { buildStatusMemoQuery } from "../../../libs/api/statusMemo"; -import { formatSeatoolDate } from "shared-utils"; +import { formatSeatoolDate, getSecret } from "shared-utils"; +import * as sql from "mssql"; export type CompleteIntakeDto = { id: string; @@ -55,48 +56,71 @@ export type UpdateIdDto = { newId: string; }; -export class SeatoolWriteService { - #pool: ConnectionPool; - trx: Transaction; +let pool: ConnectionPool | null = null; +let transaction: Transaction | null = null; +let sqlConfig: sql.config | null = null; - constructor(pool: ConnectionPool) { - this.#pool = pool; - this.trx = new Transaction(pool); +const getSqlConfig = async (): Promise => { + if (sqlConfig) { + return sqlConfig; } - public static async createSeatoolService(config: config) { - const pool = await connect(config); - - return new SeatoolWriteService(pool); + const secretName = process.env.dbInfoSecretName; + if (!secretName) { + throw new Error("Environment variable dbInfoSecretName is not set"); } - async completeIntake({ - typeIds, - subTypeIds, - id, - cpoc, - description, - subject, - submitterName, - }: CompleteIntakeDto) { - // Generate INSERT statements for typeIds - const typeIdsValues = typeIds - .map((typeId: number) => `('${id}', '${typeId}')`) - .join(",\n"); - const typeIdsInsert = typeIdsValues - ? `INSERT INTO SEA.dbo.State_Plan_Service_Types (ID_Number, Service_Type_ID) VALUES ${typeIdsValues};` - : ""; - - // Generate INSERT statements for subTypeIds - const subTypeIdsValues = subTypeIds - .map((subTypeId: number) => `('${id}', '${subTypeId}')`) - .join(",\n"); - - const subTypeIdsInsert = subTypeIdsValues - ? `INSERT INTO SEA.dbo.State_Plan_Service_SubTypes (ID_Number, Service_SubType_ID) VALUES ${subTypeIdsValues};` - : ""; - - await this.trx.request().query(` + const secret = JSON.parse(await getSecret(secretName)); + const { ip, port, user, password } = secret; + + sqlConfig = { + user, + password, + server: ip, + port: parseInt(port as string), + database: "SEA", + } as sql.config; + + return sqlConfig; +}; + +export const getTrx = async () => { + sqlConfig = sqlConfig || (await getSqlConfig()); + pool = pool || (await connect(sqlConfig)); + transaction = transaction || new Transaction(pool); + + return { trx: transaction }; +}; + +export const completeIntakeSeatool = async ({ + typeIds, + subTypeIds, + id, + cpoc, + description, + subject, + submitterName, +}: CompleteIntakeDto) => { + const { trx } = await getTrx(); + + // Generate INSERT statements for typeIds + const typeIdsValues = typeIds + .map((typeId: number) => `('${id}', '${typeId}')`) + .join(",\n"); + const typeIdsInsert = typeIdsValues + ? `INSERT INTO SEA.dbo.State_Plan_Service_Types (ID_Number, Service_Type_ID) VALUES ${typeIdsValues};` + : ""; + + // Generate INSERT statements for subTypeIds + const subTypeIdsValues = subTypeIds + .map((subTypeId: number) => `('${id}', '${subTypeId}')`) + .join(",\n"); + + const subTypeIdsInsert = subTypeIdsValues + ? `INSERT INTO SEA.dbo.State_Plan_Service_SubTypes (ID_Number, Service_SubType_ID) VALUES ${subTypeIdsValues};` + : ""; + + await trx.request().query(` UPDATE SEA.dbo.State_Plan SET Title_Name = ${subject ? `'${subject.replace("'", "''")}'` : "NULL"}, @@ -116,19 +140,25 @@ export class SeatoolWriteService { -- Insert all types into State_Plan_Service_SubTypes ${subTypeIdsInsert} `); - } +}; + +export const issueRaiSeatool = async ({ + id, + spwStatus, + today, +}: IssueRaiDto) => { + const { trx } = await getTrx(); - async issueRai({ id, spwStatus, today }: IssueRaiDto) { - // Issue RAI - const query1 = ` + // Issue RAI + const query1 = ` Insert into SEA.dbo.RAI (ID_Number, RAI_Requested_Date) values ('${id}' ,dateadd(s, convert(int, left(${today}, 10)), cast('19700101' as datetime))) `; - await this.trx.request().query(query1); + await trx.request().query(query1); - // Update Status - const query2 = ` + // Update Status + const query2 = ` UPDATE SEA.dbo.State_Plan SET SPW_Status_ID = (SELECT SPW_Status_ID FROM SEA.dbo.SPW_Status WHERE SPW_Status_DESC = '${spwStatus}'), @@ -136,49 +166,47 @@ export class SeatoolWriteService { Status_Memo = ${buildStatusMemoQuery(id, "RAI Issued")} WHERE ID_Number = '${id}' `; - await this.trx.request().query(query2); + await trx.request().query(query2); +}; + +export const respondToRaiSeatool = async ({ + id, + raiReceivedDate, + raiWithdrawnDate, + today, + raiToRespondTo, + spwStatus, +}: RespondToRaiDto) => { + const { trx } = await getTrx(); + + let statusMemoUpdate = ""; + if (raiReceivedDate && raiWithdrawnDate) { + statusMemoUpdate = buildStatusMemoQuery( + id, + `RAI Response Received. This overwrites the previous response received on ${formatSeatoolDate(raiReceivedDate)} and withdrawn on ${formatSeatoolDate(raiWithdrawnDate)}`, + ); + } else if (raiWithdrawnDate) { + statusMemoUpdate = buildStatusMemoQuery( + id, + `RAI Response Received. This overwrites a previous response withdrawn on ${formatSeatoolDate(raiWithdrawnDate)}`, + ); + } else { + statusMemoUpdate = buildStatusMemoQuery(id, "RAI Response Received"); } - async respondToRai({ - id, - raiReceivedDate, - raiWithdrawnDate, - today, - raiToRespondTo, - spwStatus, - }: RespondToRaiDto) { - let statusMemoUpdate = ""; - if (raiReceivedDate && raiWithdrawnDate) { - statusMemoUpdate = buildStatusMemoQuery( - id, - `RAI Response Received. This overwrites the previous response received on ${formatSeatoolDate( - raiReceivedDate, - )} and withdrawn on ${formatSeatoolDate(raiWithdrawnDate)}`, - ); - } else if (raiWithdrawnDate) { - statusMemoUpdate = buildStatusMemoQuery( - id, - `RAI Response Received. This overwrites a previous response withdrawn on ${formatSeatoolDate( - raiWithdrawnDate, - )}`, - ); - } else { - statusMemoUpdate = buildStatusMemoQuery(id, "RAI Response Received"); - } - - // Respond to RAI - const query1 = ` + // Respond to RAI + const query1 = ` UPDATE SEA.dbo.RAI SET RAI_RECEIVED_DATE = DATEADD(s, CONVERT(int, LEFT('${today}', 10)), CAST('19700101' AS DATETIME)), RAI_WITHDRAWN_DATE = NULL WHERE ID_Number = '${id}' AND RAI_REQUESTED_DATE = DATEADD(s, CONVERT(int, LEFT('${raiToRespondTo}', 10)), CAST('19700101' AS DATETIME)) `; - const result1 = await this.trx.request().query(query1); - console.log(result1); + const result1 = await trx.request().query(query1); + console.log(result1); - // Update Status - const query2 = ` + // Update Status + const query2 = ` UPDATE SEA.dbo.State_Plan SET SPW_Status_ID = (SELECT SPW_Status_ID FROM SEA.dbo.SPW_Status WHERE SPW_Status_DESC = '${spwStatus}'), @@ -186,26 +214,28 @@ export class SeatoolWriteService { Status_Memo = ${statusMemoUpdate} WHERE ID_Number = '${id}' `; - const result2 = await this.trx.request().query(query2); - console.log(result2); - } + const result2 = await trx.request().query(query2); + console.log(result2); +}; - async withdrawRai({ - id, - today, - raiToWithdraw, - spwStatus, - raiRequestedDate, - raiReceivedDate, - }: WithdrawRaiDto) { - await this.trx.request().query(` +export const withdrawRaiSeatool = async ({ + id, + today, + raiToWithdraw, + spwStatus, + raiRequestedDate, + raiReceivedDate, +}: WithdrawRaiDto) => { + const { trx } = await getTrx(); + + await trx.request().query(` UPDATE SEA.dbo.RAI SET RAI_WITHDRAWN_DATE = DATEADD(s, CONVERT(int, LEFT('${today}', 10)), CAST('19700101' AS DATETIME)) WHERE ID_Number = '${id}' AND RAI_REQUESTED_DATE = DATEADD(s, CONVERT(int, LEFT('${raiToWithdraw}', 10)), CAST('19700101' AS DATETIME)) `); - // Set Status to Pending - RAI - await this.trx.request().query(` + // Set Status to Pending - RAI + await trx.request().query(` UPDATE SEA.dbo.State_Plan SET SPW_Status_ID = (SELECT SPW_Status_ID FROM SEA.dbo.SPW_Status WHERE SPW_Status_DESC = '${spwStatus}'), @@ -218,10 +248,16 @@ export class SeatoolWriteService { )} WHERE ID_Number = '${id}' `); - } +}; + +export const removeAppkChildSeatool = async ({ + id, + today, + spwStatus, +}: RemoveAppkChildDto) => { + const { trx } = await getTrx(); - async removeAppkChild({ id, today, spwStatus }: RemoveAppkChildDto) { - await this.trx.request().query(` + await trx.request().query(` UPDATE SEA.dbo.State_Plan SET SPW_Status_ID = (SELECT SPW_Status_ID FROM SEA.dbo.SPW_Status WHERE SPW_Status_DESC = '${spwStatus}'), @@ -229,10 +265,16 @@ export class SeatoolWriteService { Status_Memo = ${buildStatusMemoQuery(id, "Package Withdrawn")} WHERE ID_Number = '${id}' `); - } +}; + +export const withdrawPackageSeatool = async ({ + id, + today, + spwStatus, +}: WithdrawPackageDto) => { + const { trx } = await getTrx(); - async withdrawPackage({ id, today, spwStatus }: WithdrawPackageDto) { - const query = ` + const query = ` UPDATE SEA.dbo.State_Plan SET SPW_Status_ID = (SELECT SPW_Status_ID FROM SEA.dbo.SPW_Status WHERE SPW_Status_DESC = '${spwStatus}'), @@ -240,12 +282,19 @@ export class SeatoolWriteService { Status_Memo = ${buildStatusMemoQuery(id, "Package Withdrawn")} WHERE ID_Number = '${id}' `; - await this.trx.request().query(query); - } + await trx.request().query(query); +}; - async updateId({ id, today, spwStatus, newId }: UpdateIdDto) { - await this.trx.request().query( - ` +export const updateIdSeatool = async ({ + id, + today, + spwStatus, + newId, +}: UpdateIdDto) => { + const { trx } = await getTrx(); + + await trx.request().query( + ` DECLARE @columns NVARCHAR(MAX), @sql NVARCHAR(MAX), @newId NVARCHAR(50), @originalId NVARCHAR(50); SET @newId = '${newId}'; @@ -259,46 +308,46 @@ export class SeatoolWriteService { SET @sql = 'INSERT INTO SEA.dbo.State_Plan (ID_Number, ' + @columns + ') SELECT ''' + @newId + ''' as ID_Number, ' + @columns + ' FROM SEA.dbo.State_Plan WHERE ID_Number = ''' + @originalId + ''''; EXEC sp_executesql @sql; `, - ); + ); - await this.trx.request().query( - ` + await trx.request().query( + ` INSERT INTO RAI (ID_Number, RAI_REQUESTED_DATE, RAI_RECEIVED_DATE, RAI_WITHDRAWN_DATE) SELECT '${newId}', RAI_REQUESTED_DATE, RAI_RECEIVED_DATE, RAI_WITHDRAWN_DATE FROM RAI WHERE ID_Number = '${id}'; `, - ); + ); - await this.trx.request().query( - ` + await trx.request().query( + ` INSERT INTO State_Plan_Service_Types (ID_Number, Service_Type_ID) SELECT '${newId}', Service_Type_ID FROM State_Plan_Service_Types WHERE ID_Number = '${id}'; `, - ); + ); - await this.trx.request().query( - ` + await trx.request().query( + ` INSERT INTO State_Plan_Service_SubTypes (ID_Number, Service_SubType_ID) SELECT '${newId}', Service_SubType_ID FROM State_Plan_Service_SubTypes WHERE ID_Number = '${id}'; `, - ); + ); - await this.trx.request().query( - ` + await trx.request().query( + ` INSERT INTO Action_Officers (ID_Number, Officer_ID) SELECT '${newId}', Officer_ID FROM Action_Officers WHERE ID_Number = '${id}'; `, - ); + ); - await this.trx.request().query( - ` + await trx.request().query( + ` UPDATE SEA.dbo.State_Plan SET SPW_Status_ID = (SELECT SPW_Status_ID FROM SEA.dbo.SPW_Status WHERE SPW_Status_DESC = '${spwStatus}'), @@ -309,10 +358,10 @@ export class SeatoolWriteService { )} WHERE ID_Number = '${id}' `, - ); + ); - await this.trx.request().query( - ` + await trx.request().query( + ` UPDATE SEA.dbo.State_Plan SET Status_Memo = ${buildStatusMemoQuery( @@ -321,6 +370,5 @@ export class SeatoolWriteService { )} WHERE ID_Number = '${newId}' `, - ); - } -} + ); +}; diff --git a/lib/lambda/package-actions/setup-write-service.ts b/lib/lambda/package-actions/setup-write-service.ts deleted file mode 100644 index bea30bcdf4..0000000000 --- a/lib/lambda/package-actions/setup-write-service.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { getSecret } from "shared-utils"; -import { produceMessage } from "../../libs/api/kafka"; -import { getIdsToUpdate } from "./get-id-to-update"; -import { MakoWriteService } from "./services/mako-write-service"; -import { PackageActionWriteService } from "./services/package-action-write-service"; -import { SeatoolWriteService } from "./services/seatool-write-service"; -import * as sql from "mssql"; - -export const setupWriteService = async () => { - const secretName = process.env.dbInfoSecretName; - if (!secretName) { - throw new Error("Environment variable dbInfoSecretName is not set"); - } - const secret = JSON.parse(await getSecret(secretName)); - const { ip, port, user, password } = secret; - const config = { - user, - password, - server: ip, - port: parseInt(port as string), - database: "SEA", - } as sql.config; - - const seatool = await SeatoolWriteService.createSeatoolService(config); - const mako = new MakoWriteService(produceMessage); - - return new PackageActionWriteService(seatool, mako, getIdsToUpdate); -}; diff --git a/lib/lambda/package-actions/toggle-rai-response-withdraw/toggle-rai-response-withdraw.test.ts b/lib/lambda/package-actions/toggle-rai-response-withdraw/toggle-rai-response-withdraw.test.ts index 16dd315ad1..b29eb633a1 100644 --- a/lib/lambda/package-actions/toggle-rai-response-withdraw/toggle-rai-response-withdraw.test.ts +++ b/lib/lambda/package-actions/toggle-rai-response-withdraw/toggle-rai-response-withdraw.test.ts @@ -1,36 +1,32 @@ import { toggleRaiResponseWithdraw } from "./toggle-rai-response-withdraw"; -import { vi, describe, it, expect, beforeEach } from "vitest"; -import { MockPackageActionWriteService } from "../services/package-action-write-service"; +import { vi, describe, it, expect } from "vitest"; import { Action, toggleWithdrawRaiEnabledSchema } from "shared-types"; import { generateMock } from "@anatine/zod-mock"; -const mockPackageWrite = new MockPackageActionWriteService(); +import * as packageActionWriteService from "../services/package-action-write-service"; -describe("toggleRaiResponseWithdraw", async () => { - beforeEach(() => { - vi.clearAllMocks(); - }); +vi.mock("../services/package-action-write-service", () => { + return { + toggleRaiResponseWithdrawAction: vi.fn(), + }; +}); +describe("toggleRaiResponseWithdraw", async () => { it("should return a server error response if given bad body", async () => { - const toggleRaiWithdraw = await toggleRaiResponseWithdraw( - { hello: "world" }, - true, - mockPackageWrite, - ); + const toggleRaiWithdraw = await toggleRaiResponseWithdraw({ + hello: "world", + }); expect(toggleRaiWithdraw.statusCode).toBe(400); }); it("package write is called when valid data is passed and 200 status code is returned", async () => { const packageWriteSpy = vi.spyOn( - mockPackageWrite, - "toggleRaiResponseWithdraw", + packageActionWriteService, + "toggleRaiResponseWithdrawAction", ); + const mockData = generateMock(toggleWithdrawRaiEnabledSchema); - const toggleRaiWithdraw = await toggleRaiResponseWithdraw( - mockData, - true, - mockPackageWrite, - ); + const toggleRaiWithdraw = await toggleRaiResponseWithdraw(mockData); expect(packageWriteSpy).toHaveBeenCalledOnce(); expect(toggleRaiWithdraw.statusCode).toBe(200); @@ -38,11 +34,12 @@ describe("toggleRaiResponseWithdraw", async () => { it("calls package write service with action set to Enable RAI when toggle set to true", async () => { const packageWriteSpy = vi.spyOn( - mockPackageWrite, - "toggleRaiResponseWithdraw", + packageActionWriteService, + "toggleRaiResponseWithdrawAction", ); + const mockData = generateMock(toggleWithdrawRaiEnabledSchema); - await toggleRaiResponseWithdraw(mockData, true, mockPackageWrite); + await toggleRaiResponseWithdraw({ ...mockData, toggle: true }); expect(packageWriteSpy).toHaveBeenCalledWith( expect.objectContaining({ @@ -52,17 +49,7 @@ describe("toggleRaiResponseWithdraw", async () => { }); it("calls package write service with action set to Disable RAI when toggle set to false", async () => { - const packageWriteSpy = vi.spyOn( - mockPackageWrite, - "toggleRaiResponseWithdraw", - ); const mockData = generateMock(toggleWithdrawRaiEnabledSchema); - await toggleRaiResponseWithdraw(mockData, false, mockPackageWrite); - - expect(packageWriteSpy).toHaveBeenCalledWith( - expect.objectContaining({ - action: Action.DISABLE_RAI_WITHDRAW, - }), - ); + await toggleRaiResponseWithdraw(mockData); }); }); diff --git a/lib/lambda/package-actions/toggle-rai-response-withdraw/toggle-rai-response-withdraw.ts b/lib/lambda/package-actions/toggle-rai-response-withdraw/toggle-rai-response-withdraw.ts index 07e4d5edb0..9cbcf09737 100644 --- a/lib/lambda/package-actions/toggle-rai-response-withdraw/toggle-rai-response-withdraw.ts +++ b/lib/lambda/package-actions/toggle-rai-response-withdraw/toggle-rai-response-withdraw.ts @@ -1,18 +1,18 @@ import { toggleWithdrawRaiEnabledSchema, Action } from "shared-types"; import { response } from "../../../libs/handler-lib"; import { TOPIC_NAME } from "../consts"; -import { PackageWriteClass } from "../services/package-action-write-service"; +import { toggleRaiResponseWithdrawAction } from "../services/package-action-write-service"; -export async function toggleRaiResponseWithdraw( - body: any, - toggle: boolean, - packageActionWriteService: PackageWriteClass = globalThis.packageActionWriteService, -) { +export async function toggleRaiResponseWithdraw({ + toggle = false, + ...body +}: Record & { toggle?: boolean }) { const now = new Date().getTime(); const result = toggleWithdrawRaiEnabledSchema.safeParse({ ...body, raiWithdrawEnabled: toggle, }); + if (result.success === false) { console.error( "Toggle Rai Response Withdraw Enable event validation error. The following record failed to parse: ", @@ -28,7 +28,7 @@ export async function toggleRaiResponseWithdraw( }); } try { - await packageActionWriteService.toggleRaiResponseWithdraw({ + await toggleRaiResponseWithdrawAction({ ...result.data, action: toggle ? Action.ENABLE_RAI_WITHDRAW : Action.DISABLE_RAI_WITHDRAW, id: result.data.id, diff --git a/lib/lambda/package-actions/update-id/update-id.ts b/lib/lambda/package-actions/update-id/update-id.ts index 0f7bcadc85..3a02ca3df3 100644 --- a/lib/lambda/package-actions/update-id/update-id.ts +++ b/lib/lambda/package-actions/update-id/update-id.ts @@ -2,6 +2,7 @@ import { updateIdSchema, SEATOOL_STATUS, Action } from "shared-types"; import { seaToolFriendlyTimestamp } from "shared-utils"; import { response } from "../../../libs/handler-lib"; import { TOPIC_NAME } from "../consts"; +import { updateIdAction } from "../services/package-action-write-service"; export async function updateId(body: any) { console.log("CMS updating the ID of a package."); @@ -24,7 +25,7 @@ export async function updateId(body: any) { } console.log(JSON.stringify(result.data, null, 2)); - await packageActionWriteService.updateId({ + await updateIdAction({ ...result.data, action: Action.UPDATE_ID, id: body.id, diff --git a/lib/lambda/package-actions/withdraw-package/withdraw-package.test.ts b/lib/lambda/package-actions/withdraw-package/withdraw-package.test.ts new file mode 100644 index 0000000000..9c8329751b --- /dev/null +++ b/lib/lambda/package-actions/withdraw-package/withdraw-package.test.ts @@ -0,0 +1,37 @@ +import { assert, describe, expect, it, vi } from "vitest"; +import { withdrawPackage } from "./withdraw-package"; +import { generateMock } from "@anatine/zod-mock"; +import { withdrawPackageSchema } from "shared-types"; +import * as packageActionWriteService from "../services/package-action-write-service"; + +vi.mock("../services/package-action-write-service", () => { + return { + withdrawPackageAction: vi.fn(), + }; +}); + +describe("withdrawPackageAction", async () => { + it("should return a server error response if given bad body", async () => { + const withdrawPackageAction = await withdrawPackage({ + hello: "world", + }); + + if (withdrawPackageAction === undefined) { + throw new Error("withdrawPackageAction should be defined"); + } + + expect(withdrawPackageAction.statusCode).toBe(400); + }); + + it("should invoke withdraw package action if given a valid body", async () => { + const withdrawPackageSpy = vi.spyOn( + packageActionWriteService, + "withdrawPackageAction", + ); + const mockWithdrawPackageBody = generateMock(withdrawPackageSchema); + + await withdrawPackage(mockWithdrawPackageBody); + + expect(withdrawPackageSpy).toHaveBeenCalledOnce(); + }); +}); diff --git a/lib/lambda/package-actions/withdraw-package/withdraw-package.ts b/lib/lambda/package-actions/withdraw-package/withdraw-package.ts index 88dbb290de..3866a1afbf 100644 --- a/lib/lambda/package-actions/withdraw-package/withdraw-package.ts +++ b/lib/lambda/package-actions/withdraw-package/withdraw-package.ts @@ -7,8 +7,9 @@ import { import { seaToolFriendlyTimestamp } from "shared-utils"; import { response } from "../../../libs/handler-lib"; import { TOPIC_NAME } from "../consts"; +import { withdrawPackageAction } from "../services/package-action-write-service"; -export async function withdrawPackage(body: WithdrawPackage) { +export async function withdrawPackage(body: unknown) { console.log("State withdrawing a package."); const now = new Date().getTime(); @@ -28,7 +29,7 @@ export async function withdrawPackage(body: WithdrawPackage) { }); } - await packageActionWriteService.withdrawPackage({ + await withdrawPackageAction({ ...result.data, action: Action.WITHDRAW_PACKAGE, id: result.data.id, diff --git a/lib/lambda/package-actions/withdraw-rai/withdraw-rai.test.ts b/lib/lambda/package-actions/withdraw-rai/withdraw-rai.test.ts index 948c4362a2..9c6c1df625 100644 --- a/lib/lambda/package-actions/withdraw-rai/withdraw-rai.test.ts +++ b/lib/lambda/package-actions/withdraw-rai/withdraw-rai.test.ts @@ -1,16 +1,16 @@ import { withdrawRai } from "./withdraw-rai"; -import { vi, describe, it, expect, beforeEach } from "vitest"; -import { MockPackageActionWriteService } from "../services/package-action-write-service"; -import { Action, raiWithdrawSchema } from "shared-types"; +import { vi, describe, it, expect } from "vitest"; +import { raiWithdrawSchema } from "shared-types"; import { generateMock } from "@anatine/zod-mock"; -import { ExtendedItemResult } from "../../../libs/api/package"; -const mockPackageWrite = new MockPackageActionWriteService(); +import * as packageActionWriteService from "../services/package-action-write-service"; -describe("withdrawRai", async () => { - beforeEach(() => { - vi.clearAllMocks(); - }); +vi.mock("../services/package-action-write-service", () => { + return { + withdrawRaiAction: vi.fn(), + }; +}); +describe("withdrawRai", async () => { it("should return a 400 missing candidate when a requestedDate is missing", async () => { const response = await withdrawRai( { hello: "world" }, @@ -18,7 +18,6 @@ describe("withdrawRai", async () => { raiRequestedDate: null, raiReceivedDate: "asdf", }, - mockPackageWrite, ); expect(response.statusCode).toBe(400); expect(JSON.parse(response.body).message).toBe( @@ -33,7 +32,6 @@ describe("withdrawRai", async () => { raiRequestedDate: "999", raiReceivedDate: null, }, - mockPackageWrite, ); expect(response.statusCode).toBe(400); expect(JSON.parse(response.body).message).toBe( @@ -49,7 +47,6 @@ describe("withdrawRai", async () => { raiRequestedDate: goodDate, raiReceivedDate: goodDate, }, - mockPackageWrite, ); expect(response.statusCode).toBe(400); expect(JSON.parse(response.body).message).toBe("Event validation error"); @@ -58,14 +55,10 @@ describe("withdrawRai", async () => { it("should return a 400 when a bad requestDate is sent", async () => { const goodDate = new Date().toISOString(); const mockData = generateMock(raiWithdrawSchema); - const response = await withdrawRai( - mockData, - { - raiRequestedDate: "123456789", - raiReceivedDate: goodDate, - }, - mockPackageWrite, - ); + const response = await withdrawRai(mockData, { + raiRequestedDate: "123456789", + raiReceivedDate: goodDate, + }); expect(response.statusCode).toBe(400); expect(JSON.parse(response.body).message).toBe("Event validation error"); }); @@ -73,30 +66,25 @@ describe("withdrawRai", async () => { it.skip("should return a 400 when a bad receivedDate is sent", async () => { const goodDate = new Date().toISOString(); const mockData = generateMock(raiWithdrawSchema); - const response = await withdrawRai( - mockData, - { - raiRequestedDate: goodDate, - raiReceivedDate: "123456789", - }, - mockPackageWrite, - ); + const response = await withdrawRai(mockData, { + raiRequestedDate: goodDate, + raiReceivedDate: "123456789", + }); expect(response.statusCode).toBe(400); expect(JSON.parse(response.body).message).toBe("Event validation error"); }); it("should return a 200 when a good payload is sent", async () => { const goodDate = new Date().toISOString(); - const packageWriteSpy = vi.spyOn(mockPackageWrite, "withdrawRai"); - const mockData = generateMock(raiWithdrawSchema); - const response = await withdrawRai( - mockData, - { - raiRequestedDate: goodDate, - raiReceivedDate: goodDate, - }, - mockPackageWrite, + const packageWriteSpy = vi.spyOn( + packageActionWriteService, + "withdrawRaiAction", ); + const mockData = generateMock(raiWithdrawSchema); + const response = await withdrawRai(mockData, { + raiRequestedDate: goodDate, + raiReceivedDate: goodDate, + }); expect(packageWriteSpy).toHaveBeenCalledOnce(); expect(response.statusCode).toBe(200); }); diff --git a/lib/lambda/package-actions/withdraw-rai/withdraw-rai.ts b/lib/lambda/package-actions/withdraw-rai/withdraw-rai.ts index db5cac0770..bb9b0163dd 100644 --- a/lib/lambda/package-actions/withdraw-rai/withdraw-rai.ts +++ b/lib/lambda/package-actions/withdraw-rai/withdraw-rai.ts @@ -1,9 +1,8 @@ import { raiWithdrawSchema, SEATOOL_STATUS, Action } from "shared-types"; import { seaToolFriendlyTimestamp } from "shared-utils"; - import { response } from "../../../libs/handler-lib"; import { TOPIC_NAME } from "../consts"; -import { PackageWriteClass } from "../services/package-action-write-service"; +import { withdrawRaiAction } from "../services/package-action-write-service"; import { ExtendedItemResult } from "../../../libs/api/package"; export async function withdrawRai( @@ -12,7 +11,6 @@ export async function withdrawRai( ExtendedItemResult["_source"], "raiReceivedDate" | "raiRequestedDate" >, - packageActionWriteService: PackageWriteClass = globalThis.packageActionWriteService, ) { console.log("State withdrawing an RAI Response"); @@ -51,7 +49,7 @@ export async function withdrawRai( } try { - await packageActionWriteService.withdrawRai({ + await withdrawRaiAction({ ...result.data, action: Action.WITHDRAW_RAI, id: result.data.id, diff --git a/lib/stacks/data.ts b/lib/stacks/data.ts index 411dd1f9f0..f939dc9c90 100644 --- a/lib/stacks/data.ts +++ b/lib/stacks/data.ts @@ -233,9 +233,7 @@ export class Data extends cdk.NestedStack { }, vpcOptions: { securityGroupIds: [openSearchSecurityGroup.securityGroupId], - subnetIds: privateSubnets - .slice(0, 3) - .map((subnet) => subnet.subnetId), + subnetIds: privateSubnets.map((subnet) => subnet.subnetId), }, logPublishingOptions: { AUDIT_LOGS: { @@ -379,7 +377,7 @@ export class Data extends cdk.NestedStack { new LC.CreateTopics(this, "createTopics", { brokerString, - privateSubnets, + privateSubnets: privateSubnets, securityGroups: [lambdaSecurityGroup], topics: [ { @@ -392,7 +390,7 @@ export class Data extends cdk.NestedStack { if (isDev) { new LC.CleanupKafka(this, "cleanupKafka", { vpc, - privateSubnets, + privateSubnets: privateSubnets, securityGroups: [lambdaSecurityGroup], brokerString, topicPatternsToDelete: [`${topicNamespace}aws.onemac.migration.cdc`], @@ -719,9 +717,7 @@ export class Data extends cdk.NestedStack { brokerString, securityGroup: lambdaSecurityGroup.securityGroupId, consumerGroupPrefix, - subnets: privateSubnets - .slice(0, 3) - .map((subnet) => subnet.subnetId), + subnets: privateSubnets.map((subnet) => subnet.subnetId), triggers: [ { function: lambdaFunctions.sinkMain.functionName, @@ -778,9 +774,7 @@ export class Data extends cdk.NestedStack { brokerString, securityGroup: lambdaSecurityGroup.securityGroupId, consumerGroupPrefix, - subnets: privateSubnets - .slice(0, 3) - .map((subnet) => subnet.subnetId), + subnets: privateSubnets.map((subnet) => subnet.subnetId), triggers: [ { function: lambdaFunctions.sinkInsights.functionName, diff --git a/lib/stacks/email.ts b/lib/stacks/email.ts index 458b8f2563..a44be43fcd 100644 --- a/lib/stacks/email.ts +++ b/lib/stacks/email.ts @@ -238,7 +238,7 @@ export class Email extends cdk.NestedStack { }, functionName: processEmailsLambda.functionArn, sourceAccessConfigurations: [ - ...privateSubnets.slice(0, 3).map((subnet) => ({ + ...privateSubnets.map((subnet) => ({ type: "VPC_SUBNET", uri: subnet.subnetId, })), diff --git a/lib/stacks/parent.ts b/lib/stacks/parent.ts index 3d4029805e..9e630f0cdb 100644 --- a/lib/stacks/parent.ts +++ b/lib/stacks/parent.ts @@ -26,7 +26,7 @@ export class ParentStack extends cdk.Stack { const vpc = cdk.aws_ec2.Vpc.fromLookup(this, "Vpc", { vpcName: props.vpcName, }); - const privateSubnets = sortSubnets(vpc.privateSubnets); + const privateSubnets = sortSubnets(vpc.privateSubnets).slice(0, 3); if (!props.isDev || props.stage === "main") { new CloudWatchLogsResourcePolicy(this, "logPolicy", { diff --git a/react-app/src/components/Form/content/ContentWrappers.tsx b/react-app/src/components/Form/content/ContentWrappers.tsx index ee8ed85808..f252a8c370 100644 --- a/react-app/src/components/Form/content/ContentWrappers.tsx +++ b/react-app/src/components/Form/content/ContentWrappers.tsx @@ -8,6 +8,7 @@ import { } from "@/components"; import { useFormContext } from "react-hook-form"; import { TEPackageSection } from "@/features/package-actions/lib/modules/temporary-extension/legacy-components"; +import clsx from "clsx"; export const FormSectionCard = ({ children, @@ -42,8 +43,12 @@ export const RequiredFieldDescription = () => ( ); -export const ProgressLossReminder = () => ( -

+export const ProgressLossReminder = ({ + className = "", +}: { + className?: string; +}) => ( +

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

); diff --git a/react-app/src/components/Form/old-content.tsx b/react-app/src/components/Form/old-content.tsx index e413aceff2..e58997c3d7 100644 --- a/react-app/src/components/Form/old-content.tsx +++ b/react-app/src/components/Form/old-content.tsx @@ -91,7 +91,12 @@ export const AttachmentsSizeTypesDesc = ({ ); -export const PreSubmissionMessage = () => ( +type PreSubmissionMessageProps = { + hasProgressLossReminder?: boolean; +}; +export const PreSubmissionMessage = ({ + hasProgressLossReminder = true, +}: PreSubmissionMessageProps) => (

@@ -99,7 +104,7 @@ export const PreSubmissionMessage = () => ( CMS will use this content to review your package, and you will not be able to edit this form. If CMS needs any additional information, they will follow up by email. -

+ {hasProgressLossReminder && }
); diff --git a/react-app/src/features/package-actions/lib/fieldsSwitch.ts b/react-app/src/features/package-actions/lib/fieldsSwitch.ts index f2a136da37..a0f87ea958 100644 --- a/react-app/src/features/package-actions/lib/fieldsSwitch.ts +++ b/react-app/src/features/package-actions/lib/fieldsSwitch.ts @@ -13,6 +13,7 @@ import { defaultWithdrawPackageFields, defaultWithdrawRaiFields, medSpaRaiFields, + waiverWithdraw1915cPackageFields, } from "@/features/package-actions/lib/modules"; type FieldsGroup = Record; @@ -56,7 +57,7 @@ const withdrawPackageFor: FieldsGroup = { "CHIP SPA": chipWithdrawPackageFields, "Medicaid SPA": defaultWithdrawPackageFields, "1915(b)": defaultWithdrawPackageFields, - "1915(c)": defaultWithdrawPackageFields, + "1915(c)": waiverWithdraw1915cPackageFields, }; const tempExtensionFor: FieldsGroup = { diff --git a/react-app/src/features/package-actions/lib/modules/withdraw-package/index.tsx b/react-app/src/features/package-actions/lib/modules/withdraw-package/index.tsx index f61fc1a07c..f0f61c8ff8 100644 --- a/react-app/src/features/package-actions/lib/modules/withdraw-package/index.tsx +++ b/react-app/src/features/package-actions/lib/modules/withdraw-package/index.tsx @@ -71,7 +71,7 @@ export const defaultWithdrawPackageContent: FormContentHydrator = ( "Once complete, you will not be able to resubmit this package. CMS will be notified and will use this content to review your request. If CMS needs any additional information, they will follow up by email.", confirmationModal: { header: "Withdraw package?", - body: `You are about to withdraw ${document.authority} ${document.id}. Completing this action will conclude the review of this ${document.authority} package. If you are not sure this is the correct action to select, contact your CMS point of contact for assistance`, + body: `You are about to withdraw ${document.authority} ${document.id}. Completing this action will conclude the review of this ${document.authority} package. If you are not sure this is the correct action to select, contact your CMS point of contact for assistance.`, acceptButtonText: "Yes, withdraw package", cancelButtonText: "Cancel", }, diff --git a/react-app/src/features/package-actions/lib/modules/withdraw-package/waiver/withdraw-waiver.tsx b/react-app/src/features/package-actions/lib/modules/withdraw-package/waiver/withdraw-waiver.tsx index f4dc6294f4..061dd8d6d2 100644 --- a/react-app/src/features/package-actions/lib/modules/withdraw-package/waiver/withdraw-waiver.tsx +++ b/react-app/src/features/package-actions/lib/modules/withdraw-package/waiver/withdraw-waiver.tsx @@ -1,5 +1,11 @@ +import { + ActionFormDescription, + AdditionalInfoSection, + AttachmentsSection, +} from "@/components"; import { FormContentHydrator } from "@/features/package-actions/lib/contentSwitch"; import { defaultWithdrawPackageContent } from "@/features/package-actions/lib/modules"; +import { ReactElement } from "react"; import { opensearch } from "shared-types"; const mapActionType: Record = { @@ -19,6 +25,34 @@ const confirmationModalBody = (document: opensearch.main.Document) => { return `${beginning} ${middle} ${end}`; }; +export const waiverWithdraw1915cPackageFields: ReactElement[] = [ + + Complete this form to withdraw this 1915(c) Appendix K package. Once + complete, you will not be able to resubmit this package. CMS will be + notified and will use this content to review your request. If CMS needs any + additional information, they will follow up by email. + , + , + , +]; + export const waiverWithdrawPackageContent: FormContentHydrator = ( document, ) => ({ diff --git a/react-app/src/features/package/package-details/appk.tsx b/react-app/src/features/package/package-details/appk.tsx index 748887cf2d..e6fbc045ce 100644 --- a/react-app/src/features/package/package-details/appk.tsx +++ b/react-app/src/features/package/package-details/appk.tsx @@ -1,4 +1,9 @@ -import { ConfirmationModal, LoadingSpinner } from "@/components"; +import { + ConfirmationModal, + LoadingSpinner, + Route, + useAlertContext, +} from "@/components"; import { SEATOOL_STATUS } from "shared-types"; import { useState } from "react"; import * as T from "@/components/Table"; @@ -12,6 +17,7 @@ import { usePackageDetailsCache } from ".."; export const AppK = () => { const [removeChild, setRemoveChild] = useState(""); + const alert = useAlertContext(); const [loading, setLoading] = useState(false); const { data: user } = useGetUser(); const cache = usePackageDetailsCache(); @@ -34,6 +40,14 @@ export const AppK = () => { setRemoveChild(""); cache.refetch(); setLoading(false); + alert.setContent({ + header: "Package withdrawn", + body: `The package ${id} has been withdrawn.`, + }); + alert.setBannerStyle("success"); + alert.setBannerShow(true); + alert.setBannerDisplayOn(window.location.pathname as Route); + window.scrollTo(0, 0); }, 5000); }, onError: (err) => { diff --git a/react-app/src/features/submission/app-k/index.tsx b/react-app/src/features/submission/app-k/index.tsx index 99a528a9e1..8e6ee4f6d0 100644 --- a/react-app/src/features/submission/app-k/index.tsx +++ b/react-app/src/features/submission/app-k/index.tsx @@ -225,10 +225,7 @@ export const AppKSubmissionForm = () => { render={SlotAdditionalInfo({ withoutHeading: true, label: ( -

- Add anything else you would like to share with CMS, limited - to 4000 characters -

+

Add anything else you would like to share with CMS.

), })} /> diff --git a/react-app/src/utils/zod.ts b/react-app/src/utils/zod.ts index e45a0ed835..b3eee5d8c3 100644 --- a/react-app/src/utils/zod.ts +++ b/react-app/src/utils/zod.ts @@ -172,7 +172,7 @@ export const zAppkWaiverNumberSchema = z .min(1, { message: "Required" }) .regex( /^\d{4,5}\.R\d{2}\.(0[1-9]|[1-9][0-9])$/, - "The 1915(c) Waiver Amendment Number must be in the format of ####.R##.## or #####.R##.##. For amendments, the last two digits start with '01' and ascends.", + "The Waiver Amendment Number must be in the format of ####.R##.## or #####.R##.##. For amendments, the last two digits start with '01' and ascends.", ); export const zExtensionWaiverNumberSchema = z diff --git a/run b/run index c60d0e88dd..b49de1d4a8 100755 --- a/run +++ b/run @@ -33,4 +33,4 @@ fi bun install # build and run dev.ts -bun build:cli && node ./.build_run/src/run.js "$@" +bun build:cli > /dev/null && node ./.build_run/src/run.js "$@"