diff --git a/apps/edr-freight-api/src/modules/rule-engine/controllers/cargo-types.controller.ts b/apps/edr-freight-api/src/modules/rule-engine/controllers/cargo-types.controller.ts index de855c7ef..ed1f661c2 100644 --- a/apps/edr-freight-api/src/modules/rule-engine/controllers/cargo-types.controller.ts +++ b/apps/edr-freight-api/src/modules/rule-engine/controllers/cargo-types.controller.ts @@ -3,7 +3,7 @@ import { Param, ParseUUIDPipe, Patch, Post, Query, } from '@nestjs/common'; import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger'; -import { CreateCargoTypeDto } from '../dto/create-cargo-type.dto'; +// import { CreateCargoTypeDto } from '../dto/create-cargo-type.dto'; import { UpdateCargoTypeDto } from '../dto/update-cargo-type.dto'; import { CargoTypesService } from '../services/cargo-types.service'; @@ -39,7 +39,8 @@ export class CargoTypesController { @Post() @ApiOperation({ summary: 'Create a cargo type' }) - create(@Body() dto: CreateCargoTypeDto) { + create(@Body() dto: any) { + return dto; return this.service.create(dto); } diff --git a/apps/edr-freight-web/backoffice/package.json b/apps/edr-freight-web/backoffice/package.json index 2a10e1d03..f39ee4541 100644 --- a/apps/edr-freight-web/backoffice/package.json +++ b/apps/edr-freight-web/backoffice/package.json @@ -14,7 +14,7 @@ "dependencies": { "@edr/types": "workspace:*", "@edr/ui-common": "workspace:*", - "@tanstack/react-query": "^5.59.0", + "@tanstack/react-query": "^5.100.11", "@tria-plc/iamui-common": "1.1.1", "axios": "^1.7.7", "class-variance-authority": "^0.7.1", diff --git a/apps/edr-freight-web/backoffice/src/App.tsx b/apps/edr-freight-web/backoffice/src/App.tsx index 55250dacb..75a233955 100644 --- a/apps/edr-freight-web/backoffice/src/App.tsx +++ b/apps/edr-freight-web/backoffice/src/App.tsx @@ -1,8 +1,7 @@ import { Navigate, Outlet, Route, Routes, useLocation, useNavigate } from "react-router-dom"; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { DashboardLayout, type SidebarItem } from "@edr/ui-common"; -import { LayoutDashboard, Network, Settings } from "lucide-react"; - +import { LayoutDashboard, Network, Paperclip, Settings } from "lucide-react"; import { useAuth } from "./auth/useAuth"; import LoginPage from "./pages/auth/LoginPage"; import OverviewPage from "./pages/dashboard/OverviewPage"; @@ -11,6 +10,8 @@ import PermissionsPage from "./pages/dashboard/user-management/PermissionsPage"; import RolesPage from "./pages/dashboard/user-management/RolesPage"; import UserManagementPage from "./pages/dashboard/user-management/UserManagementPage"; import LoadingScreen from "./components/LoadingScreen"; +import FileUploadSettingsPage from "./pages/documents/FileUploadSettingsPage"; +import DropdownSettingsPage from "./pages/dropdown_settings/DropdownSettingsPage"; import DemoUser1Page from "./pages/dashboard/demo/DemoUser1Page"; import DemoUser2Page from "./pages/dashboard/demo/DemoUser2Page"; import { RuleEnginePage } from "./pages/ruleEngine/RuleEngine"; @@ -26,6 +27,38 @@ const queryClient = new QueryClient({ }, }); +// const sidebarItems: SidebarItem[] = [ +// { +// label: "Overview", +// href: "/dashboard/overview", +// icon: , +// }, +// { +// label: "User management", +// href: "/dashboard/user-management", +// icon: , +// children: [ +// { +// label: "Employees", +// href: "/dashboard/user-management/employees", +// }, +// { +// label: "Permissions", +// href: "/dashboard/user-management/permissions", +// }, +// { +// label: "Roles", +// href: "/dashboard/user-management/roles", +// }, +// ], +// }, +// { +// label: "Rule Engine", +// href: "/dashboard/rule-engine", +// icon: , +// }, +// ]; + const sidebarItems: SidebarItem[] = [ { label: "Overview", @@ -51,11 +84,21 @@ const sidebarItems: SidebarItem[] = [ }, ], }, + { + label: "File Settings", + href: "/dashboard/file-settings", + icon: , + }, + { + label: "Dropdown Settings", + href: "/dashboard/dropdown-settings", + icon: , + }, { label: "Rule Engine", href: "/dashboard/rule-engine", icon: , - }, + } ]; const hasPermission = ( @@ -70,62 +113,10 @@ const hasPermission = ( ), ); }; - const DashboardShell = () => { const navigate = useNavigate(); const location = useLocation(); const { user, logout } = useAuth(); - - const sidebarItems: SidebarItem[] = [ - { - label: "Overview", - href: "/dashboard/overview", - icon: , - }, - { - label: "User management", - href: "/dashboard/user-management", - icon: , - children: [ - { - label: "Employees", - href: "/dashboard/user-management/employees", - }, - { - label: "Permissions", - href: "/dashboard/user-management/permissions", - }, - { - label: "Roles", - href: "/dashboard/user-management/roles", - }, - ], - }, - { - label: "Rule Engine", - href: "/dashboard/rule-engine", - icon: , - }, - ...(hasPermission(user, "can:demo:user1") - ? ([ - { - label: "User1", - href: "/dashboard/user1", - icon: , - }, - ] as SidebarItem[]) - : []), - ...(hasPermission(user, "can:demo:user2") - ? ([ - { - label: "User2", - href: "/dashboard/user2", - icon: , - }, - ] as SidebarItem[]) - : []), - ]; - const displayName = user?.name?.en || user?.username || user?.email || "User"; return ( @@ -164,22 +155,6 @@ const App = () => { return ( - {/* - } /> - } /> - }> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - - } /> - -======= */} } /> } /> @@ -192,6 +167,8 @@ const App = () => { } /> } /> } /> + } /> + } /> } /> } /> diff --git a/apps/edr-freight-web/backoffice/src/components/ruleEngine/ContractType copy 4.tsx b/apps/edr-freight-web/backoffice/src/components/ruleEngine/ContractType copy 4.tsx new file mode 100644 index 000000000..e7b815ae9 --- /dev/null +++ b/apps/edr-freight-web/backoffice/src/components/ruleEngine/ContractType copy 4.tsx @@ -0,0 +1,874 @@ +// src/components/ruleEngine/ContractType.tsx +import { createCargoType } from '@/services/rule.engine/cargoType'; +import { useState, useEffect } from 'react'; + +// ==================== API Service ==================== +const API_BASE_URL = 'http://localhost:3001/api'; + +const apiFetch = async (endpoint: string, options?: RequestInit): Promise => { + try { + const url = `${API_BASE_URL}${endpoint}`; + const response = await fetch(url, { + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }, + ...options, + }); + + if (!response.ok) { + const errorText = await response.text(); + throw new Error(`HTTP ${response.status}: ${errorText || response.statusText}`); + } + + return await response.json(); + } catch (error) { + console.error(`API Error (${endpoint}):`, error); + throw error; + } +}; + +const apiService = { + getCargoTypes: (): Promise => apiFetch('/cargo-types'), + createCargoType: (data: any): Promise => apiFetch('/cargo-types', { method: 'POST', body: JSON.stringify(data) }), + updateCargoType: (id: string, data: any): Promise => apiFetch(`/cargo-types/${id}`, { method: 'PATCH', body: JSON.stringify(data) }), + deleteCargoType: (id: string): Promise => apiFetch(`/cargo-types/${id}`, { method: 'DELETE' }), + + getContainerTypes: (): Promise => apiFetch('/container-types'), + createContainerType: (data: any): Promise => apiFetch('/container-types', { method: 'POST', body: JSON.stringify(data) }), + updateContainerType: (id: string, data: any): Promise => apiFetch(`/container-types/${id}`, { method: 'PATCH', body: JSON.stringify(data) }), + deleteContainerType: (id: string): Promise => apiFetch(`/container-types/${id}`, { method: 'DELETE' }), + + getPriorityRules: (): Promise => apiFetch('/priority-rules'), + createPriorityRule: (data: any): Promise => apiFetch('/priority-rules', { method: 'POST', body: JSON.stringify(data) }), + updatePriorityRule: (id: string, data: any): Promise => apiFetch(`/priority-rules/${id}`, { method: 'PATCH', body: JSON.stringify(data) }), + deletePriorityRule: (id: string): Promise => apiFetch(`/priority-rules/${id}`, { method: 'DELETE' }), + + getServiceTypes: (): Promise => apiFetch('/service-types'), + createServiceType: (data: any): Promise => apiFetch('/service-types', { method: 'POST', body: JSON.stringify(data) }), + updateServiceType: (id: string, data: any): Promise => apiFetch(`/service-types/${id}`, { method: 'PATCH', body: JSON.stringify(data) }), + deleteServiceType: (id: string): Promise => apiFetch(`/service-types/${id}`, { method: 'DELETE' }), + + getSurchargeTypes: (): Promise => apiFetch('/surcharge-types'), + createSurchargeType: (data: any): Promise => apiFetch('/surcharge-types', { method: 'POST', body: JSON.stringify(data) }), + updateSurchargeType: (id: string, data: any): Promise => apiFetch(`/surcharge-types/${id}`, { method: 'PATCH', body: JSON.stringify(data) }), + deleteSurchargeType: (id: string): Promise => apiFetch(`/surcharge-types/${id}`, { method: 'DELETE' }), + + getSurcharges: (): Promise => apiFetch('/surcharges'), + createSurcharge: (data: any): Promise => apiFetch('/surcharges', { method: 'POST', body: JSON.stringify(data) }), + updateSurcharge: (id: string, data: any): Promise => apiFetch(`/surcharges/${id}`, { method: 'PATCH', body: JSON.stringify(data) }), + deleteSurcharge: (id: string): Promise => apiFetch(`/surcharges/${id}`, { method: 'DELETE' }), + + getWeightLimitRules: (): Promise => apiFetch('/weight-limit-rules'), + createWeightLimitRule: (data: any): Promise => apiFetch('/weight-limit-rules', { method: 'POST', body: JSON.stringify(data) }), + updateWeightLimitRule: (id: string, data: any): Promise => apiFetch(`/weight-limit-rules/${id}`, { method: 'PATCH', body: JSON.stringify(data) }), + deleteWeightLimitRule: (id: string): Promise => apiFetch(`/weight-limit-rules/${id}`, { method: 'DELETE' }), +}; + +// ==================== Toast Component ==================== +const Toast = ({ message, type, onClose }: { message: string; type: string; onClose: () => void }) => { + useEffect(() => { + const timer = setTimeout(onClose, 3000); + return () => clearTimeout(timer); + }, [onClose]); + + const bgColor = type === 'success' ? 'bg-green-500' : 'bg-red-500'; + return ( +
+ {message} +
+ ); +}; + +// ==================== Modal Component ==================== +const Modal = ({ isOpen, onClose, title, children }: { isOpen: boolean; onClose: () => void; title: string; children: React.ReactNode }) => { + if (!isOpen) return null; + + return ( +
+
+
+

{title}

+ +
+
{children}
+
+
+ ); +}; + +// ==================== Form Components ==================== + +// 1. Cargo Type Form +const CargoTypeForm = ({ initialData, onSubmit, onCancel, isSubmitting }: any) => { + const [formData, setFormData] = useState({ + code: initialData?.code || '', + cargoTypeName: initialData?.cargoTypeName || '', + parentGroupId: initialData?.parentGroupId || '', + showFreeTextBox: initialData?.showFreeTextBox || false, + requiresDirectorApproval: initialData?.requiresDirectorApproval || false, + isActive: initialData?.isActive !== undefined ? initialData.isActive : true, + displayOrder: initialData?.displayOrder || 1, + }); + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + const submitData = { + code: formData.code.toUpperCase(), + cargoTypeName: formData.cargoTypeName, + parentGroupId: formData.parentGroupId || undefined, + showFreeTextBox: formData.showFreeTextBox, + requiresDirectorApproval: formData.requiresDirectorApproval, + isActive: formData.isActive, + displayOrder: Number(formData.displayOrder), + }; + onSubmit(submitData); + }; + + return ( +
+
+
+ + setFormData({...formData, code: e.target.value})} required /> +
+
+ + setFormData({...formData, cargoTypeName: e.target.value})} required /> +
+
+
+ + setFormData({...formData, parentGroupId: e.target.value})} /> +
+
+
+ + setFormData({...formData, displayOrder: parseInt(e.target.value)})} /> +
+
+
+ + + +
+
+ + +
+
+ ); +}; + +// 2. Container Type Form +const ContainerTypeForm = ({ initialData, onSubmit, onCancel, isSubmitting }: any) => { + const [formData, setFormData] = useState({ + sizeCode: initialData?.sizeCode || '', + description: initialData?.description || '', + containersPerWagon: initialData?.containersPerWagon || 1, + isActive: initialData?.isActive !== undefined ? initialData.isActive : true, + }); + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + onSubmit(formData); + }; + + return ( +
+
+ + setFormData({...formData, sizeCode: e.target.value})} required /> +
+
+ +