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

ORV2-2684 - FE:User Manage Applications in Review #1594

Merged
merged 9 commits into from
Sep 16, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export const InfoBcGovBanner = ({
additionalInfo,
className,
}: {
msg: string;
msg: string | JSX.Element;
additionalInfo?: JSX.Element;
className?: string;
}) => (
Expand Down
147 changes: 79 additions & 68 deletions frontend/src/common/components/table/OnRouteBCTableRowActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,16 @@ export const OnRouteBCTableRowActions = ({
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
const isMenuOpen = Boolean(anchorEl);

const actionsButtonPressedClassName =
isMenuOpen ? " onroutebc-table-row-actions__button--pressed" : "";
const actionsButtonPressedClassName = isMenuOpen
? " onroutebc-table-row-actions__button--pressed"
: "";

const handleOpenActionsMenu = useCallback((event: MouseEvent<HTMLElement>) => {
setAnchorEl(event.currentTarget);
}, []);
const handleOpenActionsMenu = useCallback(
(event: MouseEvent<HTMLElement>) => {
setAnchorEl(event.currentTarget);
},
[],
);

const handleCloseActionsMenu = () => {
setAnchorEl(null);
Expand All @@ -42,69 +46,76 @@ export const OnRouteBCTableRowActions = ({
};

return (
<div className="onroutebc-table-row-actions">
<Tooltip
title="Actions"
classes={{
popper: "popper onroutebc-table-row-actions__popper",
tooltip: "tooltip",
tooltipPlacementBottom: "tooltip--bottom",
}}
>
<IconButton
className={`onroutebc-table-row-actions__button ${actionsButtonPressedClassName}`}
classes={{
disabled: "onroutebc-table-row-actions__button--disabled",
}}
aria-label="Actions"
id="actions-button"
aria-controls={isMenuOpen ? "actions-menu" : undefined}
aria-expanded={isMenuOpen ? "true" : undefined}
aria-haspopup="true"
onClick={handleOpenActionsMenu}
disabled={disabled}
>
<FontAwesomeIcon
icon={faEllipsisVertical}
className="onroutebc-table-row-actions__icon"
/>
</IconButton>
</Tooltip>
<>
{
// if there are no options, return null to prevent returning an empty menu
options.length > 0 ? (
<div className="onroutebc-table-row-actions">
<Tooltip
title="Actions"
classes={{
popper: "popper onroutebc-table-row-actions__popper",
tooltip: "tooltip",
tooltipPlacementBottom: "tooltip--bottom",
}}
>
<IconButton
className={`onroutebc-table-row-actions__button ${actionsButtonPressedClassName}`}
classes={{
disabled: "onroutebc-table-row-actions__button--disabled",
}}
aria-label="Actions"
id="actions-button"
aria-controls={isMenuOpen ? "actions-menu" : undefined}
aria-expanded={isMenuOpen ? "true" : undefined}
aria-haspopup="true"
onClick={handleOpenActionsMenu}
disabled={disabled}
>
<FontAwesomeIcon
icon={faEllipsisVertical}
className="onroutebc-table-row-actions__icon"
/>
</IconButton>
</Tooltip>

<Menu
className="onroutebc-table-row-actions__menu"
id="actions-menu"
MenuListProps={{
"aria-labelledby": "actions-button",
}}
anchorEl={anchorEl}
anchorOrigin={{
horizontal: "right",
vertical: "bottom",
}}
transformOrigin={{
horizontal: "right",
vertical: "top",
}}
open={isMenuOpen}
onClose={handleCloseActionsMenu}
slotProps={{
paper: {
className: "onroutebc-table-row-actions__paper",
},
}}
>
{options.map((option) => (
<MenuItem
key={`option-${option.value}`}
className="onroutebc-table-row-actions__menu-item"
onClick={onClickOption}
data-option-value={option.value}
>
{option.label}
</MenuItem>
))}
</Menu>
</div>
<Menu
className="onroutebc-table-row-actions__menu"
id="actions-menu"
MenuListProps={{
"aria-labelledby": "actions-button",
}}
anchorEl={anchorEl}
anchorOrigin={{
horizontal: "right",
vertical: "bottom",
}}
transformOrigin={{
horizontal: "right",
vertical: "top",
}}
open={isMenuOpen}
onClose={handleCloseActionsMenu}
slotProps={{
paper: {
className: "onroutebc-table-row-actions__paper",
},
}}
>
{options.map((option) => (
<MenuItem
key={`option-${option.value}`}
className="onroutebc-table-row-actions__menu-item"
onClick={onClickOption}
data-option-value={option.value}
>
{option.label}
</MenuItem>
))}
</Menu>
</div>
) : null
}
</>
);
};
8 changes: 6 additions & 2 deletions frontend/src/common/constants/bannerMessages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@ export const BANNER_MESSAGES = {
POLICY_REMINDER:
"The applicant is responsible for ensuring they are following Legislation, policies, standards and guidelines in the operation of a commercial transportation business in British Columbia.",
CANNOT_FIND_VEHICLE: "Can't find a vehicle from your inventory?",
ISSUED_PERMIT_NUMBER_7_YEARS: "Enter any Permit No. issued to the above Client No. in the last 7 years",
SELECT_VEHICLES_LOA: "Only vehicles in the Vehicle Inventory can be designated to LOA(s).",
ISSUED_PERMIT_NUMBER_7_YEARS:
"Enter any Permit No. issued to the above Client No. in the last 7 years",
SELECT_VEHICLES_LOA:
"Only vehicles in the Vehicle Inventory can be designated to LOA(s).",
SELECT_VEHICLES_LOA_INFO:
"If you do not see the vehicle(s) you wish to designate here, please make sure you add them to the client's Vehicle Inventory first and come back to this page.",
REJECTED_APPLICATIONS:
"Rejected applications appear in Applications in Progress.",
};
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ export const APPLICATIONS_API_ROUTES = {
DELETE: (companyId: string) => APPLICATIONS_API_BASE(companyId),
};

export const APPLICATION_QUEUE_API_ROUTES = {
UPDATE_QUEUE_STATUS: (companyId: string, applicationId: string) =>
`${APPLICATIONS_API_BASE(companyId)}/${applicationId}/queue/status`,
};

export const PERMITS_API_ROUTES = {
BASE: (companyId: string) => PERMITS_API_BASE(companyId),
GET: (companyId: string) => PERMITS_API_BASE(companyId),
Expand Down
54 changes: 50 additions & 4 deletions frontend/src/features/permits/apiManager/permitsAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import {
} from "../types/application";

import {
APPLICATION_QUEUE_API_ROUTES,
APPLICATIONS_API_ROUTES,
PAYMENT_API_ROUTES,
PERMITS_API_ROUTES,
Expand All @@ -63,6 +64,7 @@ import {
VoidPermitResponseData,
} from "../pages/Void/types/VoidPermit";
import { EmailNotificationType } from "../types/EmailNotificationType";
import { CaseActivityType } from "../types/CaseActivityType";

/**
* Create a new application.
Expand Down Expand Up @@ -116,17 +118,28 @@ const getApplications = async (
orderBy = [],
}: PaginationAndFilters,
pendingPermitsOnly?: boolean,
applicationsInQueueOnly?: boolean,
): Promise<PaginatedResponse<ApplicationListItem>> => {
const companyId = getDefaultRequiredVal("", getCompanyIdFromSession());
const applicationsURL = new URL(APPLICATIONS_API_ROUTES.GET(companyId));

// API pagination index starts at 1. Hence page + 1.
applicationsURL.searchParams.set("page", `${page + 1}`);
applicationsURL.searchParams.set("take", `${take}`);
applicationsURL.searchParams.set(
"pendingPermits",
`${Boolean(pendingPermitsOnly)}`,
);

if (typeof pendingPermitsOnly !== "undefined") {
applicationsURL.searchParams.set(
"pendingPermits",
`${Boolean(pendingPermitsOnly)}`,
);
}

if (typeof applicationsInQueueOnly !== "undefined") {
applicationsURL.searchParams.set(
"applicationsInQueue",
`${Boolean(applicationsInQueueOnly)}`,
);
}

if (searchString) {
applicationsURL.searchParams.set("searchString", searchString);
Expand Down Expand Up @@ -192,6 +205,16 @@ export const getPendingPermits = async (
return await getApplications(paginationFilters, true);
};

/**
* Fetch all applications in queue.
* @return A list of applications in queue (PENDING_REVIEW, IN_REVIEW)
*/
export const getApplicationsInQueue = async (
paginationFilters: PaginationAndFilters,
): Promise<PaginatedResponse<ApplicationListItem>> => {
return await getApplications(paginationFilters, undefined, true);
};

/**
* Fetch application by its permit id.
* @param permitId permit id of the application to fetch
Expand Down Expand Up @@ -615,3 +638,26 @@ export const resendPermit = async ({
replaceEmptyValuesWithNull(data),
);
};

export const updateApplicationQueueStatus = async (
applicationId: string,
caseActivityType: CaseActivityType,
comment?: string,
) => {
const companyId = getDefaultRequiredVal("", getCompanyIdFromSession());

const data: any = {
caseActivityType,
};

// Conditionally include the comment property if it is given as an argument and not an empty string
if (comment && comment.trim() !== "") {
data.comment = [comment];
}

const response = await httpPOSTRequest(
APPLICATION_QUEUE_API_ROUTES.UPDATE_QUEUE_STATUS(companyId, applicationId),
data,
);
return response;
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { StartApplicationAction } from "../../pages/Application/components/dashb
import { ActivePermitList } from "../permit-list/ActivePermitList";
import { ExpiredPermitList } from "../permit-list/ExpiredPermitList";
import { ApplicationsInProgressList } from "../permit-list/ApplicationsInProgressList";
import { ApplicationsInReviewList } from "../permit-list/ApplicationsInReviewList";
import { Nullable } from "../../../../common/types/common";
import { usePermissionMatrix } from "../../../../common/authentication/PermissionMatrix";
import { RenderIf } from "../../../../common/components/reusable/RenderIf";
Expand All @@ -16,12 +17,14 @@ export const PermitLists = React.memo(() => {
setApplicationsInProgressCount(count);
};
const tabs = [];

const showApplicationsInProgressTab = usePermissionMatrix({
permissionMatrixKeys: {
permissionMatrixFeatureKey: "MANAGE_PERMITS",
permissionMatrixFunctionKey: "VIEW_LIST_OF_APPLICATIONS_IN_PROGRESS",
},
});

if (showApplicationsInProgressTab) {
tabs.push({
label: "Applications in Progress",
Expand All @@ -33,6 +36,21 @@ export const PermitLists = React.memo(() => {
),
});
}

const showApplicationsInReviewTab = usePermissionMatrix({
permissionMatrixKeys: {
permissionMatrixFeatureKey: "MANAGE_PERMITS",
permissionMatrixFunctionKey: "VIEW_LIST_OF_APPLICATIONS_IN_REVIEW",
},
});

if (showApplicationsInReviewTab) {
tabs.push({
label: "Applications in Review",
component: <ApplicationsInReviewList />,
});
}

tabs.push(
{
label: "Active Permits",
Expand Down
Loading
Loading