From 63b9ed9d08635b60695b2f3c73b9b5e23505d021 Mon Sep 17 00:00:00 2001 From: glen-aot <160973940+glen-aot@users.noreply.github.com> Date: Mon, 21 Oct 2024 10:51:40 -0700 Subject: [PATCH] ORV2-2834 - FE: Update: Change Start Application Menu and Steps (#1635) Co-authored-by: GlenAOT <160973940+GlenAOT@users.noreply.github.com> --- .../components/feeSummary/FeeSummary.tsx | 19 +- .../components/form/ApplicationDetails.tsx | 4 +- .../form/tests/ApplicationDetails.test.tsx | 4 +- .../features/permits/constants/constants.ts | 52 +++- .../dashboard/SelectPermitType.scss | 27 --- .../components/dashboard/SelectPermitType.tsx | 36 --- .../dashboard/StartApplicationAction.scss | 150 +++++++++++- .../dashboard/StartApplicationAction.tsx | 187 ++++++++++++--- .../components/pay/ApplicationSummary.tsx | 7 +- .../tests/ApplicationReview.test.tsx | 13 +- .../permits/pages/Refund/RefundPage.tsx | 4 +- .../Void/components/VoidPermitHeader.tsx | 10 +- .../features/permits/types/PermitCategory.ts | 51 ++++ .../src/features/permits/types/PermitType.ts | 224 ++++++++++++------ frontend/src/themes/orbcStyles.scss | 1 + 15 files changed, 572 insertions(+), 217 deletions(-) delete mode 100644 frontend/src/features/permits/pages/Application/components/dashboard/SelectPermitType.scss delete mode 100644 frontend/src/features/permits/pages/Application/components/dashboard/SelectPermitType.tsx create mode 100644 frontend/src/features/permits/types/PermitCategory.ts diff --git a/frontend/src/features/permits/components/feeSummary/FeeSummary.tsx b/frontend/src/features/permits/components/feeSummary/FeeSummary.tsx index 27ecfd7f8..7f51402a3 100644 --- a/frontend/src/features/permits/components/feeSummary/FeeSummary.tsx +++ b/frontend/src/features/permits/components/feeSummary/FeeSummary.tsx @@ -1,6 +1,6 @@ import { Nullable } from "../../../../common/types/common"; import { feeSummaryDisplayText } from "../../helpers/feeSummary"; -import { PermitType, permitTypeDisplayText } from "../../types/PermitType"; +import { getPermitTypeName, PermitType } from "../../types/PermitType"; import "./FeeSummary.scss"; export const FeeSummary = ({ @@ -14,7 +14,11 @@ export const FeeSummary = ({ permitDuration?: number; hideDescriptions?: boolean; }) => { - const feeDisplayText = feeSummaryDisplayText(feeSummary, permitDuration, permitType); + const feeDisplayText = feeSummaryDisplayText( + feeSummary, + permitDuration, + permitType, + ); return (
@@ -28,17 +32,20 @@ export const FeeSummary = ({
-
- {permitTypeDisplayText(permitType)} +
+ {getPermitTypeName(permitType)}
- +
{feeDisplayText}
)} - +
Total (CAD)
diff --git a/frontend/src/features/permits/components/form/ApplicationDetails.tsx b/frontend/src/features/permits/components/form/ApplicationDetails.tsx index bb9842061..9ed8ae86b 100644 --- a/frontend/src/features/permits/components/form/ApplicationDetails.tsx +++ b/frontend/src/features/permits/components/form/ApplicationDetails.tsx @@ -4,7 +4,7 @@ import { Dayjs } from "dayjs"; import { CompanyBanner } from "../../../../common/components/banners/CompanyBanner"; import { CompanyInformation } from "./CompanyInformation"; import "./ApplicationDetails.scss"; -import { permitTypeDisplayText } from "../../types/PermitType"; +import { getPermitTypeName } from "../../types/PermitType"; import { CompanyProfile } from "../../../manageProfile/types/manageProfile"; import { Nullable } from "../../../../common/types/common"; import { @@ -35,7 +35,7 @@ export const ApplicationDetails = ({ isAmendAction?: Nullable; doingBusinessAs?: Nullable; }) => { - const applicationName = permitTypeDisplayText( + const applicationName = getPermitTypeName( getDefaultRequiredVal("", permitType), ); diff --git a/frontend/src/features/permits/components/form/tests/ApplicationDetails.test.tsx b/frontend/src/features/permits/components/form/tests/ApplicationDetails.test.tsx index a8d68ef06..3ac3911ee 100644 --- a/frontend/src/features/permits/components/form/tests/ApplicationDetails.test.tsx +++ b/frontend/src/features/permits/components/form/tests/ApplicationDetails.test.tsx @@ -1,4 +1,4 @@ -import { permitTypeDisplayText } from "../../../types/PermitType"; +import { getPermitTypeName } from "../../../types/PermitType"; import { DATE_FORMATS, dayjsToLocalStr, @@ -57,7 +57,7 @@ describe("Application Details Display", () => { ); // Assert - expect(await title()).toHaveTextContent(permitTypeDisplayText(permitType)); + expect(await title()).toHaveTextContent(getPermitTypeName(permitType)); expect(await applicationNumber()).toHaveTextContent( defaultApplicationNumber, ); diff --git a/frontend/src/features/permits/constants/constants.ts b/frontend/src/features/permits/constants/constants.ts index 8f7639fef..ef343f2a0 100644 --- a/frontend/src/features/permits/constants/constants.ts +++ b/frontend/src/features/permits/constants/constants.ts @@ -1,5 +1,14 @@ import { VEHICLE_TYPES } from "../../manageVehicles/types/Vehicle"; -import { EMPTY_PERMIT_TYPE_SELECT, PERMIT_TYPES, getPermitTypeName } from "../types/PermitType"; +import { + getPermitCategoryName, + PERMIT_CATEGORIES, + PermitCategory, +} from "../types/PermitCategory"; +import { + PermitType, + TERM_PERMIT_LIST, + getPermitTypeShortName, +} from "../types/PermitType"; export const VEHICLE_CHOOSE_FROM = { UNIT_NUMBER: "unitNumber", @@ -19,12 +28,45 @@ export const VEHICLE_TYPE_OPTIONS = [ { value: VEHICLE_TYPES.TRAILER, label: "Trailer" }, ]; -export const PERMIT_TYPE_CHOOSE_FROM_OPTIONS = [ - { value: EMPTY_PERMIT_TYPE_SELECT, label: "Select" }, - { value: PERMIT_TYPES.TROS, label: getPermitTypeName(PERMIT_TYPES.TROS) }, - { value: PERMIT_TYPES.TROW, label: getPermitTypeName(PERMIT_TYPES.TROW) }, +export const ALL_PERMIT_TYPE_CHOOSE_FROM_OPTIONS: PermitTypeChooseFromItem[] = [ + { + value: PERMIT_CATEGORIES.TERM, + label: getPermitCategoryName(PERMIT_CATEGORIES.TERM), + items: TERM_PERMIT_LIST.map((permitType: PermitType) => ({ + value: permitType, + label: getPermitTypeShortName(permitType), + })), + }, + /* TODO uncomment these when required */ + // { + // value: PERMIT_CATEGORIES.SINGLE_TRIP, + // label: getPermitCategoryName(PERMIT_CATEGORIES.SINGLE_TRIP), + // items: SINGLE_TRIP_PERMIT_LIST.map((permitType: PermitType) => ({ + // value: permitType, + // label: getPermitTypeShortName(permitType), + // })), + // }, + // { + // value: PERMIT_CATEGORIES.NON_RESIDENT, + // label: getPermitCategoryName(PERMIT_CATEGORIES.NON_RESIDENT), + // items: NON_RESIDENT_PERMIT_LIST.map((permitType: PermitType) => ({ + // value: permitType, + // label: getPermitTypeShortName(permitType), + // })), + // }, + // { + // value: PERMIT_TYPES.MFP, + // label: getPermitTypeShortName(PERMIT_TYPES.MFP), + // }, ]; +export interface PermitTypeChooseFromItem { + value: PermitType | PermitCategory; + label: string; + items?: PermitTypeChooseFromItem[]; + category?: string; +} + export const BASE_DAYS_IN_YEAR = 365; export const COMMON_MIN_DURATION = 30; export const TERM_DURATION_INTERVAL_DAYS = 30; diff --git a/frontend/src/features/permits/pages/Application/components/dashboard/SelectPermitType.scss b/frontend/src/features/permits/pages/Application/components/dashboard/SelectPermitType.scss deleted file mode 100644 index 3d5d43677..000000000 --- a/frontend/src/features/permits/pages/Application/components/dashboard/SelectPermitType.scss +++ /dev/null @@ -1,27 +0,0 @@ -@use "../../../../../../common/components/form/CustomFormComponents"; -@import "../../../../../../themes/orbcStyles"; - -@include CustomFormComponents.custom-form-component(".select-permit-type__input"); - -.select-permit-type { - &#{&} { - font-size: 1rem; - color: $bc-black; - margin: 0; - } - - & &__label { - font-weight: bold; - margin-bottom: 0.5rem; - } - - & &__input { - background-color: $white; - width: 15.25rem; - margin-bottom: 0; - } - - & &__menu { - width: calc(100% - 10px); - } -} diff --git a/frontend/src/features/permits/pages/Application/components/dashboard/SelectPermitType.tsx b/frontend/src/features/permits/pages/Application/components/dashboard/SelectPermitType.tsx deleted file mode 100644 index 2a1cce220..000000000 --- a/frontend/src/features/permits/pages/Application/components/dashboard/SelectPermitType.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { - FormControl, - FormLabel, - Select, - SelectChangeEvent, -} from "@mui/material"; - -import "./SelectPermitType.scss"; -import { Optional } from "../../../../../../common/types/common"; - -export const SelectPermitType = ({ - value, - label, - onChange, - menuItems, -}: { - value: string; - label: string; - onChange: (event: SelectChangeEvent) => void; - menuItems: Optional; -}) => ( - - {label} - - - -); diff --git a/frontend/src/features/permits/pages/Application/components/dashboard/StartApplicationAction.scss b/frontend/src/features/permits/pages/Application/components/dashboard/StartApplicationAction.scss index 10c6665ef..5a6b9fade 100644 --- a/frontend/src/features/permits/pages/Application/components/dashboard/StartApplicationAction.scss +++ b/frontend/src/features/permits/pages/Application/components/dashboard/StartApplicationAction.scss @@ -1,8 +1,132 @@ +@import "../../../../../../themes/orbcStyles.scss"; + +$select-width: 347px; + .start-application-action { - display: flex; - flex-direction: row; - align-items: flex-end; - width: 100%; + & &__label { + font-weight: bold; + } + + &__control { + display: flex; + justify-content: space-between; + align-items: stretch; + padding-top: .5rem; + } + + & &__input { + display: flex; + justify-content: space-between; + align-items: center; + background-color: $white; + padding: .5rem .75rem; + white-space: nowrap; + overflow: hidden; + border: 2px solid; + border-color: $bc-text-box-border-grey; + color: $bc-black; + margin-bottom: 0; + width: $select-width; + + &:hover { + background-color: $white; + } + + &:active, &:focus { + border-color: $border-blue; + outline: none; + } + + + &--error { + border-color: $bc-red; + } + + &--open { + border-radius: 4px 4px 0px 0px; + border-bottom: none; + border-color: $border-blue; + // prevent input text shifting when menu is open + padding-top: 6px; + } + + } + &__input-text { + text-align: left; + width: 40ch; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + &__input-tooltip { + max-width: fit-content; + } + + &__menu-list { + &.MuiList-root { + padding: 0; + + & > * { + border-top: 1px solid $bc-border-grey; + } + } + } + + &__menu-item:not(:last-child) { + &.MuiButtonBase-root { + border-bottom: 1px solid $bc-border-grey; + } + } + + &__menu-container { + &.MuiPaper-root { + border-radius: 0; + box-shadow: 0 0.5rem 0.5rem -0.2rem #00000029; + // prevent menu from being wider than the input element itself + width: calc($select-width - 4px); + transition-duration: 0ms; + } + + &--open { + &.MuiPaper-root { + border: 2px solid; + border-top: none; + border-radius: 0px 0px 2px 2px; + border-color: $border-blue; + } + } + } + + // NESTED MENUS + + &__nested-menu-list { + &.MuiList-root.MuiMenu-list { + padding: 0; + max-height: none; + } + } + + + &__nested-menu-item:not(:last-child) { + &.MuiButtonBase-root { + border-bottom: 1px solid $bc-border-grey; + } + } + + &__nested-menu-container { + &.MuiPaper-root { + border-radius: 4px; + box-shadow: $bc-shadow; + width: calc($select-width - 4px); + transition-duration: 0ms; + border: 2px solid; + border-color: $border-blue; + margin-left: 8px; + } + } + + // SUBMIT BUTTON & &__btn { margin-left: 1.5rem; @@ -11,12 +135,22 @@ font-size: 1rem; font-weight: bold; } + + &__error-msg { + position: absolute; + color: $bc-red + } } -@media (width < 1200px) { - .start-application-action { - flex-direction: column; - align-items: flex-start; +@media (width < 600px) { + .start-application-action { + &__control { + flex-direction: column; + } + + & &__input { + width: 100%; + } & &__btn { margin-left: 0; diff --git a/frontend/src/features/permits/pages/Application/components/dashboard/StartApplicationAction.tsx b/frontend/src/features/permits/pages/Application/components/dashboard/StartApplicationAction.tsx index 7f2ecebc1..c5de21fe7 100644 --- a/frontend/src/features/permits/pages/Application/components/dashboard/StartApplicationAction.tsx +++ b/frontend/src/features/permits/pages/Application/components/dashboard/StartApplicationAction.tsx @@ -1,56 +1,167 @@ -import { useNavigate } from "react-router-dom"; +import { Box, Button, FormLabel, Menu, MenuItem, Tooltip } from "@mui/material"; import { useState } from "react"; -import { Box, MenuItem, SelectChangeEvent, Button } from "@mui/material"; - -import "./StartApplicationAction.scss"; -import { PERMIT_TYPE_CHOOSE_FROM_OPTIONS } from "../../../../constants/constants"; -import { SelectPermitType } from "./SelectPermitType"; +import { useNavigate } from "react-router-dom"; +import { NestedMenuItem } from "mui-nested-menu"; import { APPLICATIONS_ROUTES } from "../../../../../../routes/constants"; -import { DEFAULT_PERMIT_TYPE, EMPTY_PERMIT_TYPE_SELECT, PermitType } from "../../../../types/PermitType"; - -/** - * - * Code taken largely from MUI MenuList Composition - * https://mui.com/material-ui/react-menu/#menulist-composition - * - * - */ +import { + ALL_PERMIT_TYPE_CHOOSE_FROM_OPTIONS, + PermitTypeChooseFromItem, +} from "../../../../constants/constants"; +import { + EMPTY_PERMIT_TYPE_SELECT, + PermitType, + getFormattedPermitTypeName, +} from "../../../../types/PermitType"; +import "./StartApplicationAction.scss"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faChevronDown } from "@fortawesome/free-solid-svg-icons"; + export const StartApplicationAction = () => { const navigate = useNavigate(); - const [chooseFrom, setChooseFrom] = useState( - DEFAULT_PERMIT_TYPE - ); + const [chooseFrom, setChooseFrom] = useState< + PermitType | typeof EMPTY_PERMIT_TYPE_SELECT + >(EMPTY_PERMIT_TYPE_SELECT); + + const [isError, setIsError] = useState(false); - const handleChooseFrom = (event: SelectChangeEvent) => { - setChooseFrom(event.target.value as PermitType | typeof EMPTY_PERMIT_TYPE_SELECT); + const handleChooseFrom = ( + _event: React.MouseEvent, + item: PermitTypeChooseFromItem, + ) => { + setIsError(false); + setChooseFrom(item.value as PermitType); + handleClose(); }; const handleStartButtonClicked = () => { if (chooseFrom !== EMPTY_PERMIT_TYPE_SELECT) { navigate(APPLICATIONS_ROUTES.START_APPLICATION(chooseFrom)); + } else { + setIsError(true); } }; + // Update the structure of menuItems to ensure the callback is applied correctly + const menuItems = ALL_PERMIT_TYPE_CHOOSE_FROM_OPTIONS.map( + (item: PermitTypeChooseFromItem) => ({ + ...item, + callback: (event: React.MouseEvent) => + handleChooseFrom(event, item), + // Correctly set the nested item's callback + items: item?.items?.map((nestedItem) => ({ + ...nestedItem, + callback: (event: React.MouseEvent) => + handleChooseFrom(event, nestedItem), + })), + }), + ); + + const [anchorEl, setAnchorEl] = useState(); + const open = Boolean(anchorEl); + + const handleClick = (e: any) => + setAnchorEl(e.currentTarget as HTMLDivElement); + const handleClose = () => setAnchorEl(null); + + const inputClass = "start-application-action__input"; + const inputOpenClass = "start-application-action__input--open"; + const inputErrorClass = "start-application-action__input--error"; + const menuClass = "start-application-action__menu-container"; + const menuOpenClass = "start-application-action__menu-container--open"; + return ( - ( - - {data.label} - - ))} - /> - - + + Select Permit Type + +
+ + + + + + {menuItems.map((item) => + item.items ? ( + + {item.items.map((nestedItem) => ( + + {nestedItem.label} + + ))} + + ) : ( + + {item.label} + + ), + )} + + + +
+ {isError ? ( + + Select a permit type. + + ) : null}
); }; diff --git a/frontend/src/features/permits/pages/Application/components/pay/ApplicationSummary.tsx b/frontend/src/features/permits/pages/Application/components/pay/ApplicationSummary.tsx index 6e179c9d4..7df79d059 100644 --- a/frontend/src/features/permits/pages/Application/components/pay/ApplicationSummary.tsx +++ b/frontend/src/features/permits/pages/Application/components/pay/ApplicationSummary.tsx @@ -3,10 +3,7 @@ import { Box, Typography } from "@mui/material"; import "./ApplicationSummary.scss"; import { getDefaultRequiredVal } from "../../../../../../common/helpers/util"; import { Nullable } from "../../../../../../common/types/common"; -import { - PermitType, - permitTypeDisplayText, -} from "../../../../types/PermitType"; +import { getPermitTypeName, PermitType } from "../../../../types/PermitType"; export const ApplicationSummary = ({ permitType, @@ -15,7 +12,7 @@ export const ApplicationSummary = ({ permitType?: Nullable; applicationNumber?: Nullable; }) => { - const applicationName = permitTypeDisplayText( + const applicationName = getPermitTypeName( getDefaultRequiredVal("", permitType), ); diff --git a/frontend/src/features/permits/pages/Application/tests/ApplicationReview.test.tsx b/frontend/src/features/permits/pages/Application/tests/ApplicationReview.test.tsx index 09b10e1f6..960f2b9b3 100644 --- a/frontend/src/features/permits/pages/Application/tests/ApplicationReview.test.tsx +++ b/frontend/src/features/permits/pages/Application/tests/ApplicationReview.test.tsx @@ -6,7 +6,7 @@ import { vehicleTypeDisplayText } from "../../../helpers/mappers"; import { VehicleType } from "../../../../manageVehicles/types/Vehicle"; import { getDefaultRequiredVal } from "../../../../../common/helpers/util"; import { calculateFeeByDuration } from "../../../helpers/feeSummary"; -import { permitTypeDisplayText } from "../../../types/PermitType"; +import { getPermitTypeName } from "../../../types/PermitType"; import { DATE_FORMATS, dayjsToLocalStr, @@ -87,7 +87,7 @@ beforeAll(() => { // @ts-ignore window.scrollTo = vi.fn(); listenToMockServer(); - sessionStorage.setItem('onRouteBC.user.companyId', "74"); + sessionStorage.setItem("onRouteBC.user.companyId", "74"); }); beforeEach(() => { @@ -120,7 +120,7 @@ describe("Review and Confirm Application Details", () => { permitType, } = defaultApplicationData; expect(await applicationHeaderTitle()).toHaveTextContent( - permitTypeDisplayText(permitType), + getPermitTypeName(permitType), ); expect(await applicationNumber()).toHaveTextContent( applicationNo as string, @@ -343,7 +343,8 @@ describe("Review and Confirm Application Details", () => { provinceCode, vehicleType, vehicleSubType, - } = defaultApplicationData.permitData.vehicleDetails as PermitVehicleDetails; + } = defaultApplicationData.permitData + .vehicleDetails as PermitVehicleDetails; const unit = getDefaultRequiredVal("", unitNumber); const country = formatCountry(countryCode); const province = formatProvince(countryCode, provinceCode); @@ -415,7 +416,9 @@ describe("Review and Confirm Application Details", () => { defaultApplicationData.permitType, defaultApplicationData.permitData.permitDuration, )}`; - const permitTypeStr = permitTypeDisplayText(defaultApplicationData.permitType); + const permitTypeStr = getPermitTypeName( + defaultApplicationData.permitType, + ); expect(await feeSummaryPermitType()).toHaveTextContent(permitTypeStr); expect(await feeSummaryPrice()).toHaveTextContent(`$${feeSummary}.00`); expect(await feeSummaryTotal()).toHaveTextContent(`$${feeSummary}.00`); diff --git a/frontend/src/features/permits/pages/Refund/RefundPage.tsx b/frontend/src/features/permits/pages/Refund/RefundPage.tsx index cb1dd91bb..6ab9f63cf 100644 --- a/frontend/src/features/permits/pages/Refund/RefundPage.tsx +++ b/frontend/src/features/permits/pages/Refund/RefundPage.tsx @@ -14,7 +14,7 @@ import { } from "@mui/material"; import "./RefundPage.scss"; -import { PermitType, permitTypeDisplayText } from "../../types/PermitType"; +import { getPermitTypeName, PermitType } from "../../types/PermitType"; import { RefundFormData } from "./types/RefundFormData"; import { requiredMessage } from "../../../../common/helpers/validationMessages"; import { getErrorMessage } from "../../../../common/components/form/CustomFormComponents"; @@ -388,7 +388,7 @@ export const RefundPage = ({
- {permitTypeDisplayText(permitType)} + {getPermitTypeName(permitType)}
{permitActionText(permitAction)} Permit #: diff --git a/frontend/src/features/permits/pages/Void/components/VoidPermitHeader.tsx b/frontend/src/features/permits/pages/Void/components/VoidPermitHeader.tsx index ee7c06cd2..af5f3e07e 100644 --- a/frontend/src/features/permits/pages/Void/components/VoidPermitHeader.tsx +++ b/frontend/src/features/permits/pages/Void/components/VoidPermitHeader.tsx @@ -3,18 +3,14 @@ import { Box, Typography } from "@mui/material"; import "./VoidPermitHeader.scss"; import { Permit } from "../../../types/permit"; import { CompanyBanner } from "../../../../../common/components/banners/CompanyBanner"; -import { permitTypeDisplayText } from "../../../types/PermitType"; +import { getPermitTypeName } from "../../../types/PermitType"; import { Nullable } from "../../../../../common/types/common"; import { DATE_FORMATS, toLocal, } from "../../../../../common/helpers/formatDate"; -export const VoidPermitHeader = ({ - permit, -}: { - permit: Nullable; -}) => { +export const VoidPermitHeader = ({ permit }: { permit: Nullable }) => { return permit ? (
- {permitTypeDisplayText(permit.permitType)} + {getPermitTypeName(permit.permitType)} diff --git a/frontend/src/features/permits/types/PermitCategory.ts b/frontend/src/features/permits/types/PermitCategory.ts new file mode 100644 index 000000000..cb76673df --- /dev/null +++ b/frontend/src/features/permits/types/PermitCategory.ts @@ -0,0 +1,51 @@ +import { + NON_RESIDENT_PERMIT_LIST, + PermitType, + SINGLE_TRIP_PERMIT_LIST, + TERM_PERMIT_LIST, +} from "./PermitType"; + +export const PERMIT_CATEGORIES = { + TERM: "TERM", + SINGLE_TRIP: "SINGLE_TRIP", + NON_RESIDENT: "NON_RESIDENT", +}; + +export type PermitCategory = + (typeof PERMIT_CATEGORIES)[keyof typeof PERMIT_CATEGORIES]; + +/** + * Returns the name of the permit category. + * @param permitCategory String that represents the permit category + * @returns Name of the permit category, or empty string if no mapping exists for permit category + */ +export const getPermitCategoryName = (permitCategory: PermitCategory) => { + switch (permitCategory) { + case PERMIT_CATEGORIES.TERM: + return "Term"; + case PERMIT_CATEGORIES.SINGLE_TRIP: + return "Single Trip"; + case PERMIT_CATEGORIES.NON_RESIDENT: + return "Non-Resident"; + default: + return ""; + } +}; + +/** + * Returns the permit category for the given permit type. + * @param permitType String that represents the permit type + * @returns Name of the permit category, or empty string if no mapping exists for permit category + */ +export const getPermitCategory = (permitType: PermitType) => { + if (TERM_PERMIT_LIST.includes(permitType)) { + return PERMIT_CATEGORIES.TERM; + } + if (SINGLE_TRIP_PERMIT_LIST.includes(permitType)) { + return PERMIT_CATEGORIES.SINGLE_TRIP; + } + if (NON_RESIDENT_PERMIT_LIST.includes(permitType)) { + return PERMIT_CATEGORIES.NON_RESIDENT; + } + return ""; +}; diff --git a/frontend/src/features/permits/types/PermitType.ts b/frontend/src/features/permits/types/PermitType.ts index 1d2bb9341..a85676631 100644 --- a/frontend/src/features/permits/types/PermitType.ts +++ b/frontend/src/features/permits/types/PermitType.ts @@ -1,36 +1,74 @@ import { Nullable } from "../../../common/types/common"; +import { getPermitCategory, getPermitCategoryName } from "./PermitCategory"; export const PERMIT_TYPES = { - EPTOP: "EPTOP", + /* TERM */ + // Term Oversize + TROS: "TROS", + // Term Overweight + TROW: "TROW", + // Highway Crossing HC: "HC", - LCV: "LCV", - MFP: "MFP", - NRQBS: "NRQBS", - NRQCL: "NRQCL", - NRQCV: "NRQCV", - NRQFT: "NRQFT", - NRQFV: "NRQFV", - NRQXP: "NRQXP", - NRSBS: "NRSBS", - NRSCL: "NRSCL", - NRSCV: "NRSCV", - NRSFT: "NRSFT", - NRSFV: "NRSFV", - NRSXP: "NRSXP", - RIG: "RIG", - STOL: "STOL", - STOS: "STOS", + // Axle Overweight + + /* SINGLE TRIP */ + // Extra Provincial Temp Operating Permit + EPTOP: "EPTOP", + // Single Trip Overweight STOW: "STOW", + // Single Trip Oversize + STOS: "STOS", + // Single Trip Oversize Overweight STWS: "STWS", - TRAX: "TRAX", - TROS: "TROS", - TROW: "TROW", + // Empty - Single Trip Over Length 27.5 + STOL: "STOL", + // Rig Move + RIG: "RIG", + // Increased GVW + IGVW: "IGVW", + + /* NON RESIDENT */ + // Quarterly ICBC Basic Insurance (FR) + QRFR: "QRFR", + // Quarterly Non-Resident + QNRBS: "QNRBS", + // Single Trip ICBC Basic Insurance (FR) + STFR: "STFR", + // Single Trip Non-Resident + NRSCV: "NRSCV", + + /* MOTIVE FUEL USER PERMIT */ + MFP: "MFP", } as const; export type PermitType = (typeof PERMIT_TYPES)[keyof typeof PERMIT_TYPES]; export const DEFAULT_PERMIT_TYPE = PERMIT_TYPES.TROS; -export const EMPTY_PERMIT_TYPE_SELECT = "select"; +export const EMPTY_PERMIT_TYPE_SELECT = "Select"; + +export const TERM_PERMIT_LIST: PermitType[] = [ + PERMIT_TYPES.TROS, + PERMIT_TYPES.TROW, + /* TODO uncomment this when required */ + // PERMIT_TYPES.HC, +]; + +export const SINGLE_TRIP_PERMIT_LIST: PermitType[] = [ + PERMIT_TYPES.STOL, + PERMIT_TYPES.EPTOP, + PERMIT_TYPES.IGVW, + PERMIT_TYPES.STOS, + PERMIT_TYPES.STWS, + PERMIT_TYPES.STOW, + PERMIT_TYPES.RIG, +]; + +export const NON_RESIDENT_PERMIT_LIST: PermitType[] = [ + PERMIT_TYPES.QNRBS, + PERMIT_TYPES.QRFR, + PERMIT_TYPES.NRSCV, + PERMIT_TYPES.STFR, +]; /** * Returns the name/description of the permit type. @@ -39,73 +77,109 @@ export const EMPTY_PERMIT_TYPE_SELECT = "select"; */ export const getPermitTypeName = (permitType?: Nullable) => { switch (permitType) { - case PERMIT_TYPES.EPTOP: - return "Extra-Provincial Temporary Operating"; + /* TERM */ + case PERMIT_TYPES.TROS: + return "Term Oversize"; + case PERMIT_TYPES.TROW: + return "Term Overweight"; case PERMIT_TYPES.HC: return "Highway Crossing"; - case PERMIT_TYPES.LCV: - return "Long Combination Vehicle"; - case PERMIT_TYPES.MFP: - return "Motive Fuel User"; - case PERMIT_TYPES.NRQBS: - return "Quarterly Non Resident Reg. / Ins. - Bus"; - case PERMIT_TYPES.NRQCL: - return "Non Resident Quarterly Conditional License"; - case PERMIT_TYPES.NRQCV: - return "Quarterly Non Resident Reg. / Ins. - Comm Vehicle"; - case PERMIT_TYPES.NRQFT: - return "Non Resident Quarterly Farm Tractor"; - case PERMIT_TYPES.NRQFV: - return "Quarterly Non Resident Reg. / Ins. - Farm Vehicle"; - case PERMIT_TYPES.NRQXP: - return "Non Resident Quarterly X Plated"; - case PERMIT_TYPES.NRSBS: - return "Single Trip Non-Resident Registration / Insurance - Buses"; - case PERMIT_TYPES.NRSCL: - return "Non Resident Single Trip Conditional License"; - case PERMIT_TYPES.NRSCV: - return "Single Trip Non-Resident Reg. / Ins. - Commercial Vehicle"; - case PERMIT_TYPES.NRSFT: - return "Non Resident Farm Tractor Single Trip"; - case PERMIT_TYPES.NRSFV: - return "Single Trip Non-Resident Reg. / Ins. - Farm Vehicle"; - case PERMIT_TYPES.NRSXP: - return "Non Resident Single Trip X Plated Vehicle"; - case PERMIT_TYPES.RIG: - return "Rig Move"; - case PERMIT_TYPES.STOL: - return "Single Trip Over Length"; + + /* SINGLE TRIP */ case PERMIT_TYPES.STOS: return "Single Trip Oversize"; - case PERMIT_TYPES.STOW: - return "Single Trip Over Weight"; case PERMIT_TYPES.STWS: return "Single Trip Overweight Oversize"; - case PERMIT_TYPES.TRAX: - return "Term Axle Overweight"; - case PERMIT_TYPES.TROS: - return "Term Oversize"; - case PERMIT_TYPES.TROW: - return "Term Overweight"; + case PERMIT_TYPES.STOW: + return "Single Trip Over Weight"; + case PERMIT_TYPES.EPTOP: + return "Extra-Provincial Temporary Operating"; + case PERMIT_TYPES.STOL: + return "Single Trip Over Length"; + case PERMIT_TYPES.RIG: + return "Rig Move"; + case PERMIT_TYPES.IGVW: + return "Increased GVW"; + + /* NON-RESIDENT */ + case PERMIT_TYPES.NRSCV: + return "Single Trip Non-Resident"; + case PERMIT_TYPES.QNRBS: + return "Quarterly Non-Resident"; + case PERMIT_TYPES.QRFR: + return "Quarterly ICBC Basic Insurance (FR)"; + case PERMIT_TYPES.STFR: + return "Single Trip ICBC Basic Insurance (FR)"; + + /* MOTIVE FUEL USER PERMIT */ + case PERMIT_TYPES.MFP: + return "Motive Fuel User Permit"; + default: return ""; } }; /** - * Gets display text for permit type. - * @param permitType Permit type (eg. TROS, STOS, etc) - * @returns display text for the permit type + * Returns the shortened name/description of the permit type. + * @param permitType String (if any) that represents the permit type + * @returns Short name/description of the permit type, or empty string if no mapping exists for permit type */ -export const permitTypeDisplayText = (permitType?: Nullable) => { +export const getPermitTypeShortName = (permitType?: Nullable) => { switch (permitType) { + /* TERM */ case PERMIT_TYPES.TROS: - return "Oversize: Term"; + return "Oversize"; + case PERMIT_TYPES.TROW: + return "Overweight"; + case PERMIT_TYPES.HC: + return "Highway Crossing"; + + /* SINGLE TRIP */ + case PERMIT_TYPES.EPTOP: + return "Extra-Provincial Temporary Operating Permit"; + case PERMIT_TYPES.STOW: + return "Overweight"; case PERMIT_TYPES.STOS: - return "Oversize: Single Trip"; + return "Oversize"; + case PERMIT_TYPES.STWS: + return "Oversized Overweight"; + case PERMIT_TYPES.STOL: + return "Empty - Length Over 27.5 m"; + case PERMIT_TYPES.RIG: + return "Rig Move"; + case PERMIT_TYPES.IGVW: + return "Increased GVW"; + + /* NON RESIDENT */ + case PERMIT_TYPES.QRFR: + return "Quarterly ICBC Basic Insurance (FR)"; + case PERMIT_TYPES.QNRBS: + return "Quarterly"; + case PERMIT_TYPES.STFR: + return "Single Trip ICBC Basic Insurance (FR)"; + case PERMIT_TYPES.NRSCV: + return "Single Trip"; + + /* MOTIVE FUEL USER PERMIT */ + case PERMIT_TYPES.MFP: + return "Motive Fuel User Permit"; + default: - return getPermitTypeName(permitType); + return ""; + } +}; + +/** + * Gets formatted Permit Type name as "PermitCategory > PermitType". Used in the Select Permit Type dropdown + * @param permitType Permit type (eg. TROS, STOS, etc) + * @returns formatted display text for the permit category type + */ +export const getFormattedPermitTypeName = (permitType: PermitType) => { + if (permitType === PERMIT_TYPES.MFP) { + return getPermitTypeName(PERMIT_TYPES.MFP); } + return `${getPermitCategoryName(getPermitCategory(permitType))} > ${getPermitTypeShortName(permitType)}`; }; /** @@ -114,7 +188,10 @@ export const permitTypeDisplayText = (permitType?: Nullable) => { * @returns true if string is a valid permit type, or false otherwise */ export const isPermitTypeValid = (permitType?: Nullable) => { - return permitType && (Object.values(PERMIT_TYPES) as string[]).includes(permitType.toUpperCase()); + return ( + permitType && + (Object.values(PERMIT_TYPES) as string[]).includes(permitType.toUpperCase()) + ); }; /** @@ -123,6 +200,5 @@ export const isPermitTypeValid = (permitType?: Nullable) => { * @returns Whether or not the permit of that type is considered a term permit */ export const isTermPermitType = (permitType: PermitType) => { - return permitType === PERMIT_TYPES.TROS - || permitType === PERMIT_TYPES.TROW; + return permitType === PERMIT_TYPES.TROS || permitType === PERMIT_TYPES.TROW; }; diff --git a/frontend/src/themes/orbcStyles.scss b/frontend/src/themes/orbcStyles.scss index 128161cdc..fe51cdc8a 100644 --- a/frontend/src/themes/orbcStyles.scss +++ b/frontend/src/themes/orbcStyles.scss @@ -36,6 +36,7 @@ $blue: #0000ff; $button-hover: #2d5992; $disabled-colour: #b5c0cf; $focus-blue: #3b99fc; +$border-blue: #5697F5; $shadow-colour: #00000029; $white: #ffffff;