feat(freight:backoffice): added basic frontend integration with auth(login) page

This commit is contained in:
Michael Abebe
2026-05-22 17:15:46 +03:00
parent f9a9d9923c
commit 2c9ca6f16b
30 changed files with 515 additions and 3301 deletions

View File

@@ -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>

View File

@@ -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;

View File

@@ -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>,

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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."
/>
);
};

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;
}