);
};
diff --git a/apps/edr-freight-web/backoffice/src/pages/auth/LoginPage.tsx b/apps/edr-freight-web/backoffice/src/pages/auth/LoginPage.tsx
index 23f05f3af..e689ef9f8 100644
--- a/apps/edr-freight-web/backoffice/src/pages/auth/LoginPage.tsx
+++ b/apps/edr-freight-web/backoffice/src/pages/auth/LoginPage.tsx
@@ -1,6 +1,15 @@
import { type FormEvent, useState } from "react";
import { parsePhoneNumberFromString } from "libphonenumber-js";
-import { Eye, EyeOff, Mail, Smartphone, UserRound, ArrowUpRight, Globe, ChevronDown } from "lucide-react";
+import {
+ Eye,
+ EyeOff,
+ Mail,
+ Smartphone,
+ UserRound,
+ ArrowUpRight,
+ Globe,
+ ChevronDown,
+} from "lucide-react";
import { useNavigate } from "react-router-dom";
import { useAuth } from "@/auth/useAuth";
@@ -13,10 +22,25 @@ const loginModes: Array<{
icon: typeof Mail;
placeholder: string;
}> = [
- { value: "email", label: "Email", icon: Mail, placeholder: "name@company.com" },
- { value: "phone", label: "Phone", icon: Smartphone, placeholder: "09XXXXXXXX" },
- { value: "username", label: "Username", icon: UserRound, placeholder: "username" },
-];
+ {
+ value: "email",
+ label: "Email",
+ icon: Mail,
+ placeholder: "name@company.com",
+ },
+ {
+ value: "phone",
+ label: "Phone",
+ icon: Smartphone,
+ placeholder: "09XXXXXXXX",
+ },
+ {
+ value: "username",
+ label: "Username",
+ icon: UserRound,
+ placeholder: "username",
+ },
+ ];
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const usernamePattern = /^[a-zA-Z0-9._-]{3,32}$/;
@@ -43,7 +67,9 @@ const normalizeIdentifier = (mode: LoginMode, value: string) => {
}
if (!usernamePattern.test(trimmed)) {
- throw new Error("Username must be 3-32 characters and use letters, numbers, ., _, or -.");
+ throw new Error(
+ "Username must be 3-32 characters and use letters, numbers, ., _, or -.",
+ );
}
return trimmed;
@@ -59,14 +85,24 @@ const primaryButtonClass =
"h-11 w-full rounded-full bg-primary text-sm font-semibold text-primary-foreground shadow-[0_8px_20px_-6px_rgba(16,94,52,0.5)] transition-all duration-200 hover:bg-primary/90 hover:shadow-[0_10px_24px_-6px_rgba(16,94,52,0.55)] active:scale-[0.99] disabled:cursor-not-allowed disabled:opacity-60 disabled:shadow-none";
const LeftPanelDecor = () => (
-
+
{[0, 1, 2, 3, 4, 5].map((ring) => (
-
+
))}
@@ -74,12 +110,23 @@ const LeftPanelDecor = () => (
);
const RightPanelDecor = () => (
-
+
-
+
-
+
@@ -99,7 +146,11 @@ const LeftPanel = () => (
-
+
(
- Sign in to manage bookings, track cargo, and run logistics operations on the
- Ethio Djibouti Railway freight platform.
+ Sign in to manage bookings, track cargo, and run logistics operations
+ on the Ethio Djibouti Railway freight platform.
@@ -138,13 +189,22 @@ const FormFooter = () => (
© 2026 EDR Freight
@@ -176,7 +236,7 @@ const LoginPage = () => {
setNormalizedIdentifier(normalized);
const result = await login({ email: normalized, password });
- console.log(result)
+ console.log(result);
if (result.mfaRequired) {
setNeedsMfa(true);
return;
@@ -212,15 +272,20 @@ const LoginPage = () => {
-
Get Started
+
+ Get Started
+
- Log in to access the freight backoffice & explore all logistics resources.
+ Log in to access the freight backoffice & explore all logistics
+ resources.
-
Sign in method
+
+ Sign in method
+
{
className="absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 transition-colors hover:text-gray-600"
aria-label={showPassword ? "Hide password" : "Show password"}
>
- {showPassword ? : }
+ {showPassword ? (
+
+ ) : (
+
+ )}
-
-
-
- I agree to EDR Freight{" "}
-
- Terms & Conditions
-
- .
-
-
-
{error ? (
{error}
) : null}
-
+
{submitting ? "Signing in..." : "Sign In"}
@@ -318,8 +377,10 @@ const LoginPage = () => {
We sent a verification code to{" "}
- {normalizedIdentifier} . Enter it below
- to complete sign in.
+
+ {normalizedIdentifier}
+
+ . Enter it below to complete sign in.
@@ -354,7 +415,11 @@ const LoginPage = () => {
>
Back
-
+
{submitting ? "Verifying..." : "Verify"}
diff --git a/apps/edr-freight-web/backoffice/src/theme/freight-brand.ts b/apps/edr-freight-web/backoffice/src/theme/freight-brand.ts
index 32192dd36..6c1efd3f3 100644
--- a/apps/edr-freight-web/backoffice/src/theme/freight-brand.ts
+++ b/apps/edr-freight-web/backoffice/src/theme/freight-brand.ts
@@ -1,4 +1,8 @@
-import { createTheme, type MantineColorsTuple } from "@mantine/core";
+import {
+ colorsTuple,
+ createTheme,
+ type MantineColorsTuple,
+} from "@mantine/core";
/** EDR Freight primary brand green */
export const FREIGHT_BRAND = "#1B9E7A";
@@ -17,24 +21,155 @@ export const freightBrand = {
mutedBorder: "#B7EBDC",
} as const;
-/** Mantine green scale with #1B9E7A at index 6 (filled buttons, nav active). */
-const freightGreen: MantineColorsTuple = [
- "#E7F8F2",
- "#C5EFE1",
- "#9CE4CD",
- "#6BD6B5",
- "#41C8A0",
- "#25B58C",
- FREIGHT_BRAND,
- FREIGHT_BRAND_DARK,
- "#105F47",
- "#0A3D2E",
+const edrGreen: MantineColorsTuple = [
+ "#ecfdf5",
+ "#d1fae5",
+ "#a7f3d0",
+ "#6ee7b7",
+ "#34d399",
+ "#0EA371",
+ "#0A8A5F",
+ "#0A6F4D",
+ "#065f46",
+ "#064e3b",
+];
+
+const neutral: MantineColorsTuple = [
+ "#F4F7FA",
+ "#eef2f7",
+ "#E6ECF2",
+ "#d0dae6",
+ "#b0bfce",
+ "#8fa0b2",
+ "#6B7C8E",
+ "#4b5a6a",
+ "#10202F",
+ "#0C1A2B",
];
export const freightMantineTheme = createTheme({
- primaryColor: "green",
colors: {
- green: freightGreen,
+ "edr-green": edrGreen,
+ gray: neutral,
+
+ // Brand surface + text tokens (single-value semantic colors).
+ // Each generates --mantine-color-{name}-{0..9} CSS variables.
+ "edr-bg": colorsTuple("#F7FAFC"),
+ "edr-card": colorsTuple("#FFFFFF"),
+ "edr-border": colorsTuple("#E6ECF2"),
+ "edr-divider": colorsTuple("#EEF1F5"),
+ "edr-text": colorsTuple("#10202F"),
+ "edr-muted": colorsTuple("#6B7C8E"),
+ "edr-soft": colorsTuple("#ECF6F1"),
+ "edr-ink": colorsTuple("#0C1A2B"),
+ "edr-accent": colorsTuple("#F2A516"),
+
+ // Semantic status shades (from the design system).
+ "edr-amber-soft": colorsTuple("#FDF3E0"),
+ "edr-amber-text": colorsTuple("#9A5B00"),
+ "edr-blue": colorsTuple("#2E5B96"),
+ "edr-blue-soft": colorsTuple("#E9F0F8"),
+ "edr-blue-dot": colorsTuple("#3B6FB0"),
+ "edr-red": colorsTuple("#C0392B"),
+ "edr-red-soft": colorsTuple("#FBEAE7"),
+ "edr-slate": colorsTuple("#475569"),
+ "edr-slate-soft": colorsTuple("#F1F4F7"),
+ "edr-slate-soft2": colorsTuple("#EEF2F6"),
+ "edr-step": colorsTuple("#94A3B8"),
+ "edr-step-idle": colorsTuple("#D5DBE2"),
+ "edr-conn-idle": colorsTuple("#E6EAEF"),
+ },
+ primaryColor: "edr-green",
+ primaryShade: { light: 5, dark: 4 },
+
+ white: "#ffffff",
+ black: "#10202F",
+
+ fontFamily:
+ '"Inter", ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
+
+ defaultRadius: "md",
+
+ radius: {
+ xs: "4px",
+ sm: "6px",
+ md: "8px",
+ lg: "12px",
+ xl: "18px",
+ },
+
+ spacing: {
+ xs: "8px",
+ sm: "12px",
+ md: "16px",
+ lg: "24px",
+ xl: "32px",
+ },
+
+ fontSizes: {
+ xs: "12px",
+ sm: "14px",
+ md: "16px",
+ lg: "20px",
+ xl: "24px",
+ },
+
+ lineHeights: {
+ xs: "1.4",
+ sm: "1.45",
+ md: "1.55",
+ lg: "1.55",
+ xl: "1.5",
+ },
+
+ headings: {
+ fontFamily: '"Inter", var(--mantine-font-family)',
+ fontWeight: "700",
+ sizes: {
+ h1: { fontSize: "36px", lineHeight: "1.1", fontWeight: "800" },
+ h2: { fontSize: "28px", lineHeight: "1.2", fontWeight: "700" },
+ h3: { fontSize: "22px", lineHeight: "1.3", fontWeight: "600" },
+ h4: { fontSize: "18px", lineHeight: "1.4", fontWeight: "600" },
+ h5: { fontSize: "15px", lineHeight: "1.45", fontWeight: "600" },
+ h6: { fontSize: "13px", lineHeight: "1.45", fontWeight: "600" },
+ },
+ },
+
+ shadows: {
+ xs: "0 1px 2px rgba(16, 24, 40, 0.04)",
+ sm: "0 1px 3px rgba(16, 24, 40, 0.06)",
+ md: "0 4px 12px rgba(16, 24, 40, 0.06)",
+ },
+
+ components: {
+ Card: {
+ defaultProps: {
+ radius: "xl",
+ withBorder: true,
+ shadow: "none",
+ padding: "lg",
+ },
+ styles: {
+ root: { borderColor: "#E6ECF2" },
+ },
+ },
+ Button: {
+ defaultProps: { radius: "md" },
+ styles: { root: { fontWeight: 600 } },
+ },
+ Badge: {
+ defaultProps: { radius: "xl", variant: "light" },
+ styles: { root: { fontWeight: 600, textTransform: "none" } },
+ },
+ Paper: {
+ defaultProps: { radius: "xl", shadow: "none", withBorder: true },
+ styles: { root: { borderColor: "#E6ECF2" } },
+ },
+ Table: {
+ defaultProps: { verticalSpacing: "sm", horizontalSpacing: "md" },
+ },
+ Title: {
+ styles: { root: { letterSpacing: "-0.01em" } },
+ },
},
- fontFamily: "'Outfit', var(--font-sans)",
});