This commit is contained in:
@@ -3,6 +3,73 @@ const Employee = db.employee;
|
||||
|
||||
var bcrypt = require("bcryptjs");
|
||||
const { splitSite } = require("../middlewares");
|
||||
|
||||
const ALL_PERMISSIONS = [
|
||||
'Dashboard',
|
||||
'Admin View',
|
||||
'View_Info Screen',
|
||||
'Edit_Info Screen',
|
||||
'View_Customer Info _Personal Info',
|
||||
'View_Customer Info _Care & Services',
|
||||
'View_Customer Info _Medical & Insurance',
|
||||
'View_Customer Info _Confidential Details',
|
||||
'View_Customer Info _Form Submission',
|
||||
'Edit_Customer Info _ Personal Info',
|
||||
'Edit_Customer Info _ Care & Services',
|
||||
'Edit_Customer Info _ Medical & Insurance',
|
||||
'Edit_Customer Info _ Confidential Details',
|
||||
'Edit_Customer Info _ Form Submission',
|
||||
'Discharge_Customer',
|
||||
'Reactivate_Customer',
|
||||
'Create_Customer',
|
||||
'Export_Customer Report',
|
||||
'View _Calendar _Medical Appointment',
|
||||
'View _Calendar _Activities',
|
||||
'View _Calendar _Attendance Notes',
|
||||
'View _Calendar _Meal Plan',
|
||||
'View _Calendar _Important Dates',
|
||||
'Edit&Create _Calendar _Medical Appointment',
|
||||
'Edit&Create _Calendar _Activities',
|
||||
'Edit&Create _Calendar _Attendance Notes',
|
||||
'Edit&Create _Calendar _Meal Plan',
|
||||
'Edit&Create _Calendar _Important Dates',
|
||||
'View_Messaging',
|
||||
'Sent_Messaging',
|
||||
'View_Messaging Template',
|
||||
'Create&Edit_Messaging Template',
|
||||
'View_Vehicle info_Basic Info',
|
||||
'View_Vehicle info_Documents',
|
||||
'View_Vehicle info_Repair Records',
|
||||
'Edit_Vehicle info_Basic Info',
|
||||
'Edit_Vehicle info_Documents',
|
||||
'Edit_Vehicle info_Repair Records',
|
||||
'Add_New Vehicle',
|
||||
'Archive_Vehicle',
|
||||
'Delete_Vehicle',
|
||||
'Export_Vehicle Report',
|
||||
'View_Transportation Schedule_Route Overview',
|
||||
'Create&Edit_Transportation Schedule',
|
||||
'Export_Transportation Schedule Report',
|
||||
'View_Route Template',
|
||||
'Create&Edit_Route Template',
|
||||
'View_Driver Assignment for Appointment',
|
||||
'Edit_Driver Assignment for Appointment',
|
||||
'View_Provider Info',
|
||||
'Create & Edit _Provider Info',
|
||||
'View_Appointment Request',
|
||||
'Edit & Create_Appointment Request',
|
||||
'View_Appointment Calendar',
|
||||
'Edit & Create_Appointment Calendar',
|
||||
'Medical Template',
|
||||
'View_Meal Status',
|
||||
'Edit_Meal Status',
|
||||
'View_Seating Chart',
|
||||
'Edit_Seating Chart',
|
||||
'Employee page',
|
||||
'Set Permission for Employee'
|
||||
];
|
||||
|
||||
const hasAllPermissionsByUsername = (username) => (username || '').toString().trim().toLowerCase() === 'testadmin03';
|
||||
// Create and Save a new Employee (driver, distributor, admin)
|
||||
exports.createEmployee = (req, res) => {
|
||||
// Validate request
|
||||
@@ -11,13 +78,16 @@ exports.createEmployee = (req, res) => {
|
||||
return;
|
||||
}
|
||||
const site = splitSite.findSiteNumber(req);
|
||||
const normalizedUsername = req.body.username || req.body.email || '';
|
||||
const requestPermissions = Array.isArray(req.body.permissions) ? req.body.permissions : [];
|
||||
// Create a Employee
|
||||
const employee = new Employee({
|
||||
username: req.body.username || req.body.email || '',
|
||||
username: normalizedUsername,
|
||||
name_cn: req.body.name_cn || '',
|
||||
email: req.body.email || '',
|
||||
password: req.body.password ? bcrypt.hashSync(req.body.password, 8) : '',
|
||||
roles: req.body.roles || [],
|
||||
permissions: hasAllPermissionsByUsername(normalizedUsername) ? ALL_PERMISSIONS : requestPermissions,
|
||||
mobile_phone: req.body.mobile_phone || '',
|
||||
home_phone: req.body.home_phone || '',
|
||||
language: req.body.language || '',
|
||||
@@ -204,13 +274,24 @@ exports.updateEmployee = (req, res) => {
|
||||
if (req.body.password) {
|
||||
req.body.password = bcrypt.hashSync(req.body.password, 8);
|
||||
}
|
||||
Employee.findByIdAndUpdate(id, req.body, { useFindAndModify: false })
|
||||
.then(data => {
|
||||
if (!data) {
|
||||
Employee.findById(id)
|
||||
.then((existingEmployee) => {
|
||||
if (!existingEmployee) {
|
||||
res.status(404).send({
|
||||
message: `Cannot update employee with id=${id}. Maybe Employee was not found!`
|
||||
});
|
||||
} else res.send({ success: true, message: "Employee was updated successfully." });
|
||||
return null;
|
||||
}
|
||||
const nextData = Object.assign({}, req.body);
|
||||
const effectiveUsername = nextData.username || existingEmployee.username;
|
||||
if (hasAllPermissionsByUsername(effectiveUsername)) {
|
||||
nextData.permissions = ALL_PERMISSIONS;
|
||||
}
|
||||
return Employee.findByIdAndUpdate(id, nextData, { useFindAndModify: false });
|
||||
})
|
||||
.then((data) => {
|
||||
if (!data) return;
|
||||
res.send({ success: true, message: "Employee was updated successfully." });
|
||||
})
|
||||
.catch(err => {
|
||||
res.status(500).send({
|
||||
|
||||
@@ -8,6 +8,9 @@ module.exports = mongoose => {
|
||||
roles: [{
|
||||
type: String
|
||||
}],
|
||||
permissions: [{
|
||||
type: String
|
||||
}],
|
||||
mobile_phone: String,
|
||||
home_phone: String,
|
||||
language: String,
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useNavigate, useParams } from "react-router-dom";
|
||||
import { driverSlice } from "./../../store";
|
||||
import { employeeSlice } from "../../store/employees";
|
||||
import { AuthService, EmployeeService } from "../../services";
|
||||
import { EMPLOYEE_TITLE, EMPLOYEE_TITLE_CN, EMPLOYEE_TITLE_ROLES_MAP } from "../../shared";
|
||||
import { EMPLOYEE_TITLE, EMPLOYEE_TITLE_CN, EMPLOYEE_PERMISSION_GROUPS, EMPLOYEE_ALL_PERMISSIONS } from "../../shared";
|
||||
import { Modal, Button } from "react-bootstrap";
|
||||
|
||||
const UpdateEmployee = () => {
|
||||
@@ -21,7 +21,7 @@ const UpdateEmployee = () => {
|
||||
const [lastname, setLastname] = useState('');
|
||||
const [nameCN, setNameCN] = useState('');
|
||||
const [birthDate, setBirthDate] = useState('');
|
||||
const [roles, setRoles] = useState('');
|
||||
const [permissions, setPermissions] = useState([]);
|
||||
const [email, setEmail] = useState('');
|
||||
const [driverCapacity, setDriverCapacity] = useState();
|
||||
const [mobilePhone, setMobilePhone] = useState('');
|
||||
@@ -39,6 +39,8 @@ const UpdateEmployee = () => {
|
||||
const [tags, setTags] = useState('');
|
||||
const [showDeleteModal, setShowDeleteModal] = useState(false);
|
||||
const [selectedFile, setSelectedFile] = useState();
|
||||
const isAlwaysAllPermissionsUser = (value) => (value || '').toString().trim().toLowerCase() === 'testadmin03';
|
||||
const isSuperPermissionLocked = isAlwaysAllPermissionsUser(username || currentEmployee?.username);
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const redirectTo = () => {
|
||||
const redirect = params.get('redirect');
|
||||
@@ -74,7 +76,12 @@ const UpdateEmployee = () => {
|
||||
setLastname(currentEmployee.lastname);
|
||||
setNameCN(currentEmployee.name_cn);
|
||||
setBirthDate(currentEmployee.birth_date);
|
||||
setRoles(currentEmployee.roles.join(','));
|
||||
const currentPermissions = Array.isArray(currentEmployee.permissions) ? currentEmployee.permissions : [];
|
||||
setPermissions(
|
||||
isAlwaysAllPermissionsUser(currentEmployee.username)
|
||||
? EMPLOYEE_ALL_PERMISSIONS
|
||||
: currentPermissions
|
||||
);
|
||||
setEmail(currentEmployee.email);
|
||||
setDriverCapacity(currentEmployee.driver_capacity);
|
||||
setMobilePhone(currentEmployee.mobile_phone);
|
||||
@@ -98,14 +105,22 @@ const UpdateEmployee = () => {
|
||||
if (value) {
|
||||
setTitle(value);
|
||||
setTitleCN(EMPLOYEE_TITLE_CN[value]);
|
||||
setRoles(EMPLOYEE_TITLE_ROLES_MAP[value]?.join(','));
|
||||
} else {
|
||||
setTitle('');
|
||||
setTitleCN('');
|
||||
setRoles('');
|
||||
}
|
||||
}
|
||||
|
||||
const togglePermission = (permissionKey) => {
|
||||
if (isSuperPermissionLocked) return;
|
||||
setPermissions((prevPermissions) => {
|
||||
if (prevPermissions.includes(permissionKey)) {
|
||||
return prevPermissions.filter((permission) => permission !== permissionKey);
|
||||
}
|
||||
return [...prevPermissions, permissionKey];
|
||||
});
|
||||
};
|
||||
|
||||
const triggerShowDeleteModal = () => {
|
||||
setShowDeleteModal(true);
|
||||
}
|
||||
@@ -135,7 +150,7 @@ const UpdateEmployee = () => {
|
||||
edit_by: 'admin',
|
||||
note,
|
||||
tags: tags.replace(' ', '').split(','),
|
||||
roles: roles && roles.replace(' ', '').split(',')
|
||||
permissions: isAlwaysAllPermissionsUser(username) ? EMPLOYEE_ALL_PERMISSIONS : permissions
|
||||
};
|
||||
if (password && password.length > 0) {
|
||||
data = Object.assign({}, data, {password});
|
||||
@@ -174,7 +189,7 @@ const UpdateEmployee = () => {
|
||||
edit_by: 'admin',
|
||||
note,
|
||||
tags: tags.replace(' ', '').split(','),
|
||||
roles: roles && roles.replace(' ', '').split(','),
|
||||
permissions: isAlwaysAllPermissionsUser(username) ? EMPLOYEE_ALL_PERMISSIONS : permissions,
|
||||
status
|
||||
};
|
||||
if (password && password.length > 0) {
|
||||
@@ -255,9 +270,6 @@ const UpdateEmployee = () => {
|
||||
<div className="col-md-4 mb-4">
|
||||
<div>Title CN(中文称谓):</div> <input type="text" value={titleCN || ''} onChange={e => setTitleCN(e.target.value)}/>
|
||||
</div>
|
||||
<div className="col-md-4 mb-4">
|
||||
<div>Roles:(*)</div> <input type="text" value={roles || ''} onChange={e => setRoles(e.target.value)}/>
|
||||
</div>
|
||||
<div className="col-md-4 mb-4">
|
||||
<div>Email:(*)</div> <input type="email" value={email || ''} onChange={e => setEmail(e.target.value)}/>
|
||||
</div>
|
||||
@@ -306,6 +318,34 @@ const UpdateEmployee = () => {
|
||||
onChange={(e) => setSelectedFile(e.target.files[0])}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="col-md-12 mb-4">
|
||||
<div className="fw-bold mb-2">Permissions</div>
|
||||
{isSuperPermissionLocked && (
|
||||
<div className="text-muted mb-2">
|
||||
testAdmin03 always has all permissions.
|
||||
</div>
|
||||
)}
|
||||
{Object.entries(EMPLOYEE_PERMISSION_GROUPS).map(([groupName, permissionItems]) => (
|
||||
<div key={groupName} className="mb-3">
|
||||
<div className="text-primary mb-1">{groupName}</div>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '10px 18px' }}>
|
||||
{permissionItems.map((permissionKey) => (
|
||||
<label key={permissionKey} style={{ minWidth: '280px' }}>
|
||||
<input
|
||||
type="checkbox"
|
||||
className="me-2"
|
||||
checked={isSuperPermissionLocked || permissions.includes(permissionKey)}
|
||||
onChange={() => togglePermission(permissionKey)}
|
||||
disabled={isSuperPermissionLocked}
|
||||
/>
|
||||
{permissionKey}
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="list row mb-5">
|
||||
<div className="col-md-6 col-sm-6 col-xs-12">
|
||||
|
||||
@@ -393,6 +393,10 @@ const RouteCustomerEditor = ({currentRoute, setNewCustomerList = (a) => {}, view
|
||||
}))
|
||||
}
|
||||
|
||||
const removeGroupedCustomerFromSelection = (id) => {
|
||||
setNewRouteGroupedCustomerList((prevList) => prevList.filter((item) => item.customer_id !== id));
|
||||
}
|
||||
|
||||
const setNewGroupNameAction = (value) => {
|
||||
setNewGroupName(value);
|
||||
for (const item of newRouteGroupedCustomerList) {
|
||||
@@ -937,6 +941,36 @@ const RouteCustomerEditor = ({currentRoute, setNewCustomerList = (a) => {}, view
|
||||
<input type="text" value={newGroupAddress} onChange={(e) => setNewGroupAddressAction(e.target.value)}/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="app-main-content-fields-section">
|
||||
<div className="me-4" style={{ width: '100%' }}>
|
||||
<div className="field-label">Selected Customers ({newRouteGroupedCustomerList.length})</div>
|
||||
{newRouteGroupedCustomerList.length === 0 ? (
|
||||
<small className="text-muted">No customer selected yet.</small>
|
||||
) : (
|
||||
<div className="customers-container" style={{ maxHeight: '180px', overflowY: 'auto', padding: '8px' }}>
|
||||
{newRouteGroupedCustomerList.map((customer) => (
|
||||
<div
|
||||
key={`selected-group-customer-${customer.customer_id}`}
|
||||
className="d-flex align-items-center justify-content-between mb-2"
|
||||
style={{ gap: '12px' }}
|
||||
>
|
||||
<div>
|
||||
<div><small>{customer.customer_name}</small></div>
|
||||
<div><small className="text-muted">{customer.customer_address}</small></div>
|
||||
</div>
|
||||
<Button
|
||||
variant="outline-danger"
|
||||
size="sm"
|
||||
onClick={() => removeGroupedCustomerFromSelection(customer.customer_id)}
|
||||
>
|
||||
Delete
|
||||
</Button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="app-main-content-fields-section">
|
||||
<div className="me-4">
|
||||
<div className="field-label">Type in user Id or Name to Search
|
||||
|
||||
@@ -125,6 +125,94 @@ export const EMPLOYEE_TITLE_ROLES_MAP = {
|
||||
|
||||
export const INVITATION_CODE = ['ws5801care', 'world911street'];
|
||||
|
||||
export const EMPLOYEE_PERMISSION_GROUPS = {
|
||||
Dashboard: [
|
||||
'Dashboard',
|
||||
'Admin View'
|
||||
],
|
||||
InfoScreen: [
|
||||
'View_Info Screen',
|
||||
'Edit_Info Screen'
|
||||
],
|
||||
CustomerInfo: [
|
||||
'View_Customer Info _Personal Info',
|
||||
'View_Customer Info _Care & Services',
|
||||
'View_Customer Info _Medical & Insurance',
|
||||
'View_Customer Info _Confidential Details',
|
||||
'View_Customer Info _Form Submission',
|
||||
'Edit_Customer Info _ Personal Info',
|
||||
'Edit_Customer Info _ Care & Services',
|
||||
'Edit_Customer Info _ Medical & Insurance',
|
||||
'Edit_Customer Info _ Confidential Details',
|
||||
'Edit_Customer Info _ Form Submission',
|
||||
'Discharge_Customer',
|
||||
'Reactivate_Customer',
|
||||
'Create_Customer',
|
||||
'Export_Customer Report'
|
||||
],
|
||||
Calendar: [
|
||||
'View _Calendar _Medical Appointment',
|
||||
'View _Calendar _Activities',
|
||||
'View _Calendar _Attendance Notes',
|
||||
'View _Calendar _Meal Plan',
|
||||
'View _Calendar _Important Dates',
|
||||
'Edit&Create _Calendar _Medical Appointment',
|
||||
'Edit&Create _Calendar _Activities',
|
||||
'Edit&Create _Calendar _Attendance Notes',
|
||||
'Edit&Create _Calendar _Meal Plan',
|
||||
'Edit&Create _Calendar _Important Dates'
|
||||
],
|
||||
Messaging: [
|
||||
'View_Messaging',
|
||||
'Sent_Messaging',
|
||||
'View_Messaging Template',
|
||||
'Create&Edit_Messaging Template'
|
||||
],
|
||||
Vehicle: [
|
||||
'View_Vehicle info_Basic Info',
|
||||
'View_Vehicle info_Documents',
|
||||
'View_Vehicle info_Repair Records',
|
||||
'Edit_Vehicle info_Basic Info',
|
||||
'Edit_Vehicle info_Documents',
|
||||
'Edit_Vehicle info_Repair Records',
|
||||
'Add_New Vehicle',
|
||||
'Archive_Vehicle',
|
||||
'Delete_Vehicle',
|
||||
'Export_Vehicle Report'
|
||||
],
|
||||
Transportation: [
|
||||
'View_Transportation Schedule_Route Overview',
|
||||
'Create&Edit_Transportation Schedule',
|
||||
'Export_Transportation Schedule Report',
|
||||
'View_Route Template',
|
||||
'Create&Edit_Route Template',
|
||||
'View_Driver Assignment for Appointment',
|
||||
'Edit_Driver Assignment for Appointment'
|
||||
],
|
||||
Medical: [
|
||||
'View_Provider Info',
|
||||
'Create & Edit _Provider Info',
|
||||
'View_Appointment Request',
|
||||
'Edit & Create_Appointment Request',
|
||||
'View_Appointment Calendar',
|
||||
'Edit & Create_Appointment Calendar',
|
||||
'Medical Template'
|
||||
],
|
||||
Lobby: [
|
||||
'View_Meal Status',
|
||||
'Edit_Meal Status',
|
||||
'View_Seating Chart',
|
||||
'Edit_Seating Chart'
|
||||
],
|
||||
EmployeeManagement: [
|
||||
'Employee page',
|
||||
'Set Permission for Employee'
|
||||
]
|
||||
};
|
||||
|
||||
export const EMPLOYEE_ALL_PERMISSIONS = Object.values(EMPLOYEE_PERMISSION_GROUPS)
|
||||
.reduce((allPermissions, groupPermissions) => allPermissions.concat(groupPermissions), []);
|
||||
|
||||
// // Test Site 01
|
||||
// export const LEGACY_LINK = (window.location.hostname.includes('worldshine2.mayo.llc') || window.location.hostname.includes('site2')) ? 'http://worldshineretro2.mayo.llc/staff/login?user=bxia' : ((window.location.hostname.includes('worldshine3.mayo.llc') || window.location.hostname.includes('site3')) ? 'http://worldshineretro3.mayo.llc/staff/login?user=bxia': 'http://worldshineretro.mayo.llc/staff/login?user=leapon');
|
||||
// export const LEGACY_LINK = (window.location.hostname.includes('ws2') || window.location.hostname.includes('site2')) ? 'http://wsretro2.mayosolution.com/staff/login?user=bxia' : ((window.location.hostname.includes('ws3') || window.location.hostname.includes('site3')) ? 'http://wsretro3.mayosolution.com/staff/login?user=bxia': 'http://wsretro1.mayosolution.com/staff/login?user=leapon');
|
||||
|
||||
Reference in New Issue
Block a user