From 67ebb16c6c0cc632bec090f2e0ecbf44bd8c4f8c Mon Sep 17 00:00:00 2001 From: ibolton336 Date: Fri, 15 Sep 2023 12:33:17 -0400 Subject: [PATCH] Fix missing archetype flow pieces Signed-off-by: ibolton336 Drive isArchetype off of location in case of hard nav Signed-off-by: ibolton336 Remove redundant query Signed-off-by: ibolton336 Modify confirm dialog to include archetype assessment override alert Only show matching assessments for each entity type Update assessment override to use fetchassessment by archetype id approach wire up create assessment on confirm Use hook for isArchetype update test file Update logic for take assessment Wire discard assessment/review back in Fix hook and add override placeholder Signed-off-by: ibolton336 --- client/public/locales/en/translation.json | 8 +- client/src/app/Paths.ts | 3 +- client/src/app/Routes.tsx | 7 +- client/src/app/api/models.ts | 3 +- client/src/app/components/ConfirmDialog.tsx | 35 ++++- .../questionnaire-summary.tsx | 23 ++-- client/src/app/hooks/useIsArchetype.ts | 5 + .../applications-table-assessment.tsx | 9 ++ .../application-assessment-status.tsx | 2 +- .../questionnaire-upload-test-file.yml | 11 +- .../app/pages/assessment/assessment-page.tsx | 1 + .../assessment-actions-page.tsx | 13 +- .../dynamic-assessment-actions-row.tsx | 120 ++++++++++++++++-- .../components/questionnaires-table.tsx | 19 ++- .../components/assessment-page-header.tsx | 36 +++--- .../assessment-wizard/assessment-wizard.tsx | 91 +++++++------ .../custom-wizard-footer.tsx | 20 +-- client/src/app/queries/applications.ts | 7 +- client/src/app/queries/assessments.ts | 6 +- client/src/app/queries/reviews.ts | 4 +- 20 files changed, 304 insertions(+), 119 deletions(-) create mode 100644 client/src/app/hooks/useIsArchetype.ts diff --git a/client/public/locales/en/translation.json b/client/public/locales/en/translation.json index 73e78cd41e..f170b96306 100644 --- a/client/public/locales/en/translation.json +++ b/client/public/locales/en/translation.json @@ -42,6 +42,7 @@ "manageDependencies": "Manage dependencies", "manageImports": "Manage imports", "next": "Next", + "override": "Override", "review": "Review", "save": "Save", "saveAndReview": "Save and review", @@ -51,7 +52,8 @@ "selectPage": "Select page", "submitReview": "Submit review", "view": "View", - "viewErrorReport": "View error report" + "viewErrorReport": "View error report", + "viewArchetypes": "View archetypes" }, "colors": { "black": "Black", @@ -168,8 +170,8 @@ "noDataAvailableTitle": "No data available", "noResultsFoundBody": "No results match the filter criteria. Remove all filters or clear all filters to show results.", "noResultsFoundTitle": "No results found", - "overrideAssessmentConfirmation": "This application has already been assessed. Do you want to continue?", - "overrideArchetypeConfirmation": "The archetype for this application already has an assessment. Do you want to create a dedicated assessment for this application?", + "overrideAssessmentDescription": "The archetype for {{what}} already has an assessment.", + "overrideAssessmentConfirmation": "Do you want to create a dedicated assessment for this application?", "overrideReviewConfirmation": "This application has already been reviewed. Do you want to continue?", "reasonForError": "The reported reason for the error:", "reviewInstructions": "Use this section to provide your assessment of the possible migration/modernization plan and effort estimation.", diff --git a/client/src/app/Paths.ts b/client/src/app/Paths.ts index 01875abfb4..d293facac0 100644 --- a/client/src/app/Paths.ts +++ b/client/src/app/Paths.ts @@ -12,7 +12,8 @@ export enum Paths { applicationsAssessment = "/applications/assessment/:assessmentId", applicationAssessmentActions = "/applications/assessment-actions/:applicationId", archetypeAssessmentActions = "/archetypes/assessment-actions/:archetypeId", - assessmentSummary = "/applications/assessment-summary/:assessmentId", + applicationAssessmentSummary = "/applications/assessment-summary/:assessmentId", + archetypeAssessmentSummary = "/archetypes/assessment-summary/:assessmentId", applicationsReview = "/applications/:applicationId/review", applicationsAnalysis = "/applications/analysis", archetypes = "/archetypes", diff --git a/client/src/app/Routes.tsx b/client/src/app/Routes.tsx index e98bcb483a..25a700720c 100644 --- a/client/src/app/Routes.tsx +++ b/client/src/app/Routes.tsx @@ -102,7 +102,12 @@ export const devRoutes: IRoute[] = [ exact: false, }, { - path: Paths.assessmentSummary, + path: Paths.applicationAssessmentSummary, + comp: AssessmentSummary, + exact: false, + }, + { + path: Paths.archetypeAssessmentSummary, comp: AssessmentSummary, exact: false, }, diff --git a/client/src/app/api/models.ts b/client/src/app/api/models.ts index b9524cc588..78983090a6 100644 --- a/client/src/app/api/models.ts +++ b/client/src/app/api/models.ts @@ -128,6 +128,7 @@ export interface Application { migrationWave: Ref | null; assessments?: Ref[]; assessed?: boolean; + archetypes?: Ref[]; } export interface Review { @@ -749,6 +750,6 @@ export interface Archetype { assessmentTags?: Tag[]; stakeholders?: Ref[]; stakeholderGroups?: Ref[]; - applications?: Application[]; + applications?: Ref[]; assessments?: Ref[]; } diff --git a/client/src/app/components/ConfirmDialog.tsx b/client/src/app/components/ConfirmDialog.tsx index f42e046c44..2dfedcd1b0 100644 --- a/client/src/app/components/ConfirmDialog.tsx +++ b/client/src/app/components/ConfirmDialog.tsx @@ -4,6 +4,7 @@ import { Modal, ButtonVariant, ModalVariant, + Alert, } from "@patternfly/react-core"; export interface ConfirmDialogProps { @@ -20,13 +21,17 @@ export interface ConfirmDialogProps { confirmBtnLabel: string; cancelBtnLabel: string; + customActionLabel?: string; inProgress?: boolean; confirmBtnVariant: ButtonVariant; + alertMessage?: string; + onClose: () => void; onConfirm: () => void; onCancel?: () => void; + onCustomAction?: () => void; } export const ConfirmDialog: React.FC = ({ @@ -36,11 +41,14 @@ export const ConfirmDialog: React.FC = ({ message, confirmBtnLabel, cancelBtnLabel, + customActionLabel, inProgress, confirmBtnVariant, onClose, onConfirm, onCancel, + onCustomAction, + alertMessage, }) => { const confirmBtn = ( ) : undefined; + const customActionBtn = onCustomAction ? ( + + ) : undefined; + + const actions = [confirmBtn]; + + if (cancelBtn) { + actions.push(cancelBtn); + } + + if (customActionBtn) { + actions.splice(1, 0, customActionBtn); + } return ( = ({ isOpen={isOpen} onClose={onClose} aria-label="Confirm dialog" - actions={onCancel ? [confirmBtn, cancelBtn] : [confirmBtn]} + actions={actions} > + {alertMessage ? ( + + ) : null} {message} ); diff --git a/client/src/app/components/questionnaire-summary/questionnaire-summary.tsx b/client/src/app/components/questionnaire-summary/questionnaire-summary.tsx index 186687f97f..aea4bf63dc 100644 --- a/client/src/app/components/questionnaire-summary/questionnaire-summary.tsx +++ b/client/src/app/components/questionnaire-summary/questionnaire-summary.tsx @@ -16,7 +16,6 @@ import { } from "@patternfly/react-core"; import AngleLeftIcon from "@patternfly/react-icons/dist/esm/icons/angle-left-icon"; import { Link } from "react-router-dom"; -import { useTranslation } from "react-i18next"; import { Paths } from "@app/Paths"; import { ConditionalRender } from "@app/components/ConditionalRender"; import { AppPlaceholder } from "@app/components/AppPlaceholder"; @@ -25,6 +24,7 @@ import { Assessment, Questionnaire } from "@app/api/models"; import QuestionnaireSectionTabTitle from "./components/questionnaire-section-tab-title"; import { AxiosError } from "axios"; import { formatPath } from "@app/utils/utils"; +import useIsArchetype from "@app/hooks/useIsArchetype"; export enum SummaryType { Assessment = "Assessment", @@ -36,7 +36,6 @@ interface QuestionnaireSummaryProps { fetchError?: AxiosError | null; summaryData: Assessment | Questionnaire | undefined; summaryType: SummaryType; - isArchetype?: boolean; } const QuestionnaireSummary: React.FC = ({ @@ -44,9 +43,8 @@ const QuestionnaireSummary: React.FC = ({ summaryType, isFetching = false, fetchError = null, - isArchetype, }) => { - const { t } = useTranslation(); + const isArchetype = useIsArchetype(); const [activeSectionIndex, setActiveSectionIndex] = useState<"all" | number>( "all" @@ -86,17 +84,20 @@ const QuestionnaireSummary: React.FC = ({ if (!summaryData) { return
No data available.
; } + + const dynamicPath = isArchetype + ? formatPath(Paths.archetypeAssessmentActions, { + archetypeId: (summaryData as Assessment)?.archetype?.id, + }) + : formatPath(Paths.applicationAssessmentActions, { + applicationId: (summaryData as Assessment)?.application?.id, + }); + const BreadcrumbPath = summaryType === SummaryType.Assessment ? ( - - Assessment - + Assessment {summaryData?.name} diff --git a/client/src/app/hooks/useIsArchetype.ts b/client/src/app/hooks/useIsArchetype.ts new file mode 100644 index 0000000000..f735e4a96e --- /dev/null +++ b/client/src/app/hooks/useIsArchetype.ts @@ -0,0 +1,5 @@ +import { useLocation } from "react-router-dom"; + +const useIsArchetype = () => useLocation().pathname.includes("/archetypes/"); + +export default useIsArchetype; diff --git a/client/src/app/pages/applications/applications-table-assessment/applications-table-assessment.tsx b/client/src/app/pages/applications/applications-table-assessment/applications-table-assessment.tsx index ea74048810..09c3dedb33 100644 --- a/client/src/app/pages/applications/applications-table-assessment/applications-table-assessment.tsx +++ b/client/src/app/pages/applications/applications-table-assessment/applications-table-assessment.tsx @@ -669,6 +669,15 @@ export const ApplicationsTable: React.FC = () => { title: t("actions.review"), onClick: () => reviewSelectedApp(application), }, + ...(application?.review + ? [ + { + title: t("actions.discardAssessment"), + onClick: () => + setAssessmentOrReviewToDiscard(application), + }, + ] + : []), { title: t("actions.delete"), onClick: () => diff --git a/client/src/app/pages/applications/components/application-assessment-status/application-assessment-status.tsx b/client/src/app/pages/applications/components/application-assessment-status/application-assessment-status.tsx index 0bc7b28536..b510c997a6 100644 --- a/client/src/app/pages/applications/components/application-assessment-status/application-assessment-status.tsx +++ b/client/src/app/pages/applications/components/application-assessment-status/application-assessment-status.tsx @@ -32,7 +32,7 @@ export const ApplicationAssessmentStatus: React.FC< > = ({ assessments, isLoading = false, fetchError = null }) => { const { t } = useTranslation(); //TODO: remove this once we have a proper assessment status - const { assessment } = useFetchAssessmentById(assessments?.[0]?.id || 0); + const { assessment } = useFetchAssessmentById(assessments?.[0]?.id); if (fetchError) { return ; diff --git a/client/src/app/pages/assessment-management/import-questionnaire-form/questionnaire-upload-test-file.yml b/client/src/app/pages/assessment-management/import-questionnaire-form/questionnaire-upload-test-file.yml index a6d56e66a7..a18ddbc0ba 100644 --- a/client/src/app/pages/assessment-management/import-questionnaire-form/questionnaire-upload-test-file.yml +++ b/client/src/app/pages/assessment-management/import-questionnaire-form/questionnaire-upload-test-file.yml @@ -1,6 +1,5 @@ name: Test questionnaire description: This is a sample questionnaire in YAML format -revision: 1 required: true sections: - order: 1 @@ -22,7 +21,6 @@ sections: applyTags: [] autoAnswerFor: [{ category: Category1, tag: Tag1 }] selected: false - autoAnswered: false - order: 2 text: Blue risk: green @@ -31,14 +29,12 @@ sections: applyTags: [] autoAnswerFor: [] selected: false - autoAnswered: false - order: 2 text: What is your favorite sport? explanation: Please select your favorite sport. - includeFor: + excludeFor: - category: Category1 tag: Tag1 - excludeFor: [] answers: - order: 1 text: Soccer @@ -48,7 +44,6 @@ sections: applyTags: [] autoAnswerFor: [] selected: false - autoAnswered: false - order: 2 text: Cycling risk: red @@ -57,7 +52,6 @@ sections: applyTags: [] autoAnswerFor: [] selected: false - autoAnswered: false - order: 3 text: Climbing risk: yellow @@ -66,7 +60,6 @@ sections: applyTags: [] autoAnswerFor: [] selected: false - autoAnswered: false - order: 4 text: Swimming risk: yellow @@ -75,7 +68,6 @@ sections: applyTags: [] autoAnswerFor: [] selected: false - autoAnswered: false - order: 5 text: Running risk: red @@ -84,7 +76,6 @@ sections: applyTags: [] autoAnswerFor: [] selected: false - autoAnswered: false thresholds: red: 5 yellow: 10 diff --git a/client/src/app/pages/assessment/assessment-page.tsx b/client/src/app/pages/assessment/assessment-page.tsx index 406e59e10c..cbfb5652ae 100644 --- a/client/src/app/pages/assessment/assessment-page.tsx +++ b/client/src/app/pages/assessment/assessment-page.tsx @@ -23,6 +23,7 @@ const AssessmentPage: React.FC = () => { const { t } = useTranslation(); const { assessmentId } = useParams(); + const { assessment, isFetching, fetchError } = useFetchAssessmentById(assessmentId); diff --git a/client/src/app/pages/assessment/components/assessment-actions/assessment-actions-page.tsx b/client/src/app/pages/assessment/components/assessment-actions/assessment-actions-page.tsx index bc9fe22bbe..bcb97d9ab3 100644 --- a/client/src/app/pages/assessment/components/assessment-actions/assessment-actions-page.tsx +++ b/client/src/app/pages/assessment/components/assessment-actions/assessment-actions-page.tsx @@ -11,19 +11,18 @@ import { Link, useParams } from "react-router-dom"; import { AssessmentActionsRoute, Paths } from "@app/Paths"; import { ConditionalRender } from "@app/components/ConditionalRender"; import { AppPlaceholder } from "@app/components/AppPlaceholder"; -import { useFetchApplicationByID } from "@app/queries/applications"; import AssessmentActionsTable from "./components/assessment-actions-table"; import { useFetchArchetypeById } from "@app/queries/archetypes"; +import { useFetchApplicationById } from "@app/queries/applications"; +import useIsArchetype from "@app/hooks/useIsArchetype"; const AssessmentActions: React.FC = () => { const { applicationId, archetypeId } = useParams(); - const isArchetype = location.pathname.includes("/archetypes/"); - console.log("isArchetype", isArchetype); + const isArchetype = useIsArchetype(); - const { application } = useFetchApplicationByID(applicationId || ""); - const { archetype } = useFetchArchetypeById(archetypeId || ""); + const { archetype } = useFetchArchetypeById(archetypeId); + const { application } = useFetchApplicationById(applicationId); - console.log("archetype", archetype); return ( <> @@ -41,7 +40,7 @@ const AssessmentActions: React.FC = () => { )} - Assessment + {isArchetype ? archetype?.name : application?.name} diff --git a/client/src/app/pages/assessment/components/assessment-actions/components/dynamic-assessment-actions-row.tsx b/client/src/app/pages/assessment/components/assessment-actions/components/dynamic-assessment-actions-row.tsx index c444501d3d..c8507b6f94 100644 --- a/client/src/app/pages/assessment/components/assessment-actions/components/dynamic-assessment-actions-row.tsx +++ b/client/src/app/pages/assessment/components/assessment-actions/components/dynamic-assessment-actions-row.tsx @@ -5,13 +5,14 @@ import { Assessment, InitialAssessment, Questionnaire, + Ref, } from "@app/api/models"; import { assessmentsByItemIdQueryKey, useCreateAssessmentMutation, useDeleteAssessmentMutation, } from "@app/queries/assessments"; -import { Button } from "@patternfly/react-core"; +import { Button, ButtonVariant } from "@patternfly/react-core"; import React, { FunctionComponent } from "react"; import { useHistory } from "react-router-dom"; import "./dynamic-assessment-actions-row.css"; @@ -22,6 +23,9 @@ import { NotificationsContext } from "@app/components/NotificationsContext"; import { useTranslation } from "react-i18next"; import { useQueryClient } from "@tanstack/react-query"; import { TrashIcon } from "@patternfly/react-icons"; +import { ConfirmDialog } from "@app/components/ConfirmDialog"; +import { getAssessmentsByItemId } from "@app/api/rest"; +import useIsArchetype from "@app/hooks/useIsArchetype"; enum AssessmentAction { Take = "Take", @@ -31,7 +35,6 @@ enum AssessmentAction { interface DynamicAssessmentActionsRowProps { questionnaire: Questionnaire; - isArchetype: boolean; application?: Application; archetype?: Archetype; assessment?: Assessment; @@ -39,13 +42,17 @@ interface DynamicAssessmentActionsRowProps { const DynamicAssessmentActionsRow: FunctionComponent< DynamicAssessmentActionsRowProps -> = ({ questionnaire, application, archetype, assessment, isArchetype }) => { +> = ({ questionnaire, application, archetype, assessment }) => { + const isArchetype = useIsArchetype(); const history = useHistory(); const { t } = useTranslation(); const queryClient = useQueryClient(); const { pushNotification } = React.useContext(NotificationsContext); + const [archetypeRefToOverride, setArchetypeRefToOverride] = + React.useState(null); + const onSuccessHandler = () => {}; const onErrorHandler = () => {}; @@ -100,6 +107,7 @@ const DynamicAssessmentActionsRow: FunctionComponent< return "retake-button"; } }; + const createAssessment = async () => { const newAssessment: InitialAssessment = { questionnaire: { name: questionnaire.name, id: questionnaire.id }, @@ -129,18 +137,59 @@ const DynamicAssessmentActionsRow: FunctionComponent< } } catch (error) { console.error("Error while creating assessment:", error); + pushNotification({ + title: t("terms.error"), + variant: "danger", + }); } }; + + const takeAssessment = async () => { + if (!isArchetype && application?.archetypes?.length) { + for (const archetypeRef of application.archetypes) { + try { + const assessments = await getAssessmentsByItemId( + true, + archetypeRef.id + ); + + if (assessments && assessments.length > 0) { + setArchetypeRefToOverride(archetypeRef); + return; + } else { + createAssessment(); + } + } catch (error) { + console.error( + `Error fetching archetype with ID ${archetypeRef.id}:`, + error + ); + pushNotification({ + title: t("terms.error"), + variant: "danger", + }); + } + } + } else { + createAssessment(); + } + }; + const onHandleAssessmentAction = async () => { const action = determineAction(); if (action === AssessmentAction.Take) { - createAssessment(); + takeAssessment(); } else if (action === AssessmentAction.Continue) { history.push( - formatPath(Paths.applicationsAssessment, { - assessmentId: assessment?.id, - }) + formatPath( + isArchetype + ? Paths.archetypesAssessment + : Paths.applicationsAssessment, + { + assessmentId: assessment?.id, + } + ) ); } else if (action === AssessmentAction.Retake) { if (assessment) { @@ -152,11 +201,20 @@ const DynamicAssessmentActionsRow: FunctionComponent< createAssessment(); }); history.push( - formatPath(Paths.applicationsAssessment, { - assessmentId: assessment?.id, - }) + formatPath( + isArchetype + ? Paths.archetypesAssessment + : Paths.applicationsAssessment, + { + assessmentId: assessment?.id, + } + ) ); } catch (error) { + pushNotification({ + title: t("terms.error"), + variant: "danger", + }); console.error("Error while deleting assessment:", error); } } @@ -185,9 +243,14 @@ const DynamicAssessmentActionsRow: FunctionComponent< variant="secondary" onClick={() => { history.push( - formatPath(Paths.assessmentSummary, { - assessmentId: assessment.id, - }) + formatPath( + isArchetype + ? Paths.archetypeAssessmentSummary + : Paths.applicationAssessmentSummary, + { + assessmentId: assessment.id, + } + ) ); }} > @@ -212,6 +275,37 @@ const DynamicAssessmentActionsRow: FunctionComponent< ) : null} + setArchetypeRefToOverride(null)} + onClose={() => setArchetypeRefToOverride(null)} + //TODO + // onCustomAction={() => { + // //nav to view archetypes + // console.log("nav to view archetypes"); + // }} + onConfirm={() => { + history.push( + formatPath(Paths.applicationsAssessment, { + assessmentId: archetypeRefToOverride?.id, + }) + ); + setArchetypeRefToOverride(null); + createAssessment(); + }} + /> ); }; diff --git a/client/src/app/pages/assessment/components/assessment-actions/components/questionnaires-table.tsx b/client/src/app/pages/assessment/components/assessment-actions/components/questionnaires-table.tsx index 9eaaa5f221..77acd47bd3 100644 --- a/client/src/app/pages/assessment/components/assessment-actions/components/questionnaires-table.tsx +++ b/client/src/app/pages/assessment/components/assessment-actions/components/questionnaires-table.tsx @@ -74,8 +74,16 @@ const QuestionnairesTable: React.FC = ({ > {currentPageItems?.map((questionnaire, rowIndex) => { - const matchingAssessment = assessments?.find( - (assessment) => assessment.questionnaire.id === questionnaire.id + const matchingArchetypeAssessment = assessments?.find( + (assessment) => + assessment.questionnaire.id === questionnaire.id && + assessment?.archetype?.id === archetype?.id + ); + + const matchingApplicationAssessment = assessments?.find( + (assessment) => + assessment.questionnaire.id === questionnaire.id && + assessment?.application?.id === application?.id ); return ( @@ -93,9 +101,12 @@ const QuestionnairesTable: React.FC = ({ {application || archetype ? ( diff --git a/client/src/app/pages/assessment/components/assessment-page-header.tsx b/client/src/app/pages/assessment/components/assessment-page-header.tsx index c587b96679..6644d0e3f8 100644 --- a/client/src/app/pages/assessment/components/assessment-page-header.tsx +++ b/client/src/app/pages/assessment/components/assessment-page-header.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from "react"; +import React from "react"; import { useHistory } from "react-router-dom"; import { useTranslation } from "react-i18next"; import { Button, ButtonVariant, Modal, Text } from "@patternfly/react-core"; @@ -8,7 +8,9 @@ import { PageHeader } from "@app/components/PageHeader"; import { ApplicationDependenciesFormContainer } from "@app/components/ApplicationDependenciesFormContainer"; import { Paths } from "@app/Paths"; import { Application, Assessment } from "@app/api/models"; -import { getApplicationById } from "@app/api/rest"; +import { useFetchApplicationById } from "@app/queries/applications"; +import { useFetchArchetypeById } from "@app/queries/archetypes"; +import useIsArchetype from "@app/hooks/useIsArchetype"; export interface AssessmentPageHeaderProps { assessment?: Assessment; @@ -19,20 +21,14 @@ export const AssessmentPageHeader: React.FC = ({ }) => { const { t } = useTranslation(); const history = useHistory(); + const isArchetype = useIsArchetype(); + + const { archetype } = useFetchArchetypeById(assessment?.archetype?.id); + const { application } = useFetchApplicationById(assessment?.application?.id); const [isConfirmDialogOpen, setIsConfirmDialogOpen] = React.useState(false); - const [application, setApplication] = useState(); - - useEffect(() => { - if (assessment?.application?.id) { - getApplicationById(assessment?.application?.id).then((data) => { - setApplication(data); - }); - } - }, [assessment]); - const [applicationDependenciesToManage, setApplicationDependenciesToManage] = React.useState(null); @@ -40,17 +36,23 @@ export const AssessmentPageHeader: React.FC = ({ <> {application?.name}} + description={ + + {isArchetype ? archetype?.name : application?.name} + + } breadcrumbs={[ { - title: t("terms.applications"), + title: isArchetype ? t("terms.archetype") : t("terms.applications"), path: () => { setIsConfirmDialogOpen(true); }, }, { title: t("terms.assessment"), - path: Paths.applicationsAssessment, + path: isArchetype + ? Paths.archetypesAssessment + : Paths.applicationsAssessment, }, ]} btnActions={ @@ -92,7 +94,9 @@ export const AssessmentPageHeader: React.FC = ({ cancelBtnLabel={t("actions.cancel")} onCancel={() => setIsConfirmDialogOpen(false)} onClose={() => setIsConfirmDialogOpen(false)} - onConfirm={() => history.push(Paths.applications)} + onConfirm={() => + history.push(isArchetype ? Paths.archetypes : Paths.applications) + } /> )} diff --git a/client/src/app/pages/assessment/components/assessment-wizard/assessment-wizard.tsx b/client/src/app/pages/assessment/components/assessment-wizard/assessment-wizard.tsx index b7353d8e56..2c9c2a8589 100644 --- a/client/src/app/pages/assessment/components/assessment-wizard/assessment-wizard.tsx +++ b/client/src/app/pages/assessment/components/assessment-wizard/assessment-wizard.tsx @@ -18,7 +18,6 @@ import { NotificationsContext } from "@app/components/NotificationsContext"; import { WizardStepNavDescription } from "../wizard-step-nav-description"; import { QuestionnaireForm } from "../questionnaire-form"; import { ConfirmDialog } from "@app/components/ConfirmDialog"; -import { useFetchQuestionnaires } from "@app/queries/questionnaires"; import { COMMENTS_KEY, QUESTIONS_KEY, @@ -34,6 +33,7 @@ import { formatPath, getAxiosErrorMessage } from "@app/utils/utils"; import { Paths } from "@app/Paths"; import { yupResolver } from "@hookform/resolvers/yup"; import { AssessmentStakeholdersForm } from "../assessment-stakeholders-form/assessment-stakeholders-form"; +import useIsArchetype from "@app/hooks/useIsArchetype"; export const SAVE_ACTION_KEY = "saveAction"; @@ -58,16 +58,15 @@ export interface AssessmentWizardValues { export interface AssessmentWizardProps { assessment?: Assessment; isOpen: boolean; - isArchetype?: boolean; } export const AssessmentWizard: React.FC = ({ assessment, isOpen, - isArchetype, }) => { + const isArchetype = useIsArchetype(); const queryClient = useQueryClient(); - const { questionnaires } = useFetchQuestionnaires(); + const onHandleUpdateAssessmentSuccess = () => { queryClient.invalidateQueries([ assessmentsByItemIdQueryKey, @@ -78,10 +77,6 @@ export const AssessmentWizard: React.FC = ({ onHandleUpdateAssessmentSuccess ); - const matchingQuestionnaire = questionnaires.find( - (questionnaire) => questionnaire.id === assessment?.questionnaire?.id - ); - const { t } = useTranslation(); const [currentStep, setCurrentStep] = useState(0); @@ -94,10 +89,10 @@ export const AssessmentWizard: React.FC = ({ const { pushNotification } = React.useContext(NotificationsContext); const sortedSections = useMemo(() => { - return (matchingQuestionnaire ? matchingQuestionnaire.sections : []).sort( + return (assessment ? assessment.sections : []).sort( (a, b) => a.order - b.order ); - }, [matchingQuestionnaire]); + }, [assessment]); //TODO: Add comments to the sections when/if available from api // const initialComments = useMemo(() => { @@ -112,8 +107,8 @@ export const AssessmentWizard: React.FC = ({ const initialQuestions = useMemo(() => { const questions: { [key: string]: string | undefined } = {}; - if (assessment && matchingQuestionnaire) { - matchingQuestionnaire.sections + if (assessment) { + assessment.sections .flatMap((f) => f.questions) .forEach((question) => { const existingAnswer = assessment.sections @@ -126,17 +121,21 @@ export const AssessmentWizard: React.FC = ({ }); } return questions; - }, [assessment, matchingQuestionnaire]); + }, [assessment]); useEffect(() => { methods.reset({ - // stakeholders: assessment?.stakeholders || [], - // stakeholderGroups: assessment?.stakeholderGroups || [], + stakeholders: + assessment?.stakeholders.map((stakeholder) => stakeholder.name) || [], + stakeholderGroups: + assessment?.stakeholderGroups.map( + (stakeholderGroup) => stakeholderGroup.name + ) || [], // comments: initialComments, questions: initialQuestions, [SAVE_ACTION_KEY]: SAVE_ACTION_VALUE.SAVE_AS_DRAFT, }); - }, [initialQuestions]); + }, [initialQuestions, assessment]); const validationSchema = yup.object().shape({ stakeholders: yup.array().of(yup.string()), @@ -235,7 +234,7 @@ export const AssessmentWizard: React.FC = ({ // Create an array of sections based on the questionsData const sections: Section[] = - matchingQuestionnaire?.sections?.map((section) => { + assessment?.sections?.map((section) => { //TODO: Add comments to the sections // const commentValues = values["comments"]; // const fieldName = getCommentFieldName(category, false); @@ -263,7 +262,7 @@ export const AssessmentWizard: React.FC = ({ const handleSaveAsDraft = async (formValues: AssessmentWizardValues) => { try { - if (!assessment?.application?.id) { + if (!assessment?.application?.id && !assessment?.archetype?.id) { console.log("An assessment must exist in order to save as draft"); return; } @@ -307,7 +306,7 @@ export const AssessmentWizard: React.FC = ({ const handleSave = async (formValues: AssessmentWizardValues) => { try { - if (!assessment?.application?.id) { + if (!assessment?.application?.id && !assessment?.archetype?.id) { console.log("An assessment must exist in order to save."); return; } @@ -352,7 +351,7 @@ export const AssessmentWizard: React.FC = ({ const handleSaveAndReview = async (formValues: AssessmentWizardValues) => { try { - if (!assessment?.application?.id) { + if (!assessment?.application?.id && !assessment?.archetype?.id) { console.log("An assessment must exist in order to save."); return; } @@ -375,22 +374,41 @@ export const AssessmentWizard: React.FC = ({ title: "Assessment has been saved.", variant: "success", }); - - assessment?.application?.id && - getApplicationById(assessment.application.id) - .then((data) => { - history.push( - formatPath(Paths.applicationsReview, { - applicationId: data.id, - }) - ); - }) - .catch((error) => { - pushNotification({ - title: getAxiosErrorMessage(error), - variant: "danger", + if (isArchetype) { + //TODO: Review Archetype? + // assessment?.archetype?.id && + // getArchetypeById(assessment.archetype.id) + // .then((data) => { + // history.push( + // formatPath(Paths.a, { + // applicationId: data.id, + // }) + // ); + // }) + // .catch((error) => { + // pushNotification({ + // title: getAxiosErrorMessage(error), + // variant: "danger", + // }); + // }); + // } + } else { + assessment?.application?.id && + getApplicationById(assessment.application.id) + .then((data) => { + history.push( + formatPath(Paths.applicationsReview, { + applicationId: data.id, + }) + ); + }) + .catch((error) => { + pushNotification({ + title: getAxiosErrorMessage(error), + variant: "danger", + }); }); - }); + } } catch (error) { pushNotification({ title: "Failed to save.", @@ -401,7 +419,7 @@ export const AssessmentWizard: React.FC = ({ }; const onSubmit = async (formValues: AssessmentWizardValues) => { - if (!assessment?.application?.id) { + if (!assessment?.application?.id && !assessment?.archetype?.id) { console.log("An assessment must exist in order to save the form"); return; } @@ -453,6 +471,7 @@ export const AssessmentWizard: React.FC = ({ const wizardFooter = ( void; onSaveAsDraft: () => void; } @@ -21,6 +22,7 @@ export const CustomWizardFooter: React.FC = ({ isLastStep, isDisabled, isFormInvalid, + isArchetype, onSave, onSaveAsDraft, }) => { @@ -47,14 +49,16 @@ export const CustomWizardFooter: React.FC = ({ > {t("actions.save")} - + {!isArchetype && ( + + )} ) : (