mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 18:48:11 +00:00
feat(freight:backoffice): added basic frontend integration with auth(login) page
This commit is contained in:
@@ -6,14 +6,94 @@ import {
|
||||
Navigate,
|
||||
} from "react-router-dom";
|
||||
import { DashboardLayout, type SidebarItem } from "@edr/ui-common";
|
||||
import {
|
||||
LayoutDashboard,
|
||||
Users,
|
||||
CalendarCheck,
|
||||
Package,
|
||||
MapPin,
|
||||
Train,
|
||||
Receipt,
|
||||
FileText,
|
||||
Settings,
|
||||
FileUp,
|
||||
} from "lucide-react";
|
||||
import {
|
||||
IamLoginPage,
|
||||
LoadingScreen,
|
||||
useAuth,
|
||||
useAuthUser,
|
||||
} from "@tria-plc/iamui-common";
|
||||
|
||||
import BookingsPage from "./pages/bookings/BookingsPage";
|
||||
import BookingDetailPage from "./pages/bookings/BookingDetailPage";
|
||||
import NewBookingPage from "./pages/bookings/NewBookingPage";
|
||||
import ConsignmentsPage from "./pages/consignments/ConsignmentsPage";
|
||||
import ConsignmentDetailPage from "./pages/consignments/ConsignmentDetailPage";
|
||||
import TrackingPage from "./pages/tracking/TrackingPage";
|
||||
import BillingPage from "./pages/billing/BillingPage";
|
||||
import TrainsPage from "./pages/trains/TrainsPage";
|
||||
import DashboardPage from "./pages/dashboard/DashboardPage";
|
||||
import CustomersPage from "./pages/customers/CustomersPage";
|
||||
import CustomerDetailPage from "./pages/customers/CustomerDetailPage";
|
||||
import NewCustomerPage from "./pages/customers/NewCustomerPage";
|
||||
import DocumentsPage from "./pages/documents/DocumentsPage";
|
||||
import DropdownSettingsPage from "./pages/admin/DropdownSettingsPage";
|
||||
import FileUploadSettingsPage from "./pages/admin/FileUploadSettingsPage";
|
||||
|
||||
const sidebarItems: SidebarItem[] = [{ label: "Dashboard", href: "/" }];
|
||||
const sidebarItems: SidebarItem[] = [
|
||||
{ label: "Dashboard", href: "/", icon: <LayoutDashboard /> },
|
||||
{ label: "Customers", href: "/customers", icon: <Users /> },
|
||||
{ label: "Bookings", href: "/bookings", icon: <CalendarCheck /> },
|
||||
{ label: "Consignments", href: "/consignments", icon: <Package /> },
|
||||
{ label: "Tracking", href: "/tracking", icon: <MapPin /> },
|
||||
{ label: "Trains", href: "/trains", icon: <Train /> },
|
||||
{ label: "Billing", href: "/billing", icon: <Receipt /> },
|
||||
{ label: "Documents", href: "/documents", icon: <FileText /> },
|
||||
{ label: "Dropdown Settings", href: "/admin/dropdowns", icon: <Settings /> },
|
||||
{
|
||||
label: "File Upload Settings",
|
||||
href: "/admin/file-uploads",
|
||||
icon: <FileUp />,
|
||||
},
|
||||
];
|
||||
|
||||
const App = () => {
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const { user, loading } = useAuth();
|
||||
const { logout } = useAuthUser();
|
||||
|
||||
if (loading) {
|
||||
return <LoadingScreen />;
|
||||
}
|
||||
|
||||
if (!user) {
|
||||
return (
|
||||
<Routes>
|
||||
<Route path="/auth" element={<IamLoginPage />} />
|
||||
<Route path="*" element={<Navigate to="/auth" replace />} />
|
||||
</Routes>
|
||||
);
|
||||
}
|
||||
|
||||
const displayName = user.name?.en || user.username || user.email || "User";
|
||||
const userEmail = user.email;
|
||||
|
||||
const handleLogout = () => {
|
||||
logout();
|
||||
[
|
||||
"auth-token",
|
||||
"refresh-token",
|
||||
"auth-user",
|
||||
"current-position-id",
|
||||
"selected-position-id",
|
||||
].forEach((name) => {
|
||||
document.cookie = `${name}=; Max-Age=0; path=/`;
|
||||
});
|
||||
localStorage.clear();
|
||||
window.location.replace("/auth");
|
||||
};
|
||||
|
||||
return (
|
||||
<DashboardLayout
|
||||
@@ -21,9 +101,34 @@ const App = () => {
|
||||
sidebarItems={sidebarItems}
|
||||
activeHref={location.pathname}
|
||||
onNavigate={navigate}
|
||||
enableThemeToggle
|
||||
userName={displayName}
|
||||
userEmail={userEmail}
|
||||
onLogout={handleLogout}
|
||||
>
|
||||
<Routes>
|
||||
<Route path="/" element={<DashboardPage />} />
|
||||
<Route path="/bookings" element={<BookingsPage />} />
|
||||
<Route path="/customers" element={<CustomersPage />} />
|
||||
<Route path="/customers/:id" element={<CustomerDetailPage />} />
|
||||
<Route path="/new-customer" element={<NewCustomerPage />} />
|
||||
<Route path="/bookings/new" element={<NewBookingPage />} />
|
||||
<Route path="/bookings/:id" element={<BookingDetailPage />} />
|
||||
<Route path="/consignments" element={<ConsignmentsPage />} />
|
||||
<Route path="/consignments/:id" element={<ConsignmentDetailPage />} />
|
||||
<Route path="/tracking" element={<TrackingPage />} />
|
||||
<Route path="/trains" element={<TrainsPage />} />
|
||||
<Route path="/billing" element={<BillingPage />} />
|
||||
<Route path="/documents" element={<DocumentsPage />} />
|
||||
<Route
|
||||
path="/admin/dropdowns"
|
||||
element={<DropdownSettingsPage />}
|
||||
/>
|
||||
<Route
|
||||
path="/admin/file-uploads"
|
||||
element={<FileUploadSettingsPage />}
|
||||
/>
|
||||
<Route path="/user-management" element={<Navigate to="/" replace />} />
|
||||
<Route path="*" element={<Navigate to="/" replace />} />
|
||||
</Routes>
|
||||
</DashboardLayout>
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
interface FeaturePlaceholderProps {
|
||||
title: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
const FeaturePlaceholder = ({
|
||||
title,
|
||||
description,
|
||||
}: FeaturePlaceholderProps) => {
|
||||
return (
|
||||
<section className="p-6">
|
||||
<div className="rounded-2xl border border-border bg-card p-8 shadow-sm">
|
||||
<p className="text-sm font-medium uppercase tracking-[0.2em] text-muted-foreground">
|
||||
EDR Freight Backoffice
|
||||
</p>
|
||||
<h1 className="mt-3 text-3xl font-semibold text-foreground">{title}</h1>
|
||||
<p className="mt-3 max-w-2xl text-sm text-muted-foreground">
|
||||
{description}
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default FeaturePlaceholder;
|
||||
@@ -2,16 +2,75 @@ import { StrictMode } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import { BrowserRouter } from "react-router-dom";
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import "@tria-plc/iamui-common/styles.css";
|
||||
import "@edr/ui-common/styles.css";
|
||||
import "../index.css";
|
||||
import "@edr/ui-common/theme.css";
|
||||
|
||||
import App from "./App";
|
||||
import {
|
||||
AuthProvider,
|
||||
configureIam,
|
||||
UserProvider,
|
||||
axiosInstance,
|
||||
} from "@tria-plc/iamui-common";
|
||||
|
||||
["auth-token", "refresh-token"].forEach((name) => {
|
||||
const entry = document.cookie
|
||||
.split("; ")
|
||||
.find((cookie) => cookie.startsWith(`${name}=`));
|
||||
const value = entry?.split("=").slice(1).join("=");
|
||||
if (value === "undefined" || value === "null" || value === "") {
|
||||
document.cookie = `${name}=; Max-Age=0; path=/`;
|
||||
}
|
||||
});
|
||||
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
createRoot(document.getElementById("root")!).render(
|
||||
window.__IAM_CONFIG__ = {
|
||||
apiUrl: `${import.meta.env.VITE_BASE_API_URL}/api`,
|
||||
postLoginPath: "/",
|
||||
};
|
||||
|
||||
axiosInstance.interceptors.response.use((response) => {
|
||||
if (
|
||||
response.data &&
|
||||
typeof response.data === "object" &&
|
||||
"success" in response.data &&
|
||||
"data" in response.data
|
||||
) {
|
||||
response.data = response.data.data;
|
||||
}
|
||||
return response;
|
||||
});
|
||||
|
||||
window.__USER_MANAGEMENT_BRANDING__ = {
|
||||
organizationName: "EDR Platform",
|
||||
appName: "EDR Backoffice",
|
||||
moduleBasePath: "/user-management",
|
||||
backToAppPath: "/",
|
||||
backToAppLabel: "Back to dashboard",
|
||||
};
|
||||
|
||||
configureIam({
|
||||
apiUrl: `${import.meta.env.VITE_BASE_API_URL}/api`,
|
||||
});
|
||||
|
||||
const rootElement = document.getElementById("root");
|
||||
|
||||
if (!rootElement) {
|
||||
throw new Error("Root element not found");
|
||||
}
|
||||
|
||||
createRoot(rootElement).render(
|
||||
<StrictMode>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<BrowserRouter>
|
||||
<App />
|
||||
<AuthProvider>
|
||||
<UserProvider>
|
||||
<App />
|
||||
</UserProvider>
|
||||
</AuthProvider>
|
||||
</BrowserRouter>
|
||||
</QueryClientProvider>
|
||||
</StrictMode>,
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
import FeaturePlaceholder from "@/components/FeaturePlaceholder";
|
||||
|
||||
const DropdownSettingsPage = () => {
|
||||
return (
|
||||
<FeaturePlaceholder
|
||||
title="Dropdown Settings"
|
||||
description="Configure controlled dropdown options used across backoffice workflows."
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default DropdownSettingsPage;
|
||||
@@ -0,0 +1,12 @@
|
||||
import FeaturePlaceholder from "@/components/FeaturePlaceholder";
|
||||
|
||||
const FileUploadSettingsPage = () => {
|
||||
return (
|
||||
<FeaturePlaceholder
|
||||
title="File Upload Settings"
|
||||
description="Define the document fields and upload rules used by freight backoffice teams."
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default FileUploadSettingsPage;
|
||||
@@ -0,0 +1,12 @@
|
||||
import FeaturePlaceholder from "@/components/FeaturePlaceholder";
|
||||
|
||||
const BillingPage = () => {
|
||||
return (
|
||||
<FeaturePlaceholder
|
||||
title="Billing"
|
||||
description="Review invoice activity, billing exceptions, and reconciliation tasks for freight operations."
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default BillingPage;
|
||||
@@ -0,0 +1,12 @@
|
||||
import FeaturePlaceholder from "@/components/FeaturePlaceholder";
|
||||
|
||||
const BookingDetailPage = () => {
|
||||
return (
|
||||
<FeaturePlaceholder
|
||||
title="Booking Detail"
|
||||
description="Inspect booking metadata, operational notes, and fulfillment progress for internal teams."
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default BookingDetailPage;
|
||||
@@ -0,0 +1,12 @@
|
||||
import FeaturePlaceholder from "@/components/FeaturePlaceholder";
|
||||
|
||||
const BookingsPage = () => {
|
||||
return (
|
||||
<FeaturePlaceholder
|
||||
title="Bookings"
|
||||
description="Manage freight bookings, review operational status, and coordinate internal processing flows."
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default BookingsPage;
|
||||
@@ -0,0 +1,12 @@
|
||||
import FeaturePlaceholder from "@/components/FeaturePlaceholder";
|
||||
|
||||
const NewBookingPage = () => {
|
||||
return (
|
||||
<FeaturePlaceholder
|
||||
title="Create Booking"
|
||||
description="Capture and validate new freight bookings from the backoffice workflow."
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default NewBookingPage;
|
||||
@@ -0,0 +1,12 @@
|
||||
import FeaturePlaceholder from "@/components/FeaturePlaceholder";
|
||||
|
||||
const ConsignmentDetailPage = () => {
|
||||
return (
|
||||
<FeaturePlaceholder
|
||||
title="Consignment Detail"
|
||||
description="Review cargo information, routing context, and operational actions for a consignment."
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default ConsignmentDetailPage;
|
||||
@@ -0,0 +1,12 @@
|
||||
import FeaturePlaceholder from "@/components/FeaturePlaceholder";
|
||||
|
||||
const ConsignmentsPage = () => {
|
||||
return (
|
||||
<FeaturePlaceholder
|
||||
title="Consignments"
|
||||
description="Manage consignment handling, milestones, and internal exception resolution."
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default ConsignmentsPage;
|
||||
@@ -0,0 +1,12 @@
|
||||
import FeaturePlaceholder from "@/components/FeaturePlaceholder";
|
||||
|
||||
const CustomerDetailPage = () => {
|
||||
return (
|
||||
<FeaturePlaceholder
|
||||
title="Customer Detail"
|
||||
description="View customer profile details, active shipments, and internal account notes."
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default CustomerDetailPage;
|
||||
@@ -0,0 +1,12 @@
|
||||
import FeaturePlaceholder from "@/components/FeaturePlaceholder";
|
||||
|
||||
const CustomersPage = () => {
|
||||
return (
|
||||
<FeaturePlaceholder
|
||||
title="Customers"
|
||||
description="Review and maintain customer records, service status, and operational context."
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default CustomersPage;
|
||||
@@ -0,0 +1,12 @@
|
||||
import FeaturePlaceholder from "@/components/FeaturePlaceholder";
|
||||
|
||||
const NewCustomerPage = () => {
|
||||
return (
|
||||
<FeaturePlaceholder
|
||||
title="Create Customer"
|
||||
description="Register a new freight customer and prepare the account for operational use."
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default NewCustomerPage;
|
||||
@@ -1,9 +1,11 @@
|
||||
import FeaturePlaceholder from "@/components/FeaturePlaceholder";
|
||||
|
||||
const DashboardPage = () => {
|
||||
return (
|
||||
<div className="p-6">
|
||||
<h1 className="text-2xl font-semibold">EDR Freight Backoffice</h1>
|
||||
<p className="mt-2 text-gray-600">Backoffice — coming soon.</p>
|
||||
</div>
|
||||
<FeaturePlaceholder
|
||||
title="Operations Dashboard"
|
||||
description="Track internal freight activity, exceptions, and workload from one backoffice workspace."
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
import FeaturePlaceholder from "@/components/FeaturePlaceholder";
|
||||
|
||||
const DocumentsPage = () => {
|
||||
return (
|
||||
<FeaturePlaceholder
|
||||
title="Documents"
|
||||
description="Manage internal freight documents, approvals, and operational record keeping."
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default DocumentsPage;
|
||||
@@ -0,0 +1,12 @@
|
||||
import FeaturePlaceholder from "@/components/FeaturePlaceholder";
|
||||
|
||||
const TrackingPage = () => {
|
||||
return (
|
||||
<FeaturePlaceholder
|
||||
title="Tracking"
|
||||
description="Monitor shipment movement, operational events, and delays across the rail network."
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default TrackingPage;
|
||||
@@ -0,0 +1,12 @@
|
||||
import FeaturePlaceholder from "@/components/FeaturePlaceholder";
|
||||
|
||||
const TrainsPage = () => {
|
||||
return (
|
||||
<FeaturePlaceholder
|
||||
title="Trains"
|
||||
description="Coordinate train assignments, scheduling visibility, and operational readiness."
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default TrainsPage;
|
||||
@@ -1 +1,24 @@
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
interface Window {
|
||||
__IAM_CONFIG__?: {
|
||||
apiUrl: string;
|
||||
postLoginPath?: string;
|
||||
};
|
||||
__USER_MANAGEMENT_BRANDING__?: {
|
||||
organizationName: string;
|
||||
appName: string;
|
||||
moduleBasePath: string;
|
||||
backToAppPath?: string;
|
||||
backToAppLabel?: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface ImportMetaEnv {
|
||||
readonly VITE_API_URL: string;
|
||||
readonly VITE_BASE_API_URL: string;
|
||||
}
|
||||
|
||||
interface ImportMeta {
|
||||
readonly env: ImportMetaEnv;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user