From 822a8d209900bdb587ba2f81c67f4b6b3958d865 Mon Sep 17 00:00:00 2001 From: Rafael Solorzano <61289255+rafasdc@users.noreply.github.com> Date: Thu, 27 Jul 2023 13:37:09 -0700 Subject: [PATCH 1/8] feat: initial archive draft mutation and ui --- app/components/Dashboard/Row.tsx | 10 ++++ .../application/archiveApplication.ts | 24 +++++++++ app/schema/schema.graphql | 51 +++++++++++++++++++ db/deploy/mutations/archive_application.sql | 36 +++++++++++++ db/revert/mutations/archive_application.sql | 7 +++ db/sqitch.plan | 1 + 6 files changed, 129 insertions(+) create mode 100644 app/schema/mutations/application/archiveApplication.ts create mode 100644 db/deploy/mutations/archive_application.sql create mode 100644 db/revert/mutations/archive_application.sql diff --git a/app/components/Dashboard/Row.tsx b/app/components/Dashboard/Row.tsx index 3ad9253115..0e25c75b30 100644 --- a/app/components/Dashboard/Row.tsx +++ b/app/components/Dashboard/Row.tsx @@ -44,6 +44,7 @@ const Row = ({ application, formPages, reviewPage, setWithdrawId }) => { const isWithdrawn = application.status === 'withdrawn'; const isSubmitted = application.status === 'submitted'; + const isDraft = application.status === 'draft'; const getApplicationUrl = () => { if (isWithdrawn) { @@ -85,6 +86,15 @@ const Row = ({ application, formPages, reviewPage, setWithdrawId }) => { )} + {!ccbcNumber && isDraft && ( + setWithdrawId(rowId)} + data-testid="withdraw-btn-test" + type="button" + > + Delete + + )} {application.hasRfiOpen && ( + useMutationWithErrorMessage( + mutation, + () => 'An error occurred while archiveing the application.' + ); + +export { mutation, useArchiveApplicationMutation }; diff --git a/app/schema/schema.graphql b/app/schema/schema.graphql index dad4289619..62eb927a9d 100644 --- a/app/schema/schema.graphql +++ b/app/schema/schema.graphql @@ -45839,6 +45839,14 @@ type Mutation { """ input: DeleteSowTab8ByRowIdInput! ): DeleteSowTab8Payload + + """Mutation to archive an application and its related data""" + archiveApplication( + """ + The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields. + """ + input: ArchiveApplicationInput! + ): ArchiveApplicationPayload archiveApplicationSow( """ The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields. @@ -53443,6 +53451,49 @@ input DeleteSowTab8ByRowIdInput { rowId: Int! } +"""The output of our `archiveApplication` mutation.""" +type ArchiveApplicationPayload { + """ + The exact same `clientMutationId` that was provided in the mutation input, + unchanged and unused. May be used by a client to track mutations. + """ + clientMutationId: String + application: Application + + """ + Our root query field type. Allows us to run any query from our mutation payload. + """ + query: Query + + """Reads a single `Intake` that is related to this `Application`.""" + intakeByIntakeId: Intake + + """Reads a single `CcbcUser` that is related to this `Application`.""" + ccbcUserByCreatedBy: CcbcUser + + """Reads a single `CcbcUser` that is related to this `Application`.""" + ccbcUserByUpdatedBy: CcbcUser + + """Reads a single `CcbcUser` that is related to this `Application`.""" + ccbcUserByArchivedBy: CcbcUser + + """An edge for our `Application`. May be used by Relay 1.""" + applicationEdge( + """The method to use when ordering `Application`.""" + orderBy: [ApplicationsOrderBy!] = [PRIMARY_KEY_ASC] + ): ApplicationsEdge +} + +"""All input for the `archiveApplication` mutation.""" +input ArchiveApplicationInput { + """ + An arbitrary string value with no semantic meaning. Will be included in the + payload verbatim. May be used to track mutations by the client. + """ + clientMutationId: String + applicationRowId: Int! +} + """The output of our `archiveApplicationSow` mutation.""" type ArchiveApplicationSowPayload { """ diff --git a/db/deploy/mutations/archive_application.sql b/db/deploy/mutations/archive_application.sql new file mode 100644 index 0000000000..defd3fe8f1 --- /dev/null +++ b/db/deploy/mutations/archive_application.sql @@ -0,0 +1,36 @@ +-- Deploy ccbc:mutations/archive_application to pg + +begin; + +create or replace function ccbc_public.archive_application(application_row_id int) +returns ccbc_public.application as $$ +declare +application_status varchar; +form_data_id int; +form_data_status varchar(1000); +begin + +select ccbc_public.application_status(ccbc_public.application.*) into application_status from ccbc_public.application where id = application_row_id; + +select id, form_data_status_type_id from +ccbc_public.application_form_data((select row(ccbc_public.application.*)::ccbc_public.application from ccbc_public.application where id = application_row_id)) +into form_data_id, form_data_status; + + +-- Just one more check at the DB level making sure form is in draft +if application_status === 'draft' then + update ccbc_public.form_data set archived_at = now() where id = form_data_id; + update ccbc_public.application set archived_at = now() where id = application_row_id; +end if; + +return (select row(application.*)::ccbc_public.application from ccbc_public.application where id = application_row_id); + +end + +$$ language plpgsql; + +grant execute on function ccbc_public.archive_application to ccbc_auth_user; + +comment on function ccbc_public.archive_application is 'Mutation to archive an application and its related data'; + +commit; diff --git a/db/revert/mutations/archive_application.sql b/db/revert/mutations/archive_application.sql new file mode 100644 index 0000000000..a0903dce2c --- /dev/null +++ b/db/revert/mutations/archive_application.sql @@ -0,0 +1,7 @@ +-- Revert ccbc:mutations/archive_application from pg + +BEGIN; + +drop function if exists ccbc_public.archive_application; + +COMMIT; diff --git a/db/sqitch.plan b/db/sqitch.plan index 643fd0d07c..8484fe9bc8 100644 --- a/db/sqitch.plan +++ b/db/sqitch.plan @@ -372,3 +372,4 @@ mutations/create_change_request [mutations/create_change_request@1.85.0] 2023-07 tables/intake_005_add_description 2023-07-19T23:20:24Z Marcel Mueller # add description column functions/next_intake [functions/next_intake@1.85.0] 2023-07-24T20:08:07Z Marcel Mueller # grant analyst permissions mutations/create_intake [mutations/create_intake@1.88.0] 2023-07-24T21:51:46Z Marcel Mueller # add description input and verify intake number +mutations/archive_application 2023-07-26T22:48:25Z Rafael Solorzano <61289255+rafasdc@users.noreply.github.com> # functionality to archive application and its form data From ca93da5be9963d1de902e5b93f2381a507e5cec5 Mon Sep 17 00:00:00 2001 From: Rafael Solorzano <61289255+rafasdc@users.noreply.github.com> Date: Thu, 27 Jul 2023 15:35:46 -0700 Subject: [PATCH 2/8] feat: only show non archived applications --- app/pages/applicantportal/dashboard.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/pages/applicantportal/dashboard.tsx b/app/pages/applicantportal/dashboard.tsx index 28e77134d3..f2996a8626 100644 --- a/app/pages/applicantportal/dashboard.tsx +++ b/app/pages/applicantportal/dashboard.tsx @@ -167,7 +167,7 @@ export const withRelayOptions = { const sub: string = ctx?.req?.claims?.sub; return { - formOwner: { owner: sub }, + formOwner: { owner: sub, archivedAt: null, archivedBy: null }, }; }, }; From 348c9e864de00d0d1f46621c929b90c19b39c641 Mon Sep 17 00:00:00 2001 From: Rafael Solorzano <61289255+rafasdc@users.noreply.github.com> Date: Thu, 27 Jul 2023 16:02:43 -0700 Subject: [PATCH 3/8] fix: application status check --- db/deploy/mutations/archive_application.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/deploy/mutations/archive_application.sql b/db/deploy/mutations/archive_application.sql index defd3fe8f1..266c21e007 100644 --- a/db/deploy/mutations/archive_application.sql +++ b/db/deploy/mutations/archive_application.sql @@ -18,7 +18,7 @@ into form_data_id, form_data_status; -- Just one more check at the DB level making sure form is in draft -if application_status === 'draft' then +if application_status = 'draft' then update ccbc_public.form_data set archived_at = now() where id = form_data_id; update ccbc_public.application set archived_at = now() where id = application_row_id; end if; From 19a35be67b9df27ec3f7cf95c0dcb97bbd09d470 Mon Sep 17 00:00:00 2001 From: Rafael Solorzano <61289255+rafasdc@users.noreply.github.com> Date: Thu, 27 Jul 2023 16:04:07 -0700 Subject: [PATCH 4/8] feat: delete draft application --- app/components/Dashboard/ArchiveModal.tsx | 92 +++++++++++++++++++++++ app/components/Dashboard/Row.tsx | 15 +++- app/components/Dashboard/Table.tsx | 5 +- 3 files changed, 108 insertions(+), 4 deletions(-) create mode 100644 app/components/Dashboard/ArchiveModal.tsx diff --git a/app/components/Dashboard/ArchiveModal.tsx b/app/components/Dashboard/ArchiveModal.tsx new file mode 100644 index 0000000000..858989d416 --- /dev/null +++ b/app/components/Dashboard/ArchiveModal.tsx @@ -0,0 +1,92 @@ +import { useState } from 'react'; +import Button from '@button-inc/bcgov-theme/Button'; +import Modal from '@button-inc/bcgov-theme/Modal'; +import styled from 'styled-components'; + +import { useArchiveApplicationMutation } from 'schema/mutations/application/archiveApplication'; +import X from './XIcon'; + +const StyledModal = styled(Modal)` + display: flex; + align-items: center; + z-index: 2; +`; + +const ModalButtons = styled('div')` + & button { + margin-right: 1em; + } +`; + +const StyledConfirmBox = styled('div')` + position: absolute; + left: 40px; + bottom: 3.5em; + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + + background: #1a5a96; + border-radius: 4px; + color: #ffffff; + padding: 16px 24px; + + & div:first-child { + margin-right: 1em; + } +`; + +const ArchiveModal = ({ id }) => { + const [successModal, setSuccessModal] = useState(false); + + const [archiveApplication] = useArchiveApplicationMutation(); + + const handleWithdraw = async () => { + archiveApplication({ + variables: { + input: { + applicationRowId: id, + }, + }, + onCompleted: () => setSuccessModal(true), + }); + }; + + return ( + <> + + + Delete draft + + + + + + Are you sure you want to delete this draft application? + + + + Yes, delete + + + + + No, keep + + + + + {successModal && ( + + Application deleted + setSuccessModal(false)}> + + + + )} + > + ); +}; + +export default ArchiveModal; diff --git a/app/components/Dashboard/Row.tsx b/app/components/Dashboard/Row.tsx index 0e25c75b30..937fc13df0 100644 --- a/app/components/Dashboard/Row.tsx +++ b/app/components/Dashboard/Row.tsx @@ -31,7 +31,13 @@ const StyledBtns = styled('div')` } `; -const Row = ({ application, formPages, reviewPage, setWithdrawId }) => { +const Row = ({ + application, + formPages, + reviewPage, + setWithdrawId, + setArchiveId, +}) => { const { ccbcNumber, intakeByIntakeId, formData, projectName, rowId, status } = application; @@ -88,8 +94,11 @@ const Row = ({ application, formPages, reviewPage, setWithdrawId }) => { )} {!ccbcNumber && isDraft && ( setWithdrawId(rowId)} - data-testid="withdraw-btn-test" + onClick={() => { + setArchiveId(rowId); + window.location.hash = 'delete-application'; + }} + data-testid="archive-btn-test" type="button" > Delete diff --git a/app/components/Dashboard/Table.tsx b/app/components/Dashboard/Table.tsx index 7d2e3f53de..4cdd4a3827 100644 --- a/app/components/Dashboard/Table.tsx +++ b/app/components/Dashboard/Table.tsx @@ -7,6 +7,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faCircleInfo } from '@fortawesome/free-solid-svg-icons'; import Modal from './Modal'; import Row from './Row'; +import ArchiveModal from './ArchiveModal'; const StyledFontAwesome = styled(FontAwesomeIcon)` margin-left: 4px; ; @@ -40,6 +41,7 @@ type Props = { const Table = ({ applications }: Props) => { const [withdrawId, setWithdrawId] = useState(null); + const [archiveId, setArchiveId] = useState(null); const applicationNodes = applications.allApplications.nodes; @@ -77,12 +79,13 @@ const Table = ({ applications }: Props) => { formPages={formPages} reviewPage={reviewPage} setWithdrawId={setWithdrawId} + setArchiveId={setArchiveId} /> ); })} - + > ); From 16cc58e747ffe4e216f1da4f33e5873a1938cebb Mon Sep 17 00:00:00 2001 From: Rafael Solorzano <61289255+rafasdc@users.noreply.github.com> Date: Fri, 28 Jul 2023 13:08:23 -0700 Subject: [PATCH 5/8] feat(relay): set connection key and edges for delete updated graphql query to use connection key and move to edges and node for updater when application is deleted for immediate UI refresh --- app/components/Dashboard/ArchiveModal.tsx | 11 ++++- app/components/Dashboard/Row.tsx | 13 +++-- app/components/Dashboard/Table.tsx | 12 +++-- app/pages/applicantportal/dashboard.tsx | 49 +++++++++++-------- .../application/archiveApplication.ts | 2 + 5 files changed, 57 insertions(+), 30 deletions(-) diff --git a/app/components/Dashboard/ArchiveModal.tsx b/app/components/Dashboard/ArchiveModal.tsx index 858989d416..6b2dea7d23 100644 --- a/app/components/Dashboard/ArchiveModal.tsx +++ b/app/components/Dashboard/ArchiveModal.tsx @@ -4,6 +4,7 @@ import Modal from '@button-inc/bcgov-theme/Modal'; import styled from 'styled-components'; import { useArchiveApplicationMutation } from 'schema/mutations/application/archiveApplication'; +import { ConnectionHandler } from 'relay-runtime'; import X from './XIcon'; const StyledModal = styled(Modal)` @@ -37,8 +38,9 @@ const StyledConfirmBox = styled('div')` } `; -const ArchiveModal = ({ id }) => { +const ArchiveModal = ({ applications, id }) => { const [successModal, setSuccessModal] = useState(false); + const relayId = applications.allApplications.__id; const [archiveApplication] = useArchiveApplicationMutation(); @@ -46,10 +48,15 @@ const ArchiveModal = ({ id }) => { archiveApplication({ variables: { input: { - applicationRowId: id, + applicationRowId: id.rowId, }, }, onCompleted: () => setSuccessModal(true), + updater: (store) => { + const connection = store.get(relayId); + store.delete(id.id); + ConnectionHandler.deleteNode(connection, id.id); + }, }); }; diff --git a/app/components/Dashboard/Row.tsx b/app/components/Dashboard/Row.tsx index 937fc13df0..42bc851954 100644 --- a/app/components/Dashboard/Row.tsx +++ b/app/components/Dashboard/Row.tsx @@ -38,8 +38,15 @@ const Row = ({ setWithdrawId, setArchiveId, }) => { - const { ccbcNumber, intakeByIntakeId, formData, projectName, rowId, status } = - application; + const { + ccbcNumber, + intakeByIntakeId, + formData, + projectName, + rowId, + status, + id, + } = application; const lastEditedIndex = formPages.indexOf(formData.lastEditedPage) + 1; @@ -95,7 +102,7 @@ const Row = ({ {!ccbcNumber && isDraft && ( { - setArchiveId(rowId); + setArchiveId({ rowId, id }); window.location.hash = 'delete-application'; }} data-testid="archive-btn-test" diff --git a/app/components/Dashboard/Table.tsx b/app/components/Dashboard/Table.tsx index 4cdd4a3827..2fd6d69877 100644 --- a/app/components/Dashboard/Table.tsx +++ b/app/components/Dashboard/Table.tsx @@ -41,9 +41,11 @@ type Props = { const Table = ({ applications }: Props) => { const [withdrawId, setWithdrawId] = useState(null); - const [archiveId, setArchiveId] = useState(null); + const [archiveId, setArchiveId] = useState({ rowId: null, id: null }); - const applicationNodes = applications.allApplications.nodes; + const applicationNodes = applications.allApplications.edges + .map((edge) => edge.node) + .filter((node) => node !== null); const formPages = Object.keys(schema.properties); @@ -72,7 +74,7 @@ const Table = ({ applications }: Props) => { {applicationNodes.map((application) => { - return ( + return application ? ( { setWithdrawId={setWithdrawId} setArchiveId={setArchiveId} /> - ); + ) : null; })} - + > ); diff --git a/app/pages/applicantportal/dashboard.tsx b/app/pages/applicantportal/dashboard.tsx index f2996a8626..16b35d549d 100644 --- a/app/pages/applicantportal/dashboard.tsx +++ b/app/pages/applicantportal/dashboard.tsx @@ -16,26 +16,35 @@ import { dashboardQuery } from '__generated__/dashboardQuery.graphql'; const getDashboardQuery = graphql` query dashboardQuery($formOwner: ApplicationCondition!) { - allApplications(condition: $formOwner, orderBy: CREATED_AT_DESC) { - nodes { - id - rowId - owner - status - projectName - ccbcNumber - formData { - lastEditedPage - isEditable - } - intakeByIntakeId { - ccbcIntakeNumber - closeTimestamp - openTimestamp - } - hasRfiOpen - rfi { + allApplications( + condition: $formOwner + orderBy: CREATED_AT_DESC + first: 1000 + ) @connection(key: "dashboard_allApplications") { + __id + edges { + node { + id + archivedAt + archivedBy rowId + owner + status + projectName + ccbcNumber + formData { + lastEditedPage + isEditable + } + intakeByIntakeId { + ccbcIntakeNumber + closeTimestamp + openTimestamp + } + hasRfiOpen + rfi { + rowId + } } } } @@ -66,7 +75,7 @@ const Dashboard = ({ const sub: string = session?.sub; - const hasApplications = allApplications.nodes.length > 0; + const hasApplications = allApplications.edges.length > 0; const router = useRouter(); diff --git a/app/schema/mutations/application/archiveApplication.ts b/app/schema/mutations/application/archiveApplication.ts index b2a1eae490..70c6e23f24 100644 --- a/app/schema/mutations/application/archiveApplication.ts +++ b/app/schema/mutations/application/archiveApplication.ts @@ -5,7 +5,9 @@ import useMutationWithErrorMessage from '../useMutationWithErrorMessage'; const mutation = graphql` mutation archiveApplicationMutation($input: ArchiveApplicationInput!) { archiveApplication(input: $input) { + clientMutationId application { + id updatedAt status ccbcNumber From 87ac68edbcfac60bf396cd9af19309c495bbb671 Mon Sep 17 00:00:00 2001 From: Rafael Solorzano <61289255+rafasdc@users.noreply.github.com> Date: Fri, 28 Jul 2023 15:54:18 -0700 Subject: [PATCH 6/8] test: update to use edges and node --- .../components/Dashboard/Dashboard.test.tsx | 277 ++++++++++-------- .../pages/applicantportal/dashboard.test.tsx | 60 ++-- 2 files changed, 180 insertions(+), 157 deletions(-) diff --git a/app/tests/components/Dashboard/Dashboard.test.tsx b/app/tests/components/Dashboard/Dashboard.test.tsx index 0504e4d6b4..c66ca62071 100644 --- a/app/tests/components/Dashboard/Dashboard.test.tsx +++ b/app/tests/components/Dashboard/Dashboard.test.tsx @@ -10,21 +10,24 @@ import compiledDashboardTestQuery, { const testQuery = graphql` query DashboardTestQuery($formOwner: ApplicationCondition!) { allApplications(condition: $formOwner) { - nodes { - id - rowId - owner - status - projectName - ccbcNumber - formData { - lastEditedPage - isEditable - } - intakeByIntakeId { - ccbcIntakeNumber - closeTimestamp - openTimestamp + __id + edges { + node { + id + rowId + owner + status + projectName + ccbcNumber + formData { + lastEditedPage + isEditable + } + intakeByIntakeId { + ccbcIntakeNumber + closeTimestamp + openTimestamp + } } } } @@ -35,56 +38,62 @@ const mockQueryPayload = { Query() { return { allApplications: { - nodes: [ + edges: [ { - id: 'WyJhcHBsaWNhdGlvbnMiLDJd', - rowId: 2, - owner: '4e0ac88c-bf05-49ac-948f-7fd53c7a9fd6', - status: 'withdrawn', - projectName: null, - ccbcNumber: 'CCBC-010001', - formData: { - lastEditedPage: '', - isEditable: false, - }, - intakeByIntakeId: { - ccbcIntakeNumber: 1, - closeTimestamp: '2022-09-09T13:49:23.513427-07:00', - openTimestamp: '2022-07-25T00:00:00-07:00', + node: { + id: 'WyJhcHBsaWNhdGlvbnMiLDJd', + rowId: 2, + owner: '4e0ac88c-bf05-49ac-948f-7fd53c7a9fd6', + status: 'withdrawn', + projectName: null, + ccbcNumber: 'CCBC-010001', + formData: { + lastEditedPage: '', + isEditable: false, + }, + intakeByIntakeId: { + ccbcIntakeNumber: 1, + closeTimestamp: '2022-09-09T13:49:23.513427-07:00', + openTimestamp: '2022-07-25T00:00:00-07:00', + }, }, }, { - id: 'WyJhcHBsaWNhdGlvbnMiLDNd', - rowId: 3, - owner: '4e0ac88c-bf05-49ac-948f-7fd53c7a9fd6', - status: 'submitted', - projectName: null, - ccbcNumber: 'CCBC-010002', - formData: { - lastEditedPage: '', - isEditable: true, - }, - intakeByIntakeId: { - ccbcIntakeNumber: 1, - closeTimestamp: '2022-09-09T13:49:23.513427-07:00', - openTimestamp: '2022-07-25T00:00:00-07:00', + node: { + id: 'WyJhcHBsaWNhdGlvbnMiLDNd', + rowId: 3, + owner: '4e0ac88c-bf05-49ac-948f-7fd53c7a9fd6', + status: 'submitted', + projectName: null, + ccbcNumber: 'CCBC-010002', + formData: { + lastEditedPage: '', + isEditable: true, + }, + intakeByIntakeId: { + ccbcIntakeNumber: 1, + closeTimestamp: '2022-09-09T13:49:23.513427-07:00', + openTimestamp: '2022-07-25T00:00:00-07:00', + }, }, }, { - id: 'WyJhcHBsaWNhdGlvbnMiLDRd', - rowId: 4, - owner: '4e0ac88c-bf05-49ac-948f-7fd53c7a9fd6', - status: 'submitted', - projectName: null, - ccbcNumber: 'CCBC-010003', - formData: { - lastEditedPage: '', - isEditable: true, - }, - intakeByIntakeId: { - ccbcIntakeNumber: 1, - closeTimestamp: '2022-09-09T13:49:23.513427-07:00', - openTimestamp: '2022-07-25T00:00:00-07:00', + node: { + id: 'WyJhcHBsaWNhdGlvbnMiLDRd', + rowId: 4, + owner: '4e0ac88c-bf05-49ac-948f-7fd53c7a9fd6', + status: 'submitted', + projectName: null, + ccbcNumber: 'CCBC-010003', + formData: { + lastEditedPage: '', + isEditable: true, + }, + intakeByIntakeId: { + ccbcIntakeNumber: 1, + closeTimestamp: '2022-09-09T13:49:23.513427-07:00', + openTimestamp: '2022-07-25T00:00:00-07:00', + }, }, }, ], @@ -126,19 +135,21 @@ describe('The Dashboard', () => { Query() { return { allApplications: { - nodes: [ + edges: [ { - id: 'WyJhcHBsaWNhdGlvbnMiLDFd', - rowId: 1, - owner: '4e0ac88c-bf05-49ac-948f-7fd53c7a9fd6', - status: 'draft', - projectName: null, - ccbcNumber: null, - formData: { - lastEditedPage: 'templateUploads', - isEditable: true, + node: { + id: 'WyJhcHBsaWNhdGlvbnMiLDFd', + rowId: 1, + owner: '4e0ac88c-bf05-49ac-948f-7fd53c7a9fd6', + status: 'draft', + projectName: null, + ccbcNumber: null, + formData: { + lastEditedPage: 'templateUploads', + isEditable: true, + }, + intakeByIntakeId: null, }, - intakeByIntakeId: null, }, ], }, @@ -158,22 +169,24 @@ describe('The Dashboard', () => { Query() { return { allApplications: { - nodes: [ + edges: [ { - id: 'WyJhcHBsaWNhdGlvbnMiLDJd', - rowId: 2, - owner: '4e0ac88c-bf05-49ac-948f-7fd53c7a9fd6', - status: 'submitted', - projectName: null, - ccbcNumber: 'CCBC-010004', - formData: { - lastEditedPage: '', - isEditable: true, - }, - intakeByIntakeId: { - ccbcIntakeNumber: 1, - closeTimestamp: '2024-09-09T13:49:23.513427-07:00', - openTimestamp: '2022-07-25T00:00:00-07:00', + node: { + id: 'WyJhcHBsaWNhdGlvbnMiLDJd', + rowId: 2, + owner: '4e0ac88c-bf05-49ac-948f-7fd53c7a9fd6', + status: 'submitted', + projectName: null, + ccbcNumber: 'CCBC-010004', + formData: { + lastEditedPage: '', + isEditable: true, + }, + intakeByIntakeId: { + ccbcIntakeNumber: 1, + closeTimestamp: '2024-09-09T13:49:23.513427-07:00', + openTimestamp: '2022-07-25T00:00:00-07:00', + }, }, }, ], @@ -195,22 +208,24 @@ describe('The Dashboard', () => { Query() { return { allApplications: { - nodes: [ + edges: [ { - id: 'WyJhcHBsaWNhdGlvbnMiLDJd', - rowId: 2, - owner: '4e0ac88c-bf05-49ac-948f-7fd53c7a9fd6', - status: 'submitted', - projectName: null, - ccbcNumber: 'CCBC-010005', - formData: { - lastEditedPage: '', - isEditable: true, - }, - intakeByIntakeId: { - ccbcIntakeNumber: 1, - closeTimestamp: '2024-09-09T13:49:23.513427-07:00', - openTimestamp: '2022-07-25T00:00:00-07:00', + node: { + id: 'WyJhcHBsaWNhdGlvbnMiLDJd', + rowId: 2, + owner: '4e0ac88c-bf05-49ac-948f-7fd53c7a9fd6', + status: 'submitted', + projectName: null, + ccbcNumber: 'CCBC-010005', + formData: { + lastEditedPage: '', + isEditable: true, + }, + intakeByIntakeId: { + ccbcIntakeNumber: 1, + closeTimestamp: '2024-09-09T13:49:23.513427-07:00', + openTimestamp: '2022-07-25T00:00:00-07:00', + }, }, }, ], @@ -248,22 +263,24 @@ describe('The Dashboard', () => { Query() { return { allApplications: { - nodes: [ + edges: [ { - id: 'WyJhcHBsaWNhdGlvbnMiLDJd', - rowId: 2, - owner: '4e0ac88c-bf05-49ac-948f-7fd53c7a9fd6', - status: 'submitted', - projectName: null, - ccbcNumber: 'CCBC-010005', - formData: { - lastEditedPage: '', - isEditable: false, - }, - intakeByIntakeId: { - ccbcIntakeNumber: 1, - closeTimestamp: '2021-09-09T13:49:23.513427-07:00', - openTimestamp: '2020-07-25T00:00:00-07:00', + node: { + id: 'WyJhcHBsaWNhdGlvbnMiLDJd', + rowId: 2, + owner: '4e0ac88c-bf05-49ac-948f-7fd53c7a9fd6', + status: 'submitted', + projectName: null, + ccbcNumber: 'CCBC-010005', + formData: { + lastEditedPage: '', + isEditable: false, + }, + intakeByIntakeId: { + ccbcIntakeNumber: 1, + closeTimestamp: '2021-09-09T13:49:23.513427-07:00', + openTimestamp: '2020-07-25T00:00:00-07:00', + }, }, }, ], @@ -284,22 +301,24 @@ describe('The Dashboard', () => { Query() { return { allApplications: { - nodes: [ + edges: [ { - id: 'WyJhcHBsaWNhdGlvbnMiLDJd', - rowId: 2, - owner: '4e0ac88c-bf05-49ac-948f-7fd53c7a9fd6', - status: 'withdrawn', - projectName: null, - ccbcNumber: 'CCBC-010005', - formData: { - lastEditedPage: '', - isEditable: false, - }, - intakeByIntakeId: { - ccbcIntakeNumber: 1, - closeTimestamp: '2024-09-09T13:49:23.513427-07:00', - openTimestamp: '2022-07-25T00:00:00-07:00', + node: { + id: 'WyJhcHBsaWNhdGlvbnMiLDJd', + rowId: 2, + owner: '4e0ac88c-bf05-49ac-948f-7fd53c7a9fd6', + status: 'withdrawn', + projectName: null, + ccbcNumber: 'CCBC-010005', + formData: { + lastEditedPage: '', + isEditable: false, + }, + intakeByIntakeId: { + ccbcIntakeNumber: 1, + closeTimestamp: '2024-09-09T13:49:23.513427-07:00', + openTimestamp: '2022-07-25T00:00:00-07:00', + }, }, }, ], diff --git a/app/tests/pages/applicantportal/dashboard.test.tsx b/app/tests/pages/applicantportal/dashboard.test.tsx index e947b5e7b7..d4b48ca7f6 100644 --- a/app/tests/pages/applicantportal/dashboard.test.tsx +++ b/app/tests/pages/applicantportal/dashboard.test.tsx @@ -51,37 +51,41 @@ const mockQueryPayload = { Query() { return { allApplications: { - nodes: [ + edges: [ { - id: 'WyJhcHBsaWNhdGlvbnMiLDJd', - rowId: 2, - owner: '4e0ac88c-bf05-49ac-948f-7fd53c7a9fd6', - status: 'withdrawn', - projectName: null, - ccbcNumber: 'CCBC-010001', - formData: { - lastEditedPage: '', - isEditable: false, - }, - intakeByIntakeId: { - ccbcIntakeNumber: 1, - closeTimestamp: '2022-09-09T13:49:23.513427-07:00', - openTimestamp: '2022-07-25T00:00:00-07:00', + node: { + id: 'WyJhcHBsaWNhdGlvbnMiLDJd', + rowId: 2, + owner: '4e0ac88c-bf05-49ac-948f-7fd53c7a9fd6', + status: 'withdrawn', + projectName: null, + ccbcNumber: 'CCBC-010001', + formData: { + lastEditedPage: '', + isEditable: false, + }, + intakeByIntakeId: { + ccbcIntakeNumber: 1, + closeTimestamp: '2022-09-09T13:49:23.513427-07:00', + openTimestamp: '2022-07-25T00:00:00-07:00', + }, }, }, { - id: 'WyJhcHBsaWNhdGlvbnMiLDJf', - rowId: 3, - owner: '4e0ac88c-bf05-49ac-948f-7fd53c7a9fd6', - status: 'Received', - projectName: 'test', - ccbcNumber: 'CCBC-020002', - formData: { - lastEditedPage: '', - isEditable: false, - }, - intakeByIntakeId: { - ccbcIntakeNumber: 2, + node: { + id: 'WyJhcHBsaWNhdGlvbnMiLDJf', + rowId: 3, + owner: '4e0ac88c-bf05-49ac-948f-7fd53c7a9fd6', + status: 'Received', + projectName: 'test', + ccbcNumber: 'CCBC-020002', + formData: { + lastEditedPage: '', + isEditable: false, + }, + intakeByIntakeId: { + ccbcIntakeNumber: 2, + }, }, }, ], @@ -100,7 +104,7 @@ const mockQueryPayload = { const mockNoApplicationsPayload = { Query() { return { - allApplications: { nodes: [] }, + allApplications: { edges: [] }, session: { sub: '4e0ac88c-bf05-49ac-948f-7fd53c7a9fd6', }, From 9f917d4f77fca49f1718949a1de1113c796a3915 Mon Sep 17 00:00:00 2001 From: Rafael Solorzano <61289255+rafasdc@users.noreply.github.com> Date: Mon, 31 Jul 2023 09:17:14 -0700 Subject: [PATCH 7/8] chore: style delete link --- app/components/Dashboard/Row.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/components/Dashboard/Row.tsx b/app/components/Dashboard/Row.tsx index 42bc851954..ea24078802 100644 --- a/app/components/Dashboard/Row.tsx +++ b/app/components/Dashboard/Row.tsx @@ -108,7 +108,7 @@ const Row = ({ data-testid="archive-btn-test" type="button" > - Delete + Delete )} {application.hasRfiOpen && ( From b36f500585664e9354264bbf1cb4aa3bf74135cd Mon Sep 17 00:00:00 2001 From: Rafael Solorzano <61289255+rafasdc@users.noreply.github.com> Date: Mon, 31 Jul 2023 09:27:43 -0700 Subject: [PATCH 8/8] test: add delete tests --- .../components/Dashboard/Dashboard.test.tsx | 54 +++++++++++++++++++ .../pages/applicantportal/dashboard.test.tsx | 27 +++++++++- 2 files changed, 80 insertions(+), 1 deletion(-) diff --git a/app/tests/components/Dashboard/Dashboard.test.tsx b/app/tests/components/Dashboard/Dashboard.test.tsx index c66ca62071..43b84a4619 100644 --- a/app/tests/components/Dashboard/Dashboard.test.tsx +++ b/app/tests/components/Dashboard/Dashboard.test.tsx @@ -333,4 +333,58 @@ describe('The Dashboard', () => { expect(screen.getByText('View')).toBeInTheDocument(); expect(screen.queryByTestId('withdraw-btn-test')).toBeNull(); }); + + it('Calls the correct mutation when the delete button is clicked', async () => { + const payload = { + Query() { + return { + allApplications: { + edges: [ + { + node: { + id: 'WyJhcHBsaWNhdGlvbnMiLDJd', + rowId: 2, + owner: '4e0ac88c-bf05-49ac-948f-7fd53c7a9fd6', + status: 'draft', + projectName: null, + ccbcNumber: null, + formData: { + lastEditedPage: '', + isEditable: true, + }, + intakeByIntakeId: { + ccbcIntakeNumber: 1, + closeTimestamp: '2024-09-09T13:49:23.513427-07:00', + openTimestamp: '2022-07-25T00:00:00-07:00', + }, + }, + }, + ], + }, + }; + }, + }; + componentTestingHelper.loadQuery(payload); + const user = userEvent.setup(); + + componentTestingHelper.renderComponent(); + expect(screen.getByText('Draft')).toBeInTheDocument(); + expect(screen.getByText('Delete')).toBeInTheDocument(); + expect(screen.getByTestId('archive-btn-test')).toBeInTheDocument(); + + const archiveBtn = screen.getByTestId('archive-btn-test'); + await user.click(archiveBtn); + + const archiveModalBtn = screen.getByTestId('archive-yes-btn'); + await user.click(archiveModalBtn); + + componentTestingHelper.expectMutationToBeCalled( + 'archiveApplicationMutation', + { + input: { + applicationRowId: 2, + }, + } + ); + }); }); diff --git a/app/tests/pages/applicantportal/dashboard.test.tsx b/app/tests/pages/applicantportal/dashboard.test.tsx index d4b48ca7f6..0b2929b801 100644 --- a/app/tests/pages/applicantportal/dashboard.test.tsx +++ b/app/tests/pages/applicantportal/dashboard.test.tsx @@ -88,6 +88,23 @@ const mockQueryPayload = { }, }, }, + { + node: { + id: 'WyJhcHBsaWNhdGlvbnMiLDJF', + rowId: 4, + owner: '4e0ac88c-bf05-49ac-948f-7fd53c7a9fd6', + status: 'draft', + projectName: 'test', + ccbcNumber: null, + formData: { + lastEditedPage: '', + isEditable: false, + }, + intakeByIntakeId: { + ccbcIntakeNumber: 3, + }, + }, + }, ], }, session: { @@ -236,12 +253,20 @@ describe('The index page', () => { expect(screen.getAllByText(`View`)[0]).toBeInTheDocument(); }); - it('displays the intake numbers for 2 applications', async () => { + it('displays the intake numbers for 3 applications', async () => { pageTestingHelper.loadQuery(); pageTestingHelper.renderPage(); expect(screen.getByText('1')).toBeInTheDocument(); expect(screen.getByText('2')).toBeInTheDocument(); + expect(screen.getByText('3')).toBeInTheDocument(); + }); + + it('should show the delete button for draft applications', async () => { + pageTestingHelper.loadQuery(); + pageTestingHelper.renderPage(); + + expect(screen.getByText('Delete')).toBeInTheDocument(); }); afterEach(() => {
Are you sure you want to delete this draft application?