mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 23:28:11 +00:00
Merge pull request #51 from Tria-plc/freight/rule_engine_ui
Freight/rule engine UI
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import { Navigate, Outlet, Route, Routes, useLocation, useNavigate } from "react-router-dom";
|
import { Navigate, Outlet, Route, Routes, useLocation, useNavigate } from "react-router-dom";
|
||||||
import { DashboardLayout, type SidebarItem } from "@edr/ui-common";
|
import { DashboardLayout, type SidebarItem } from "@edr/ui-common";
|
||||||
import { LayoutDashboard, Network } from "lucide-react";
|
import { LayoutDashboard, Network, Settings } from "lucide-react";
|
||||||
|
|
||||||
import { useAuth } from "./auth/useAuth";
|
import { useAuth } from "./auth/useAuth";
|
||||||
import LoginPage from "./pages/auth/LoginPage";
|
import LoginPage from "./pages/auth/LoginPage";
|
||||||
@@ -10,6 +10,7 @@ import PermissionsPage from "./pages/dashboard/user-management/PermissionsPage";
|
|||||||
import RolesPage from "./pages/dashboard/user-management/RolesPage";
|
import RolesPage from "./pages/dashboard/user-management/RolesPage";
|
||||||
import UserManagementPage from "./pages/dashboard/user-management/UserManagementPage";
|
import UserManagementPage from "./pages/dashboard/user-management/UserManagementPage";
|
||||||
import LoadingScreen from "./components/LoadingScreen";
|
import LoadingScreen from "./components/LoadingScreen";
|
||||||
|
import { RuleEnginePage } from "./pages/ruleEngine/RuleEngine";
|
||||||
|
|
||||||
const sidebarItems: SidebarItem[] = [
|
const sidebarItems: SidebarItem[] = [
|
||||||
{
|
{
|
||||||
@@ -36,6 +37,11 @@ const sidebarItems: SidebarItem[] = [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: "Rule Engine",
|
||||||
|
href: "/dashboard/rule-engine",
|
||||||
|
icon: <Settings />,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const DashboardShell = () => {
|
const DashboardShell = () => {
|
||||||
@@ -84,9 +90,13 @@ const App = () => {
|
|||||||
<Route path="/dashboard" element={<DashboardShell />}>
|
<Route path="/dashboard" element={<DashboardShell />}>
|
||||||
<Route path="overview" element={<OverviewPage />} />
|
<Route path="overview" element={<OverviewPage />} />
|
||||||
<Route path="user-management" element={<UserManagementPage />} />
|
<Route path="user-management" element={<UserManagementPage />} />
|
||||||
|
|
||||||
|
<Route path="rule-engine" element={<RuleEnginePage />} />
|
||||||
|
|
||||||
<Route path="user-management/employees" element={<EmployeesPage />} />
|
<Route path="user-management/employees" element={<EmployeesPage />} />
|
||||||
<Route path="user-management/permissions" element={<PermissionsPage />} />
|
<Route path="user-management/permissions" element={<PermissionsPage />} />
|
||||||
<Route path="user-management/roles" element={<RolesPage />} />
|
<Route path="user-management/roles" element={<RolesPage />} />
|
||||||
|
|
||||||
<Route path="org-structure" element={<Navigate to="/dashboard/user-management" replace />} />
|
<Route path="org-structure" element={<Navigate to="/dashboard/user-management" replace />} />
|
||||||
<Route path="org-structure/*" element={<Navigate to="/dashboard/user-management" replace />} />
|
<Route path="org-structure/*" element={<Navigate to="/dashboard/user-management" replace />} />
|
||||||
</Route>
|
</Route>
|
||||||
|
|||||||
@@ -0,0 +1,221 @@
|
|||||||
|
import { JSXElementConstructor, MouseEventHandler, ReactElement, ReactNode, SetStateAction, useState } from 'react';
|
||||||
|
|
||||||
|
export const ContractTypePage = () => {
|
||||||
|
const [expandedSections, setExpandedSections] = useState({
|
||||||
|
contractType: true,
|
||||||
|
serviceType: false,
|
||||||
|
cargoType: false
|
||||||
|
});
|
||||||
|
|
||||||
|
const [contractTypes, setContractTypes] = useState([
|
||||||
|
{ id: 1, name: 'Shipper', description: 'Company that sends the freight' },
|
||||||
|
{ id: 2, name: 'Consignee', description: 'Company that receives the freight' },
|
||||||
|
{ id: 3, name: 'Third Party', description: 'Company that is neither the shipper nor the consignee but is involved in the freight process' }
|
||||||
|
]);
|
||||||
|
|
||||||
|
const [serviceTypes, setServiceTypes] = useState([
|
||||||
|
{ id: 1, name: 'Standard', description: 'Regular shipping service' },
|
||||||
|
{ id: 2, name: 'Express', description: 'Fast delivery service' },
|
||||||
|
{ id: 3, name: 'Economy', description: 'Cost-effective shipping option' }
|
||||||
|
]);
|
||||||
|
|
||||||
|
const [cargoTypes, setCargoTypes] = useState([
|
||||||
|
{ id: 1, name: 'General Cargo', description: 'Standard packaged goods' },
|
||||||
|
{ id: 2, name: 'Temperature Controlled', description: 'Goods requiring specific temperature' },
|
||||||
|
{ id: 3, name: 'Hazardous Materials', description: 'Dangerous goods requiring special handling' }
|
||||||
|
]);
|
||||||
|
|
||||||
|
const [newContractType, setNewContractType] = useState({ name: '', description: '' });
|
||||||
|
const [newServiceType, setNewServiceType] = useState({ name: '', description: '' });
|
||||||
|
const [newCargoType, setNewCargoType] = useState({ name: '', description: '' });
|
||||||
|
const [showAddForms, setShowAddForms] = useState({
|
||||||
|
contractType: false,
|
||||||
|
serviceType: false,
|
||||||
|
|
||||||
|
cargoType: false
|
||||||
|
});
|
||||||
|
|
||||||
|
type SectionKey = 'contractType' | 'serviceType' | 'cargoType';
|
||||||
|
|
||||||
|
const toggleSection = (section: SectionKey) => {
|
||||||
|
setExpandedSections(prev => ({
|
||||||
|
...prev,
|
||||||
|
[section]: !prev[section]
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const toggleAddForm = (section: SectionKey) => {
|
||||||
|
setShowAddForms(prev => ({
|
||||||
|
...prev,
|
||||||
|
[section]: !prev[section]
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleAddContractType = () => {
|
||||||
|
if (newContractType.name && newContractType.description) {
|
||||||
|
setContractTypes([
|
||||||
|
...contractTypes,
|
||||||
|
{ id: Date.now(), ...newContractType }
|
||||||
|
]);
|
||||||
|
setNewContractType({ name: '', description: '' });
|
||||||
|
toggleAddForm('contractType');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleAddServiceType = () => {
|
||||||
|
if (newServiceType.name && newServiceType.description) {
|
||||||
|
setServiceTypes([
|
||||||
|
...serviceTypes,
|
||||||
|
{ id: Date.now(), ...newServiceType }
|
||||||
|
]);
|
||||||
|
setNewServiceType({ name: '', description: '' });
|
||||||
|
toggleAddForm('serviceType');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleAddCargoType = () => {
|
||||||
|
if (newCargoType.name && newCargoType.description) {
|
||||||
|
setCargoTypes([
|
||||||
|
...cargoTypes,
|
||||||
|
{ id: Date.now(), ...newCargoType }
|
||||||
|
]);
|
||||||
|
setNewCargoType({ name: '', description: '' });
|
||||||
|
toggleAddForm('cargoType');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDelete = (type: string, id: number) => {
|
||||||
|
if (type === 'contract') {
|
||||||
|
setContractTypes(contractTypes.filter(item => item.id !== id));
|
||||||
|
} else if (type === 'service') {
|
||||||
|
setServiceTypes(serviceTypes.filter(item => item.id !== id));
|
||||||
|
} else if (type === 'cargo') {
|
||||||
|
setCargoTypes(cargoTypes.filter(item => item.id !== id));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleEdit = (type: any, id: any) => {
|
||||||
|
// Implement edit functionality as needed
|
||||||
|
alert(`Edit ${type} type with id: ${id}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderTable = (title: string | number | boolean | ReactElement<any, string | JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined, types: any[], onAdd: { (): void; (): void; (): void; }, newItem: { name: any; description: any; }, setNewItem: { (value: SetStateAction<{ name: string; description: string; }>): void; (value: SetStateAction<{ name: string; description: string; }>): void; (value: SetStateAction<{ name: string; description: string; }>): void; (arg0: any): void; }, showAddForm: boolean, typeKey: string, addHandler: MouseEventHandler<HTMLButtonElement> | undefined) => (
|
||||||
|
<div style={{ marginBottom: '20px' }}>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
cursor: 'pointer',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
padding: '10px',
|
||||||
|
backgroundColor: '#f0f0f0',
|
||||||
|
marginBottom: '10px'
|
||||||
|
}}
|
||||||
|
onClick={() => toggleSection(typeKey)}
|
||||||
|
>
|
||||||
|
<span style={{ marginRight: '10px', fontSize: '20px', color: '#138a49' }}>
|
||||||
|
{expandedSections[typeKey] ? '▼' : '▶'}
|
||||||
|
</span>
|
||||||
|
<h3 style={{ margin: 0 }}>{title}</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{expandedSections[typeKey] && (
|
||||||
|
<div style={{ marginLeft: '20px' }}>
|
||||||
|
<button onClick={() => toggleAddForm(typeKey)}>
|
||||||
|
Add {title.replace(' Types', ' type')}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{showAddForm && (
|
||||||
|
<div style={{
|
||||||
|
marginTop: '10px',
|
||||||
|
marginBottom: '10px',
|
||||||
|
padding: '10px',
|
||||||
|
border: '1px solid #ccc',
|
||||||
|
borderRadius: '4px'
|
||||||
|
}}>
|
||||||
|
<h4>Add New {title.replace(' Types', '')}</h4>
|
||||||
|
<div>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder="Name"
|
||||||
|
value={newItem.name}
|
||||||
|
onChange={(e) => setNewItem({ ...newItem, name: e.target.value })}
|
||||||
|
style={{ marginRight: '10px', padding: '5px' }}
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder="Description"
|
||||||
|
value={newItem.description}
|
||||||
|
onChange={(e) => setNewItem({ ...newItem, description: e.target.value })}
|
||||||
|
style={{ marginRight: '10px', padding: '5px' }}
|
||||||
|
/>
|
||||||
|
<button onClick={addHandler}>Save</button>
|
||||||
|
<button onClick={() => toggleAddForm(typeKey)} style={{ marginLeft: '5px' }}>Cancel</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<table style={{ width: '100%', borderCollapse: 'collapse', marginTop: '10px' }}>
|
||||||
|
<thead>
|
||||||
|
<tr style={{ backgroundColor: '#f2f2f2' }}>
|
||||||
|
<th style={{ border: '1px solid #ddd', padding: '8px', textAlign: 'left' }}>ID</th>
|
||||||
|
<th style={{ border: '1px solid #ddd', padding: '8px', textAlign: 'left' }}>Name</th>
|
||||||
|
<th style={{ border: '1px solid #ddd', padding: '8px', textAlign: 'left' }}>Description</th>
|
||||||
|
<th style={{ border: '1px solid #ddd', padding: '8px', textAlign: 'left' }}>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{types.map((type) => (
|
||||||
|
<tr key={type.id}>
|
||||||
|
<td style={{ border: '1px solid #ddd', padding: '8px' }}>{type.id}</td>
|
||||||
|
<td style={{ border: '1px solid #ddd', padding: '8px' }}>{type.name}</td>
|
||||||
|
<td style={{ border: '1px solid #ddd', padding: '8px' }}>{type.description}</td>
|
||||||
|
<td style={{ border: '1px solid #ddd', padding: '8px' }}>
|
||||||
|
<button onClick={() => handleEdit(typeKey, type.id)} style={{ marginRight: '5px' }}>Edit</button>
|
||||||
|
<button onClick={() => handleDelete(typeKey === 'contractType' ? 'contract' : typeKey === 'serviceType' ? 'service' : 'cargo', type.id)}>Delete</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{renderTable(
|
||||||
|
'Contract Types',
|
||||||
|
contractTypes,
|
||||||
|
handleAddContractType,
|
||||||
|
newContractType,
|
||||||
|
setNewContractType,
|
||||||
|
showAddForms.contractType,
|
||||||
|
'contractType',
|
||||||
|
handleAddContractType
|
||||||
|
)}
|
||||||
|
|
||||||
|
{renderTable(
|
||||||
|
'Service Types',
|
||||||
|
serviceTypes,
|
||||||
|
handleAddServiceType,
|
||||||
|
newServiceType,
|
||||||
|
setNewServiceType,
|
||||||
|
showAddForms.serviceType,
|
||||||
|
'serviceType',
|
||||||
|
handleAddServiceType
|
||||||
|
)}
|
||||||
|
|
||||||
|
{renderTable(
|
||||||
|
'Cargo Types',
|
||||||
|
cargoTypes,
|
||||||
|
handleAddCargoType,
|
||||||
|
newCargoType,
|
||||||
|
setNewCargoType,
|
||||||
|
showAddForms.cargoType,
|
||||||
|
'cargoType',
|
||||||
|
handleAddCargoType
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { ContractTypePage, } from "@/components/ruleEngine/ContractType";
|
||||||
|
|
||||||
|
export const RuleEnginePage = () => {
|
||||||
|
return <div>
|
||||||
|
<h3>
|
||||||
|
Rule Engine Page
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<ContractTypePage />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user