fix
All checks were successful
Build And Deploy Main / build-and-deploy (push) Successful in 32s

This commit is contained in:
2026-03-11 14:08:34 -04:00
parent 3714a86422
commit e39f1c8fa1
10 changed files with 96 additions and 27 deletions

View File

@@ -8,7 +8,34 @@ import DashboardCustomersList from "../dashboard/DashboardCustomersList";
const CustomersList = () => {
const navigate = useNavigate();
const [customers, setCustomers] = useState([]);
const [columns] = useState([
const CUSTOMER_LIST_COLUMN_TAB_MAP = {
name: 'personalInfo',
chinese_name: 'personalInfo',
email: 'personalInfo',
type: 'careServices',
pickup_status: 'careServices',
birth_date: 'personalInfo',
gender: 'personalInfo',
language: 'personalInfo',
medicare_number: 'medicalInsurance',
medicaid_number: 'medicalInsurance',
address: 'personalInfo',
phone: 'personalInfo',
emergency_contact: 'medicalInsurance',
health_condition: 'medicalInsurance',
payment_status: 'careServices',
payment_due_date: 'careServices',
service_requirement: 'careServices',
tags: 'personalInfo'
};
const getVisibleColumnsByPermission = (columnList = []) => {
return columnList.filter((column) => {
const mappedTab = CUSTOMER_LIST_COLUMN_TAB_MAP[column.key];
if (!mappedTab) return true;
return AuthService.canViewCustomerTab(mappedTab);
});
};
const [columns] = useState(getVisibleColumnsByPermission([
{ key: 'name', label:'Name', show: true },
{ key: 'chinese_name', label: 'Preferred Name', show: true },
{ key: 'email', label: 'Email', show: true },
@@ -27,7 +54,7 @@ const CustomersList = () => {
{ key: 'payment_due_date', label: 'Payment Due Date', show: true },
{ key: 'service_requirement', label: 'Service Requirement', show: true },
{ key: 'tags', label: 'Tags', show: true }
]);
]));
useEffect(() => {
if (!AuthService.canViewCustomers()) {

View File

@@ -8,6 +8,29 @@ import { Spinner, Breadcrumb, BreadcrumbItem, Tabs, Tab, Dropdown, Modal } from
import { Columns, Download, Filter, PencilSquare, PersonSquare, Plus } from "react-bootstrap-icons";
const DashboardCustomersList = ({ additionalButtons, showBreadcrumb = false, title = null }) => {
const CUSTOMER_LIST_COLUMN_TAB_MAP = {
name: 'personalInfo',
chinese_name: 'personalInfo',
email: 'personalInfo',
type: 'careServices',
pickup_status: 'careServices',
birth_date: 'personalInfo',
gender: 'personalInfo',
language: 'personalInfo',
medicare_number: 'medicalInsurance',
medicaid_number: 'medicalInsurance',
address: 'personalInfo',
phone: 'personalInfo',
emergency_contact: 'medicalInsurance',
tags: 'personalInfo'
};
const getVisibleColumnsByPermission = (columnList = []) => {
return columnList.filter((column) => {
const mappedTab = CUSTOMER_LIST_COLUMN_TAB_MAP[column.key];
if (!mappedTab) return true;
return AuthService.canViewCustomerTab(mappedTab);
});
};
const navigate = useNavigate();
const dispatch = useDispatch();
const site = EventsService.site;
@@ -33,7 +56,7 @@ const DashboardCustomersList = ({ additionalButtons, showBreadcrumb = false, tit
const [avatarLoading, setAvatarLoading] = useState(false);
const [customerAvatars, setCustomerAvatars] = useState({});
const isAllCustomersPage = title === 'All Customers';
const [columns, setColumns] = useState([
const [columns, setColumns] = useState(getVisibleColumnsByPermission([
{
key: 'name',
label:'Name',
@@ -104,7 +127,11 @@ const DashboardCustomersList = ({ additionalButtons, showBreadcrumb = false, tit
label: 'Tags',
show: true
}
]);
]));
useEffect(() => {
setColumns((prevColumns) => getVisibleColumnsByPermission(prevColumns));
}, []);
useEffect(() => {
if (!AuthService.canViewCustomers()) {
@@ -257,7 +284,7 @@ const DashboardCustomersList = ({ additionalButtons, showBreadcrumb = false, tit
};
const handleColumnsChange = (newColumns) => {
setColumns(newColumns);
setColumns(getVisibleColumnsByPermission(newColumns));
}
const goToEdit = (id) => {

View File

@@ -139,7 +139,7 @@ const SideMenu = () => {
name: 'Templates',
link: '/trans-routes/daily-templates/list',
category: '/trans-routes/daily-templates',
roleFunc: AuthService.canViewRoutes
roleFunc: () => AuthService.canViewRouteTemplates() || AuthService.canEditRouteTemplates()
},
{
name: 'Appointment One-Day List',
@@ -194,7 +194,7 @@ const SideMenu = () => {
name: 'Template',
link: '/medical/template',
category: '/medical/template',
roleFunc: AuthService.canViewMedicalSection
roleFunc: AuthService.canViewMedicalTemplate
}
]
},

View File

@@ -22,7 +22,7 @@ const TemplateManager = () => {
};
useEffect(() => {
if (!AuthService.canViewMedicalSection()) {
if (!AuthService.canViewMedicalTemplate()) {
window.alert("You haven't login yet OR this user does not have access to this page. Please change an admin account to login.");
AuthService.logout();
navigate("/login");

View File

@@ -94,7 +94,7 @@ const Card = ({ content, index, moveCard }) => {
)
}
const RouteCustomerEditor = ({currentRoute, setNewCustomerList = (a) => {}, viewMode, editFun, onAddCustomer = null, scheduledAbsentCustomerIds = []}) => {
const RouteCustomerEditor = ({currentRoute, setNewCustomerList = (a) => {}, viewMode, editFun = () => {}, canEdit = true, onAddCustomer = null, scheduledAbsentCustomerIds = []}) => {
const [customers, setCustomers] = useState([]);
const [initializedRouteId, setInitializedRouteId] = useState(null);
const [showAddPersonnelModal, setShowAddPersonnelModal] = useState(false);
@@ -713,7 +713,7 @@ const RouteCustomerEditor = ({currentRoute, setNewCustomerList = (a) => {}, view
return (
<DndProvider backend={HTML5Backend}>
{ !viewMode && <h6 class="text-primary">Customers Assigned ({getCurrentAssignedNumber()})</h6>}
{ viewMode && <h6 class="text-primary">Route Assignment <button className="btn btn-sm btn-primary" onClick={() => editFun('assignment')}><Pencil size={16} className="me-2"></Pencil>Edit </button></h6>}
{ viewMode && <h6 class="text-primary">Route Assignment {canEdit && <button className="btn btn-sm btn-primary" onClick={() => editFun('assignment')}><Pencil size={16} className="me-2"></Pencil>Edit </button>}</h6>}
{!viewMode && <CustomersDropZone>
{customers.map((item, index) => {
if (item?.customers) {
@@ -763,7 +763,7 @@ const RouteCustomerEditor = ({currentRoute, setNewCustomerList = (a) => {}, view
if (item?.customers) {
return <div className="customers-dnd-item-container">
<div className="stop-index"><span>{`Stop ${index+1}`}</span><RecordCircleFill size={16} color={"#0066B1"} className="ms-2"></RecordCircleFill> </div>
<div className="customer-dnd-item" onClick={() => openEditAptGroupModal(index, item)}>
<div className="customer-dnd-item" onClick={() => canEdit && openEditAptGroupModal(index, item)} style={{ cursor: canEdit ? 'pointer' : 'default' }}>
<span className="me-2">{item.customer_group} </span> <span>{item.customers[0]?.customer_group_address}</span>
<div className="customer-dnd-item-content">{item.customers.map(customer =>
<div key={customer.customer_id}>

View File

@@ -60,6 +60,7 @@ const RouteView = () => {
};
const routeForStatusView = mergeRouteCustomerMeta(latestRouteForStatus || routeSnapshot || currentRoute);
const routeForAssignmentView = routeSnapshot || currentRoute;
const canEditRoutes = AuthService.canAddOrEditRoutes();
const closeModal = () => {
setShowVehicleDetails(false);
}
@@ -81,6 +82,7 @@ const RouteView = () => {
navigate(`/trans-routes/dashboard?dateSchedule=${moment(currentRoute?.schedule_date).format('YYYY-MM-DD')}`);
}
const edit = (editSection) => {
if (!canEditRoutes) return;
if (scheduleDate) {
navigate(`/trans-routes/edit/${currentRoute?.id}?dateSchedule=${scheduleDate}&editSection=${editSection}`)
} else {
@@ -227,7 +229,7 @@ const RouteView = () => {
<div className="app-main-content-list-func-container">
<Tabs defaultActiveKey="routeOverview" id="route-view-tab">
<Tab eventKey="routeOverview" title="Route Information">
<h6 className="text-primary">Route Details <button className="btn btn-sm btn-primary" onClick={() => edit('info')}><Pencil size={16} className="me-2"></Pencil>Edit </button></h6>
<h6 className="text-primary">Route Details {canEditRoutes && <button className="btn btn-sm btn-primary" onClick={() => edit('info')}><Pencil size={16} className="me-2"></Pencil>Edit </button>}</h6>
<div className="app-main-content-fields-section">
<div className="field-body">
<div className="field-label">Route Name</div>
@@ -299,7 +301,7 @@ const RouteView = () => {
{currentRoute && currentRoute?.checklist_result.length === 0 && <>No Checklist found</>}</div>
</div>
</div>
<RouteCustomerEditor currentRoute={routeForAssignmentView} viewMode={true} editFun={edit}></RouteCustomerEditor>
<RouteCustomerEditor currentRoute={routeForAssignmentView} viewMode={true} editFun={edit} canEdit={canEditRoutes}></RouteCustomerEditor>
</Tab>
<Tab eventKey="routeStatus" title="Route Status">
<div className="list row">
@@ -333,7 +335,7 @@ const RouteView = () => {
</div>
</div>
<div className="col-md-12 mb-4">
{routeForStatusView && <PersonnelSection transRoutes={[routeForStatusView]} showCompletedInfo={true} showGroupInfo={true} isInbound={routeForStatusView?.type === 'inbound' } allowForceEdit={AuthService.canViewRoutes()} sectionName="Personnel Status (click on each user to edit)" relatedOutbound={getRelatedOutboundRoutesForThisView()} vehicle={currentVehicle} driverName={resolvedDriverName} deleteFile={deleteFile} onRouteUpdated={refreshRouteStatusData}/>}
{routeForStatusView && <PersonnelSection transRoutes={[routeForStatusView]} showCompletedInfo={true} showGroupInfo={true} isInbound={routeForStatusView?.type === 'inbound' } allowForceEdit={canEditRoutes} sectionName="Personnel Status (click on each user to edit)" relatedOutbound={getRelatedOutboundRoutesForThisView()} vehicle={currentVehicle} driverName={resolvedDriverName} deleteFile={deleteFile} onRouteUpdated={refreshRouteStatusData}/>}
</div>
</div>
</Tab>

View File

@@ -66,7 +66,7 @@ const RoutesHistory = () => {
</div>
<div className="list row">
<div className="col-md-12 mb-4">
<PersonnelSection transRoutes={allRoutes} showCompletedInfo={false} showGroupInfo={false} allowForceEdit={AuthService.canViewRoutes()} showFilter={true} sectionName="Personnel Status (click on each user to edit)"/>
<PersonnelSection transRoutes={allRoutes} showCompletedInfo={false} showGroupInfo={false} allowForceEdit={AuthService.canAddOrEditRoutes()} showFilter={true} sectionName="Personnel Status (click on each user to edit)"/>
</div>
</div>
</>

View File

@@ -1,7 +1,7 @@
import React, {useState, useEffect} from "react";
import { useParams, useNavigate } from "react-router-dom";
import { useSelector } from "react-redux";
import { DailyRoutesTemplateService } from "../../services";
import { AuthService, DailyRoutesTemplateService } from "../../services";
import { Breadcrumb, Modal, Button, Spinner } from "react-bootstrap";
import { PencilSquare, Trash } from "react-bootstrap-icons";
import RoutesSection from "./RoutesSection";
@@ -20,6 +20,7 @@ const ViewDailyTemplate = () => {
const [newName, setNewName] = useState('');
const [saving, setSaving] = useState(false);
const [deleting, setDeleting] = useState(false);
const canEditTemplateRoutes = AuthService.canEditRouteTemplates();
useEffect(() => {
fetchTemplate();
@@ -44,6 +45,7 @@ const ViewDailyTemplate = () => {
};
const openEditNameModal = () => {
if (!canEditTemplateRoutes) return;
setShowEditNameModal(true);
};
@@ -77,6 +79,7 @@ const ViewDailyTemplate = () => {
};
const confirmDelete = () => {
if (!canEditTemplateRoutes) return;
setShowDeleteModal(true);
};
@@ -93,6 +96,7 @@ const ViewDailyTemplate = () => {
};
const goToCreateRoute = (type) => {
if (!canEditTemplateRoutes) return;
navigate(`/trans-routes/daily-templates/${params.id}/create-route?type=${type}`);
};
@@ -121,16 +125,16 @@ const ViewDailyTemplate = () => {
<div className="col-md-12 text-primary">
<h4>
{template.name}
<PencilSquare
{canEditTemplateRoutes && <PencilSquare
size={20}
className="clickable ms-2"
onClick={openEditNameModal}
title="Edit template name"
/>
/>}
<button className="btn btn-link btn-sm" onClick={goBack}>Back to List</button>
<button className="btn btn-danger btn-sm ms-2" onClick={confirmDelete}>
{canEditTemplateRoutes && <button className="btn btn-danger btn-sm ms-2" onClick={confirmDelete}>
<Trash size={14} className="me-1" />Delete Template
</button>
</button>}
</h4>
<div className="text-muted">
<small>Template Date: {template.template_date} | Created by: {template.create_by}</small>
@@ -149,7 +153,7 @@ const ViewDailyTemplate = () => {
onRouteClick={handleRouteClick}
isTemplate={true}
templateId={params.id}
canAddNew={true}
canAddNew={canEditTemplateRoutes}
addText="+Add Route"
redirect={goToCreateRoute}
routeType="inbound"
@@ -165,7 +169,7 @@ const ViewDailyTemplate = () => {
onRouteClick={handleRouteClick}
isTemplate={true}
templateId={params.id}
canAddNew={true}
canAddNew={canEditTemplateRoutes}
addText="+Add Route"
redirect={goToCreateRoute}
routeType="outbound"

View File

@@ -1,7 +1,7 @@
import React, {useState, useEffect} from "react";
import { useSelector } from "react-redux";
import { useParams, useNavigate } from "react-router-dom";
import { DailyRoutesTemplateService } from "../../services";
import { AuthService, DailyRoutesTemplateService } from "../../services";
import { selectAllActiveDrivers, selectAllActiveVehicles } from "./../../store";
import { Breadcrumb, Spinner, Modal, Button } from "react-bootstrap";
import { Pencil, Trash } from "react-bootstrap-icons";
@@ -16,6 +16,7 @@ const ViewDailyTemplateRoute = () => {
const [currentRoute, setCurrentRoute] = useState(null);
const [showDeleteModal, setShowDeleteModal] = useState(false);
const [deleting, setDeleting] = useState(false);
const canEditTemplateRoutes = AuthService.canEditRouteTemplates();
const currentVehicle = vehicles.find(item => item.id === currentRoute?.vehicle);
const currentDriver = drivers.find(item => item.id === currentRoute?.driver);
@@ -37,10 +38,12 @@ const ViewDailyTemplateRoute = () => {
};
const goToEdit = () => {
if (!canEditTemplateRoutes) return;
navigate(`/trans-routes/daily-templates/${params.id}/update-route/${params.routeId}`);
};
const confirmDelete = () => {
if (!canEditTemplateRoutes) return;
setShowDeleteModal(true);
};
@@ -125,14 +128,14 @@ const ViewDailyTemplateRoute = () => {
</div>
<div className="mt-4">
<button className="btn btn-primary me-2" onClick={goToEdit}>
{canEditTemplateRoutes && <button className="btn btn-primary me-2" onClick={goToEdit}>
<Pencil size={16} className="me-2" />
Update Route
</button>
<button className="btn btn-danger" onClick={confirmDelete}>
</button>}
{canEditTemplateRoutes && <button className="btn btn-danger" onClick={confirmDelete}>
<Trash size={16} className="me-2" />
Delete Route
</button>
</button>}
</div>
</div>
@@ -140,6 +143,7 @@ const ViewDailyTemplateRoute = () => {
currentRoute={currentRoute}
viewMode={true}
editFun={() => goToEdit()}
canEdit={canEditTemplateRoutes}
/>
</div>

View File

@@ -194,6 +194,10 @@ const canEditAppointmentRequests = () => {
return hasPermission('Edit & Create_Appointment Request');
}
const canViewMedicalTemplate = () => {
return hasPermission('Medical Template');
}
const canViewMedicalEvents = () => {
return hasAnyPermission([
'View _Calendar _Medical Appointment',
@@ -365,6 +369,7 @@ export const AuthService = {
canEditProviderInfo,
canViewAppointmentRequests,
canEditAppointmentRequests,
canViewMedicalTemplate,
canViewMedicalEvents,
canEditMedicalEvents,
canViewMealStatus,