Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: adjust seedlot details page #1527

Merged
merged 10 commits into from
Aug 26, 2024
19 changes: 9 additions & 10 deletions frontend/src/contexts/AuthProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { env } from '../env';
import FamUser from '../types/FamUser';
import LoginProviders from '../types/LoginProviders';
import AuthContext, { AuthContextData } from './AuthContext';
import { SPAR_REDIRECT_PATH, TSC_ADMIN_ROLE } from '../shared-constants/shared-constants';
import { MINISTRY_OF_FOREST_ID, SPAR_REDIRECT_PATH, TSC_ADMIN_ROLE } from '../shared-constants/shared-constants';
import { TWO_MINUTE } from '../config/TimeUnits';
import ROUTES from '../routes/constants';

Expand Down Expand Up @@ -42,7 +42,6 @@ const findFindAndLastName = (displayName: string, provider: string): Array<strin

const parseRole = (accessToken: { [id: string]: any }): UserClientRolesType[] => {
const separator = '_';
const minitryOfForestId = '00012797';

const cognitoGroups: string[] = accessToken['cognito:groups'];
if (!cognitoGroups) {
Expand All @@ -51,19 +50,19 @@ const parseRole = (accessToken: { [id: string]: any }): UserClientRolesType[] =>

const parsedClientRoles: UserClientRolesType[] = [];

cognitoGroups.forEach((cognaitoRole) => {
if (!cognaitoRole.includes(separator)) {
throw new Error(`Invalid role format with string: ${cognaitoRole}`);
cognitoGroups.forEach((cognitoRole) => {
if (!cognitoRole.includes(separator)) {
throw new Error(`Invalid role format with string: ${cognitoRole}`);
}
const lastUnderscoreIndex = cognaitoRole.lastIndexOf(separator);
let role = cognaitoRole.substring(0, lastUnderscoreIndex);
let clientId = cognaitoRole.substring(lastUnderscoreIndex + 1);
const lastUnderscoreIndex = cognitoRole.lastIndexOf(separator);
let role = cognitoRole.substring(0, lastUnderscoreIndex);
let clientId = cognitoRole.substring(lastUnderscoreIndex + 1);

// If the last substring after an underscore is not a number then it's a concrete role,
// we need to manually assign it a MoF client id for now.
if (Number.isNaN(Number(clientId))) {
clientId = minitryOfForestId;
role = cognaitoRole;
clientId = MINISTRY_OF_FOREST_ID;
role = cognitoRole;
}

// Check if a client id already exist in parsed client role
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/shared-constants/shared-constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,5 @@ export const LARGE_SCREEN_WIDTH = 1056;
export const TSC_ADMIN_ROLE = 'SPAR_TSC_ADMIN';

export const PLACE_HOLDER = '--';

export const MINISTRY_OF_FOREST_ID = '00012797';
mgaseta marked this conversation as resolved.
Show resolved Hide resolved
22 changes: 22 additions & 0 deletions frontend/src/utils/BreadcrumbUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import ROUTES from '../routes/constants';
import { addParamToPath } from './PathUtils';
import { MINISTRY_OF_FOREST_ID } from '../shared-constants/shared-constants';

export const getSeedlotBreadcrumbs = (
seedlotNumber: string,
seedlotApplicant: string,
isTscAdmin: boolean
) => {
const crumbsList = [];
crumbsList.push({ name: 'Seedlots', path: ROUTES.SEEDLOTS });
if (isTscAdmin && seedlotApplicant !== MINISTRY_OF_FOREST_ID) {
crumbsList.push({ name: 'Review Seedlots', path: ROUTES.TSC_SEEDLOTS_TABLE });
} else {
crumbsList.push({ name: 'My seedlots', path: ROUTES.MY_SEEDLOTS });
}
crumbsList.push({
name: `Seedlot ${seedlotNumber}`,
path: `${addParamToPath(ROUTES.SEEDLOT_DETAILS, seedlotNumber)}`
});
return crumbsList;
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';

import { EmptyMultiOptObj } from '../../../shared-constants/shared-constants';
import { EmptyMultiOptObj, MINISTRY_OF_FOREST_ID } from '../../../shared-constants/shared-constants';
import MultiOptionsObj from '../../../types/MultiOptionsObject';
import {
CollectionFormSubmitType, ExtractionFormSubmitType, InterimFormSubmitType, OrchardFormSubmitType,
Expand Down Expand Up @@ -87,8 +87,8 @@ export const stepMap: StepMap = {
};

export const tscAgencyObj: MultiOptionsObj = {
code: '00012797',
label: '00012797 - Tree Seed Centre - MOF',
code: MINISTRY_OF_FOREST_ID,
label: `${MINISTRY_OF_FOREST_ID} - Tree Seed Centre - MOF`,
description: 'Tree Seed Centre'
};

Expand Down
28 changes: 17 additions & 11 deletions frontend/src/views/Seedlot/EditAClassApplication/Form.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect } from 'react';
import React, { useContext, useEffect } from 'react';
import {
ActionableNotification,
FlexGrid,
Expand All @@ -13,26 +13,26 @@ import { AxiosError } from 'axios';
import { toast } from 'react-toastify';
import { useNavigate, useParams } from 'react-router-dom';

import AuthContext from '../../../contexts/AuthContext';
import { getSeedlotById, patchSeedlotApplicationInfo } from '../../../api-service/seedlotAPI';
import { THREE_HALF_HOURS, THREE_HOURS } from '../../../config/TimeUnits';
import getVegCodes from '../../../api-service/vegetationCodeAPI';
import LotApplicantAndInfoForm from '../../../components/LotApplicantAndInfoForm';
import ROUTES from '../../../routes/constants';
import { SeedlotType } from '../../../types/SeedlotType';
import { SeedlotPatchPayloadType, SeedlotRegFormType } from '../../../types/SeedlotRegistrationTypes';
import MultiOptionsObj from '../../../types/MultiOptionsObject';
import PageTitle from '../../../components/PageTitle';
import { THREE_HALF_HOURS, THREE_HOURS } from '../../../config/TimeUnits';
import focusById from '../../../utils/FocusUtils';
import ROUTES from '../../../routes/constants';
import ErrorToast from '../../../components/Toast/ErrorToast';
import Breadcrumbs from '../../../components/Breadcrumbs';
import { ErrToastOption } from '../../../config/ToastifyConfig';
import { getForestClientStringInput } from '../../../utils/ForestClientUtils';
import { getBooleanInputObj, getOptionsInputObj, getStringInputObj } from '../../../utils/FormInputUtils';
import { getSpeciesOptionByCode } from '../../../utils/SeedlotUtils';
import { addParamToPath } from '../../../utils/PathUtils';
import { getMultiOptList } from '../../../utils/MultiOptionsUtils';

import { getBreadcrumbs } from './utils';
import { getSeedlotBreadcrumbs } from '../../../utils/BreadcrumbUtils';
import LotApplicantAndInfoForm from '../../../components/LotApplicantAndInfoForm';
import PageTitle from '../../../components/PageTitle';
import ErrorToast from '../../../components/Toast/ErrorToast';
import Breadcrumbs from '../../../components/Breadcrumbs';
import { ErrToastOption } from '../../../config/ToastifyConfig';

import './styles.scss';

Expand All @@ -47,6 +47,8 @@ const EditAClassApplicationForm = ({ isReview, applicantData, setApplicantData }
const navigate = useNavigate();
const { seedlotNumber } = useParams();

const { isTscAdmin } = useContext(AuthContext);

const vegCodeQuery = useQuery({
queryKey: ['vegetation-codes'],
queryFn: getVegCodes,
Expand Down Expand Up @@ -160,7 +162,11 @@ const EditAClassApplicationForm = ({ isReview, applicantData, setApplicantData }
: (
<>
<Row className="breadcrumb-row">
<Breadcrumbs crumbs={getBreadcrumbs(seedlotNumber!)} />
<Breadcrumbs
crumbs={
getSeedlotBreadcrumbs(seedlotNumber!, applicantClientNumber!, isTscAdmin)
}
/>
</Row>
<Row className="title-row">
<PageTitle
Expand Down
17 changes: 0 additions & 17 deletions frontend/src/views/Seedlot/EditAClassApplication/utils.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,15 @@ interface ApplicantSeedlotInformationProps {
seedlotNumber?: string;
applicant?: SeedlotApplicantType;
isFetching: boolean;
hideEditButton: boolean;
}

const ApplicantInformation = (
{ seedlotNumber, applicant, isFetching }: ApplicantSeedlotInformationProps
) => {
const ApplicantInformation = ({
seedlotNumber,
applicant,
isFetching,
hideEditButton
}: ApplicantSeedlotInformationProps) => {
const navigate = useNavigate();

return (
Expand Down Expand Up @@ -146,19 +150,25 @@ const ApplicantInformation = (
}
</Column>
</Row>
<Row>
<Column>
<Button
kind="tertiary"
size="md"
className="section-btn"
renderIcon={Edit}
onClick={() => navigate(addParamToPath(ROUTES.SEEDLOT_A_CLASS_EDIT, seedlotNumber ?? ''))}
>
Edit applicant
</Button>
</Column>
</Row>
{
hideEditButton
? null
: (
<Row>
<Column>
<Button
kind="tertiary"
size="md"
className="section-btn"
renderIcon={Edit}
onClick={() => navigate(addParamToPath(ROUTES.SEEDLOT_A_CLASS_EDIT, seedlotNumber ?? ''))}
>
Edit applicant
</Button>
</Column>
</Row>
)
}
</FlexGrid>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { Edit } from '@carbon/icons-react';

import { getAClassSeedlotProgressStatus } from '../../../../api-service/seedlotAPI';
import { ProgressIndicatorConfig } from '../../ContextContainerClassA/definitions';
import DetailSection from '../../../../components/DetailSection';
import SeedlotRegistrationProgress from '../../../../components/SeedlotRegistrationProgress';
import NetworkError from '../../../../components/NetworkError';
import { completeProgressConfig, initialProgressConfig } from '../../ContextContainerClassA/constants';
Expand All @@ -19,7 +20,6 @@ import { QueryStatusType } from '../../../../types/QueryStatusType';
import { SeedlotStatusCode } from '../../../../types/SeedlotType';

import './styles.scss';
import DetailSection from '../../../../components/DetailSection';

interface FormProgressProps {
seedlotNumber?: string;
Expand Down Expand Up @@ -115,7 +115,14 @@ const FormProgress = (
onClick={() => navigate(addParamToPath(ROUTES.SEEDLOT_A_CLASS_REGISTRATION, seedlotNumber ?? ''))}
disabled={getSeedlotQueryStatus === 'loading'}
>
{seedlotStatusCode === 'SUB' ? 'View your seedlot' : 'Edit seedlot form'}
{
seedlotStatusCode === 'SUB'
|| seedlotStatusCode === 'EXP'
|| seedlotStatusCode === 'COM'
|| seedlotStatusCode === 'APP'
? 'View your seedlot'
: 'Edit seedlot form'
}
</Button>
</Column>
</Row>
Expand Down
29 changes: 21 additions & 8 deletions frontend/src/views/Seedlot/SeedlotDetails/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import { convertToApplicantInfoObj, covertRawToDisplayObj } from '../../../utils
import { getForestClientByNumberOrAcronym } from '../../../api-service/forestClientsAPI';
import ROUTES from '../../../routes/constants';
import { addParamToPath } from '../../../utils/PathUtils';
import { MEDIUM_SCREEN_WIDTH } from '../../../shared-constants/shared-constants';
import { MEDIUM_SCREEN_WIDTH, MINISTRY_OF_FOREST_ID } from '../../../shared-constants/shared-constants';
import Breadcrumbs from '../../../components/Breadcrumbs';
import { getMultiOptList } from '../../../utils/MultiOptionsUtils';
import { StatusOnSaveType } from '../../../api-service/tscAdminAPI';
Expand All @@ -53,11 +53,16 @@ const SeedlotDetails = () => {

const statusOnSave = searchParams.get('statusOnSave') as StatusOnSaveType | null;

const viewOnlySeedlot: boolean = seedlotData?.seedlotStatus === 'Submitted'
|| seedlotData?.seedlotStatus === 'Expired'
|| seedlotData?.seedlotStatus === 'Complete'
|| seedlotData?.seedlotStatus === 'Approved';

const manageOptions = [
{
text: 'Edit seedlot applicant',
onClickFunction: () => navigate(addParamToPath(ROUTES.SEEDLOT_A_CLASS_EDIT, seedlotNumber ?? '')),
disabled: false
disabled: viewOnlySeedlot
},
{
text: 'Print seedlot',
Expand Down Expand Up @@ -108,7 +113,7 @@ const SeedlotDetails = () => {
if (isTscAdmin && seedlotData?.seedlotStatus === 'Submitted') {
return 'Review seedlot';
}
if (seedlotData?.seedlotStatus === 'Submitted') {
if (viewOnlySeedlot) {
return 'View your seedlot';
}
return 'Edit seedlot form';
Expand Down Expand Up @@ -141,6 +146,17 @@ const SeedlotDetails = () => {
}
};

const createBreadcrumbItems = () => {
const crumbsList = [];
crumbsList.push({ name: 'Seedlots', path: ROUTES.SEEDLOTS });
if (isTscAdmin && seedlotData?.applicantAgency !== MINISTRY_OF_FOREST_ID) {
crumbsList.push({ name: 'Review Seedlots', path: ROUTES.TSC_SEEDLOTS_TABLE });
} else {
crumbsList.push({ name: 'My seedlots', path: ROUTES.MY_SEEDLOTS });
}
return crumbsList;
};

useEffect(() => {
if (forestClientQuery.isFetched && seedlotQuery.isFetchedAfterMount) {
covertToClientObj();
Expand All @@ -150,11 +166,7 @@ const SeedlotDetails = () => {
return (
<FlexGrid className="seedlot-details-page">
<Row className="seedlot-details-breadcrumb">
<Breadcrumbs crumbs={[
{ name: 'Seedlots', path: ROUTES.SEEDLOTS },
{ name: 'My seedlots', path: ROUTES.MY_SEEDLOTS }
]}
/>
<Breadcrumbs crumbs={createBreadcrumbItems()} />
</Row>
<Row className="page-title">
<Column className={windowSize.innerWidth < MEDIUM_SCREEN_WIDTH ? 'summary-title-flex-col' : 'summary-title-flex-row'}>
Expand Down Expand Up @@ -244,6 +256,7 @@ const SeedlotDetails = () => {
seedlotNumber={seedlotNumber}
applicant={applicantData}
isFetching={forestClientQuery?.isFetching}
hideEditButton={!isTscAdmin && viewOnlySeedlot}
/>
{
(
Expand Down
16 changes: 14 additions & 2 deletions frontend/src/views/Seedlot/SeedlotRegFormClassA/RegPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,16 @@ import { ArrowRight } from '@carbon/icons-react';
import { useNavigate } from 'react-router-dom';
import { AxiosError } from 'axios';
import Breadcrumbs from '../../../components/Breadcrumbs';
import { getBreadcrumbs, getSeedlotSubmitErrDescription } from '../ContextContainerClassA/utils';
import { getSeedlotSubmitErrDescription } from '../ContextContainerClassA/utils';
import PageTitle from '../../../components/PageTitle';
import SaveTooltipLabel from './SaveTooltip';
import SeedlotRegistrationProgress from '../../../components/SeedlotRegistrationProgress';
import RegForm from './RegForm';
import SubmitModal from '../../../components/SeedlotRegistrationSteps/SubmitModal';
import AuthContext from '../../../contexts/AuthContext';
import ClassAContext from '../ContextContainerClassA/context';
import { addParamToPath } from '../../../utils/PathUtils';
import { getSeedlotBreadcrumbs } from '../../../utils/BreadcrumbUtils';
import ROUTES from '../../../routes/constants';
import { completeProgressConfig, smartSaveText } from '../ContextContainerClassA/constants';

Expand Down Expand Up @@ -55,12 +57,22 @@ const RegPage = () => {

const reloadFormDraft = () => getFormDraftQuery.refetch();

const { isTscAdmin } = useContext(AuthContext);

return (
<div className="seedlot-registration-page">
<FlexGrid fullWidth>
<Row>
<Column className="seedlot-registration-breadcrumb">
<Breadcrumbs crumbs={getBreadcrumbs(seedlotNumber!)} />
<Breadcrumbs
crumbs={
getSeedlotBreadcrumbs(
seedlotNumber!,
seedlotData?.applicantClientNumber!,
isTscAdmin
)
}
/>
</Column>
</Row>
<Row>
Expand Down
Loading
Loading