Skip to content

Commit

Permalink
clean up types across app
Browse files Browse the repository at this point in the history
  • Loading branch information
karla-vm committed Jun 3, 2024
1 parent e448d3e commit 06c9d51
Show file tree
Hide file tree
Showing 10 changed files with 602 additions and 130 deletions.
9 changes: 7 additions & 2 deletions services/app-api/utils/formTemplates/formTemplates.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
getOrCreateFormTemplate,
getValidationFromFormTemplate,
isFieldElement,
isLayoutElement,
} from "./formTemplates";
import { DynamoDBDocumentClient, QueryCommand } from "@aws-sdk/lib-dynamodb";
import { mockClient } from "aws-sdk-client-mock";
Expand All @@ -21,7 +20,13 @@ import {
mockS3PutObjectCommandOutput,
} from "../testing/setupJest";
// types
import { FormJson, ReportJson, ReportRoute, ReportType } from "../types";
import {
FormJson,
ReportJson,
ReportRoute,
ReportType,
isLayoutElement,
} from "../types";
import { createHash } from "crypto";

const dynamoClientMock = mockClient(DynamoDBDocumentClient);
Expand Down
10 changes: 0 additions & 10 deletions services/app-api/utils/formTemplates/formTemplates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,16 +255,6 @@ export function isFieldElement(
return !formLayoutElementTypes.includes(field.type);
}

export function isLayoutElement(
field: FormField | FormLayoutElement
): field is FormLayoutElement {
/*
* This function is duplicated in ui-src/src/types/formFields.ts
* If you change it here, change it there!
*/
return (field as FormField).validation === undefined;
}

export function getValidationFromFormTemplate(reportJson: ReportJson) {
return compileValidationJsonFromRoutes(
flattenReportRoutesArray(reportJson.routes)
Expand Down
132 changes: 120 additions & 12 deletions services/app-api/utils/types/formFields.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,52 @@
import { AnyObject } from "./other";
import { ModalOverlayReportPageVerbiage, ReportPageShapeBase } from "./reports";

// FORM & FIELD STRUCTURE

export interface ModalOverlayReportPageShape extends ReportPageShapeBase {
entityType: string;
verbiage: ModalOverlayReportPageVerbiage;
modalForm: FormJson;
overlayForm?: FormJson;
drawerForm?: never;
form?: never;
/**
* Reports can have nested entities, each of which refers to a distinct instance of a form.
* This constant represents all of the entity types that are currently available.
*/
export const entityTypes = [
"plans",
"bssEntities",
"accessMeasures",
"qualityMeasures",
"sanctions",
"program",
"ilos",
] as const;

/**
* This type is a string union type generated by the constant above.
*/
export declare type EntityType = typeof entityTypes[number];

export enum ModalDrawerEntityTypes {
ACCESS_MEASURES = "accessMeasures",
QUALITY_MEASURES = "qualityMeasures",
SANCTIONS = "sanctions",
}

export interface FormLayoutElement {
export interface EntityShape {
id: string;
type: string;
props?: AnyObject;
[key: string]: any;
}

/**
* General type for all form JSON.
*/
export interface FormJson {
id: string;
fields: FormField[];
fields: (FormField | FormLayoutElement)[];
heading?: AnyObject;
options?: AnyObject;
validation?: AnyObject;
/**
* False for most forms, including all report forms.
* True for the admin banner and dash selector.
* Only exists on the UI side; the API is protected by routes.
*/
editableByAdmins?: boolean;
}

export interface DependentFieldValidation {
Expand Down Expand Up @@ -61,6 +85,17 @@ export interface FormField {
repeat?: string;
}

export interface FormLayoutElement {
id: string;
type: string;
props?: AnyObject;
}

export interface DropdownOptions {
label: string;
value: string;
}

export interface FieldChoice {
id: string;
name: string;
Expand All @@ -71,7 +106,80 @@ export interface FieldChoice {
checkedChildren?: any;
}

export interface ChoiceFieldProps {
name: string;
label: string;
choices: FieldChoice[];
sxOverride?: AnyObject;
[key: string]: any;
}
export interface Choice {
key: string; // choice.name
value: string; // choice.value
}

export interface DropdownChoice {
label: string;
value: string;
}

/**
* Shape of autosave field input. Since autosave is atomic, it requires a special shape
* to more easily validate field values.
*/
export interface AutosaveField {
name: string;
type: string;
value: FieldValue;
defaultValue?: FieldValue;
hydrationValue?: FieldValue;
overrideCheck?: boolean;
}

/**
* Type for a selection radio or checklist option.
*/
export interface SelectedOption {
label: string;
value: string;
}

/**
* All (most) of the possible field value types.
*/
export type FieldValue =
| string
| number
| EntityShape
| EntityShape[]
| Choice
| Choice[]
| SelectedOption;

// HELPER FUNCTIONS

/**
* Check if an unknown string is an entity type.
*
* @param entityType unknown string
* @returns true and string is EntityType, false.
*/
export function isEntityType(entityType: string): entityType is EntityType {
return entityTypes.includes(entityType as EntityType);
}

export function isFieldElement(
field: FormField | FormLayoutElement
): field is FormField {
/*
* This function is duplicated in app-api/utils/formTemplates/formTemplates.ts
* If you change it here, change it there!
*/
const formLayoutElementTypes = ["sectionHeader", "sectionContent"];
return !formLayoutElementTypes.includes(field.type);
}
export function isLayoutElement(
field: FormField | FormLayoutElement
): field is FormLayoutElement {
return (field as FormField).validation === undefined;
}
55 changes: 47 additions & 8 deletions services/app-api/utils/types/other.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,6 @@ export const enum StatusCodes {
SERVER_ERROR = 500,
}

export interface CompletionData {
[key: string]: boolean | CompletionData;
}

/**
* Abridged copy of the type used by `aws-lambda@1.0.7` (from `@types/aws-lambda@8.10.88`)
* We only this package for these types, and we use only a subset of the
Expand Down Expand Up @@ -94,6 +90,29 @@ export interface S3EventRecord {
glacierEventData?: S3EventRecordGlacierEventData | undefined;
}

// ALERTS

export enum AlertTypes {
ERROR = "error",
INFO = "info",
SUCCESS = "success",
WARNING = "warning",
}

// TIME

export interface DateShape {
year: number;
month: number;
day: number;
}

export interface TimeShape {
hour: number;
minute: number;
second: number;
}

// OTHER

export interface CustomHtmlElement {
Expand All @@ -109,6 +128,24 @@ export const enum TemplateKeys {
NAAAR = "templates/naaar-reporting-template.xlsx",
}

export enum PageTypes {
STANDARD = "standard",
DRAWER = "drawer",
MODAL_DRAWER = "modalDrawer",
MODAL_OVERLAY = "modalOverlay",
REVIEW_SUBMIT = "reviewSubmit",
}

export interface ScreenReaderOnlyHeaderName {
hiddenName: string;
}

export interface TableContentShape {
caption?: string;
headRow?: Array<string | ScreenReaderOnlyHeaderName>;
bodyRows?: string[][];
}

const states = [
"AL",
"AK",
Expand Down Expand Up @@ -165,10 +202,6 @@ const states = [
] as const;
export type State = typeof states[number];

export const isState = (state: unknown): state is State => {
return states.includes(state as State);
};

export interface FormTemplate {
md5Hash: string;
versionNumber: number;
Expand All @@ -177,6 +210,12 @@ export interface FormTemplate {
reportType: string;
}

// HELPER FUNCTIONS

export const isState = (state: unknown): state is State => {
return states.includes(state as State);
};

/**
* Instructs Typescript to complain if it detects that this function may be reachable.
* Useful for the default branch of a switch statement that verifiably covers every case.
Expand Down
70 changes: 70 additions & 0 deletions services/app-api/utils/types/reportContext.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,77 @@
// REPORT PROVIDER/CONTEXT

import { AnyObject, Choice, ReportJson } from "./index";

export interface ReportKeys {
reportType: string;
state: string;
id: string;
}

export interface ReportMetadataShape extends ReportKeys {
submissionCount: number;
reportType: string;
programName: string;
submissionName?: string;
status: ReportStatus;
reportingPeriodStartDate: number;
reportingPeriodEndDate: number;
dueDate: number;
createdAt: number;
lastAltered: number;
lastAlteredBy: string;
combinedData: boolean;
submittedBy?: string;
submitterEmail?: string;
submittedOnDate?: number;
archived?: boolean;
locked: boolean;
fieldDataId: string;
copyFieldDataSourceId?: string;
programIsPCCM?: Choice[];
ilosAvailable?: boolean;
previousRevisions: string[];
}

export interface ReportShape extends ReportMetadataShape {
formTemplate: ReportJson;
fieldData: AnyObject;
completionStatus?: CompletionData;
isComplete?: boolean;
}

export interface CompletionData {
[key: string]: boolean | CompletionData;
}

export interface ReportContextMethods {
fetchReport: Function;
fetchReportsByState: Function;
archiveReport: Function;
releaseReport?: Function;
submitReport: Function;
createReport: Function;
updateReport: Function;
clearReportSelection: Function;
clearReportsByState: Function;
setReportSelection: Function;
}

export interface ReportContextShape extends ReportContextMethods {
contextIsLoaded: boolean;
errorMessage?: string | undefined;
isReportPage: boolean;
}

export enum ReportStatus {
NOT_STARTED = "Not started",
IN_PROGRESS = "In progress",
SUBMITTED = "Submitted",
}

export interface ReportPageProgress {
name: string;
path: string;
children?: ReportPageProgress[];
status?: boolean;
}
Loading

0 comments on commit 06c9d51

Please sign in to comment.