Skip to content

Commit

Permalink
Reapply "feat: replace old Status index with new StatusCreatedAt one (#…
Browse files Browse the repository at this point in the history
…4691)" (#4761) (#4763)

* Reapply "feat: replace old Status index with new StatusCreatedAt one (#4691)" (#4761)

This reverts commit 78a8457.

* fix DynamoDB request configuration when no Status#CreatedAt need to be passed in
  • Loading branch information
craigzour authored Dec 10, 2024
1 parent e860a68 commit c031a4a
Show file tree
Hide file tree
Showing 12 changed files with 274 additions and 314 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
retrieveSubmissions,
updateLastDownloadedBy,
submissionTypeExists,
retrieveSubmissionRemovalDate,
} from "@lib/vault";
import { transform as csvTransform } from "@lib/responseDownloadFormats/csv";
import { transform as htmlAggregatedTransform } from "@lib/responseDownloadFormats/html-aggregated";
Expand Down Expand Up @@ -228,119 +229,121 @@ export const getSubmissionsByFormat = async ({

const allowGroupsFlag = allowGrouping();
// Get responses into a ResponseSubmission array containing questions and answers that can be easily transformed
const responses = queryResult.map((item) => {
const submission = Object.entries(JSON.parse(String(item.formSubmission))).map(
([questionId, answer]) => {
const question = fullFormTemplate.form.elements.find(
(element) => element.id === Number(questionId)
);

// Handle Dynamic Rows
if (question?.type === FormElementTypes.dynamicRow && answer instanceof Array) {
return {
questionId: question.id,
type: question?.type,
questionEn: question?.properties.titleEn,
questionFr: question?.properties.titleFr,
answer: answer.map((item) => {
return Object.values(item).map((value, index) => {
if (question?.properties.subElements) {
const subQuestion = question?.properties.subElements[index];
return {
questionId: question?.id,
type: subQuestion.type,
questionEn: subQuestion.properties.titleEn,
questionFr: subQuestion.properties.titleFr,
answer: getAnswerAsString(subQuestion, value),
...(subQuestion.type === "formattedDate" && {
dateFormat: subQuestion.properties.dateFormat,
}),
};
}
});
}),
} as Answer;
}

// Handle "Split" AddressComplete in a similiar manner to dynamic fields.
if (
question?.type === FormElementTypes.addressComplete &&
question.properties.addressComponents?.splitAddress === true
) {
const addressObject = JSON.parse(answer as string) as AddressElements;
const responses = queryResult
.sort((a, b) => a.createdAt - b.createdAt)
.map((item) => {
const submission = Object.entries(JSON.parse(String(item.formSubmission))).map(
([questionId, answer]) => {
const question = fullFormTemplate.form.elements.find(
(element) => element.id === Number(questionId)
);

const questionComponents = question.properties.addressComponents as AddressComponents;
if (questionComponents.canadianOnly) {
addressObject.country = "CAN";
// Handle Dynamic Rows
if (question?.type === FormElementTypes.dynamicRow && answer instanceof Array) {
return {
questionId: question.id,
type: question?.type,
questionEn: question?.properties.titleEn,
questionFr: question?.properties.titleFr,
answer: answer.map((item) => {
return Object.values(item).map((value, index) => {
if (question?.properties.subElements) {
const subQuestion = question?.properties.subElements[index];
return {
questionId: question?.id,
type: subQuestion.type,
questionEn: subQuestion.properties.titleEn,
questionFr: subQuestion.properties.titleFr,
answer: getAnswerAsString(subQuestion, value),
...(subQuestion.type === "formattedDate" && {
dateFormat: subQuestion.properties.dateFormat,
}),
};
}
});
}),
} as Answer;
}

const extraTranslations = {
streetAddress: {
en: tEn("addressComponents.streetAddress"),
fr: tFr("addressComponents.streetAddress"),
},
city: {
en: tEn("addressComponents.city"),
fr: tFr("addressComponents.city"),
},
province: {
en: tEn("addressComponents.province"),
fr: tFr("addressComponents.province"),
},
postalCode: {
en: tEn("addressComponents.postalCode"),
fr: tFr("addressComponents.postalCode"),
},
country: {
en: tEn("addressComponents.country"),
fr: tFr("addressComponents.country"),
},
};

const reviewElements = getAddressAsAnswerElements(
question,
addressObject,
extraTranslations
);

const addressElements = [reviewElements];
// Handle "Split" AddressComplete in a similiar manner to dynamic fields.
if (
question?.type === FormElementTypes.addressComplete &&
question.properties.addressComponents?.splitAddress === true
) {
const addressObject = JSON.parse(answer as string) as AddressElements;

const questionComponents = question.properties.addressComponents as AddressComponents;
if (questionComponents.canadianOnly) {
addressObject.country = "CAN";
}

const extraTranslations = {
streetAddress: {
en: tEn("addressComponents.streetAddress"),
fr: tFr("addressComponents.streetAddress"),
},
city: {
en: tEn("addressComponents.city"),
fr: tFr("addressComponents.city"),
},
province: {
en: tEn("addressComponents.province"),
fr: tFr("addressComponents.province"),
},
postalCode: {
en: tEn("addressComponents.postalCode"),
fr: tFr("addressComponents.postalCode"),
},
country: {
en: tEn("addressComponents.country"),
fr: tFr("addressComponents.country"),
},
};

const reviewElements = getAddressAsAnswerElements(
question,
addressObject,
extraTranslations
);

const addressElements = [reviewElements];

return {
questionId: question.id,
type: FormElementTypes.address,
questionEn: question?.properties.titleEn,
questionFr: question?.properties.titleFr,
answer: addressElements,
} as Answer;
}

// return the final answer object
return {
questionId: question.id,
type: FormElementTypes.address,
questionId: question?.id,
type: question?.type,
questionEn: question?.properties.titleEn,
questionFr: question?.properties.titleFr,
answer: addressElements,
answer: getAnswerAsString(question, answer),
...(question?.type === "formattedDate" && {
dateFormat: question.properties.dateFormat,
}),
} as Answer;
}

// return the final answer object
return {
questionId: question?.id,
type: question?.type,
questionEn: question?.properties.titleEn,
questionFr: question?.properties.titleFr,
answer: getAnswerAsString(question, answer),
...(question?.type === "formattedDate" && {
dateFormat: question.properties.dateFormat,
}),
} as Answer;
);
let sorted: Answer[];
if (allowGroupsFlag && formHasGroups(fullFormTemplate.form)) {
sorted = sortByGroups({ form: fullFormTemplate.form, elements: submission });
} else {
sorted = sortByLayout({ layout: fullFormTemplate.form.layout, elements: submission });
}
);
let sorted: Answer[];
if (allowGroupsFlag && formHasGroups(fullFormTemplate.form)) {
sorted = sortByGroups({ form: fullFormTemplate.form, elements: submission });
} else {
sorted = sortByLayout({ layout: fullFormTemplate.form.layout, elements: submission });
}

return {
id: item.name,
createdAt: parseInt(item.createdAt.toString()),
confirmationCode: item.confirmationCode,
answers: sorted,
};
}) as FormResponseSubmissions["submissions"];
return {
id: item.name,
createdAt: parseInt(item.createdAt.toString()),
confirmationCode: item.confirmationCode,
answers: sorted,
};
}) as FormResponseSubmissions["submissions"];

if (!responses.length) {
throw new FormBuilderError("No responses found.", FormServerErrorCodes.NO_RESPONSES_FOUND);
Expand Down Expand Up @@ -446,3 +449,13 @@ export const unConfirmedResponsesExist = async (formId: string) => {
return { error: "There was an error. Please try again later." } as ServerActionError;
}
};

export const getSubmissionRemovalDate = async (formId: string, submissionName: string) => {
try {
const { ability } = await authCheckAndRedirect();
return retrieveSubmissionRemovalDate(ability, formId, submissionName);
} catch (error) {
// Throw sanitized error back to client
return { error: "There was an error. Please try again later." } as ServerActionError;
}
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use client";
import { CheckAllIcon, CheckBoxEmptyIcon, CheckIndeterminateIcon } from "@serverComponents/icons";
import { VaultSubmissionList } from "@lib/types";
import { VaultSubmissionOverview } from "@lib/types";
import React from "react";
import { useTranslation } from "@i18n/client";
import { ReducerTableItemsActions, TableActions } from "./DownloadTableReducer";
Expand All @@ -15,7 +15,7 @@ export const CheckAll = ({
tableItems: {
checkedItems: Map<string, boolean>;
statusItems: Map<string, boolean>;
allItems: VaultSubmissionList[];
allItems: VaultSubmissionOverview[];
numberOfOverdueResponses: number;
};
tableItemsDispatch: React.Dispatch<ReducerTableItemsActions>;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
import React, { useEffect, useReducer, useState } from "react";
import {
NagwareResult,
TypeOmit,
VaultStatus,
VaultSubmission,
VaultSubmissionList,
} from "@lib/types";
import { NagwareResult, VaultStatus, VaultSubmissionOverview } from "@lib/types";
import { useTranslation } from "@i18n/client";
import { SkipLinkReusable } from "@clientComponents/globals/SkipLinkReusable";
import Link from "next/link";
Expand All @@ -29,7 +23,7 @@ import { StatusFilter } from "../types";
import { useFormBuilderConfig } from "@lib/hooks/useFormBuilderConfig";

interface DownloadTableProps {
vaultSubmissions: VaultSubmissionList[];
vaultSubmissions: VaultSubmissionOverview[];
formName: string;
formId: string;
nagwareResult: NagwareResult | null;
Expand Down Expand Up @@ -83,9 +77,7 @@ export const DownloadTable = ({
}
};

const blockDownload = (
submission: TypeOmit<VaultSubmission, "formSubmission" | "submissionID" | "confirmationCode">
) => {
const blockDownload = (submission: VaultSubmissionOverview) => {
const daysPast = getDaysPassed(submission.createdAt);

if (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getDaysPassed } from "@lib/client/clientHelpers";
import { VaultSubmissionList, VaultStatus } from "@lib/types";
import { VaultSubmissionOverview, VaultStatus } from "@lib/types";

export enum TableActions {
UPDATE = "UPDATE",
Expand All @@ -9,7 +9,7 @@ export enum TableActions {
interface ReducerTableItemsState {
statusItems: Map<string, boolean>;
checkedItems: Map<string, boolean>;
allItems: VaultSubmissionList[];
allItems: VaultSubmissionOverview[];
numberOfOverdueResponses: number;
overdueAfter: number | undefined;
}
Expand All @@ -21,12 +21,12 @@ export interface ReducerTableItemsActions {
name: string;
checked: boolean;
};
vaultSubmissions?: VaultSubmissionList[];
vaultSubmissions?: VaultSubmissionOverview[];
};
}

export const initialTableItemsState = (
vaultSubmissions: VaultSubmissionList[],
vaultSubmissions: VaultSubmissionOverview[],
overdueAfter: number | undefined
) => {
return {
Expand Down
Loading

0 comments on commit c031a4a

Please sign in to comment.