// Welcome / hero landing page — dismissed on click, scroll, or key press function WelcomeOverlay({ onDismiss }) { const [leaving, setLeaving] = useState(false); const dismissed = useRef(false); const [authed, setAuthed] = useState(!!window.OCMS_USER); useEffect(() => { if (authed) return; const handler = () => setAuthed(true); window.addEventListener('ocms:user-ready', handler); return () => window.removeEventListener('ocms:user-ready', handler); }, []); const dismiss = () => { if (!authed) return; if (dismissed.current) return; dismissed.current = true; setLeaving(true); setTimeout(onDismiss, 480); }; useEffect(() => { const onKey = (e) => { if (["Escape", " ", "Enter", "ArrowDown", "PageDown"].includes(e.key)) dismiss(); }; const onWheel = (e) => { if (Math.abs(e.deltaY) > 4) dismiss(); }; const onTouch = () => dismiss(); window.addEventListener("keydown", onKey); window.addEventListener("wheel", onWheel, { passive: true }); window.addEventListener("touchmove", onTouch, { passive: true }); return () => { window.removeEventListener("keydown", onKey); window.removeEventListener("wheel", onWheel); window.removeEventListener("touchmove", onTouch); }; }, []); return (
{/* Background — grid + gradient + grain */} {/* Animated abstract APA terminal map */} {/* Top bar */}
T
TCMS
Ocean Finance · APA
v1.1.0 Live · {new Date().toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" })} Confidential
{/* Body — split left content / right map */}
{/* LEFT — copy */}
{/* Title */}

Terminal Contract Management System

The single source of truth for APA terminal contracts, rates, rebates and total cost of ownership — purpose-built for Ocean Finance, Procurement and Rate Focal teams.

{/* Module illustration row */}
{glyphContract} {glyphCalculator} {glyphVolume} {glyphTCO}
{/* Modules chip row */}
{[ ["Rate Repository", false], ["Rate Health", true], ["Rebate Monitor", true], ["Volume Tracker", true], ["TCO Analysis", true], ["AI Assistant", false], ["Documentation", false], ].map(([m, isNew]) => ( {isNew && } {m} ))}
{/* RIGHT — visual hero */}
{/* Bottom CTA */}
{authed ? (
Click, scroll, or press any key to enter
Authenticated via Maersk SSO · session 8h
) : (
Authenticating via Maersk SSO…
)}
Powered by DIFY + Power Automate
{/* Keyframes */}
); } function BackgroundLayer() { return ( <> {/* Radial gradient */}
{/* Grid */} {/* Subtle horizon line */}
); } // Abstract APA terminal map — animated dots + connecting arcs function TerminalMap() { // Pseudo-coords (right-half of viewport) const dots = [ { x: 78, y: 18, l: "CNTSN", region: "NA" }, // Tianjin { x: 82, y: 24, l: "CNSHA", region: "NA" }, // Shanghai { x: 80, y: 28, l: "CNNGB", region: "NA" }, // Ningbo { x: 86, y: 33, l: "CNTAO", region: "NA" }, // (offset) { x: 92, y: 22, l: "JPYOK", region: "NA" }, // Yokohama { x: 89, y: 17, l: "KRPUS", region: "NA" }, // Busan { x: 88, y: 39, l: "HKHKG", region: "NA" }, // Hong Kong { x: 84, y: 42, l: "CNYTN", region: "NA" }, // Shenzhen { x: 75, y: 56, l: "VNSGN", region: "SEA" }, // Ho Chi Minh { x: 70, y: 62, l: "MYPKG", region: "SEA" }, // Port Klang { x: 78, y: 68, l: "SGSIN", region: "SEA" }, // Singapore { x: 80, y: 73, l: "IDJKT", region: "SEA" }, // Jakarta { x: 60, y: 50, l: "INNSA", region: "SA" }, // India { x: 56, y: 56, l: "INMUN", region: "SA" }, // Mundra { x: 88, y: 86, l: "AUSYD", region: "OCE" }, // Sydney { x: 84, y: 84, l: "AUMEL", region: "OCE" }, // Melbourne { x: 96, y: 88, l: "NZAKL", region: "OCE" }, // Auckland ]; const regionColor = { NA: "#14a3bd", SEA: "#5fd1a8", SA: "#d8a83a", OCE: "#b07cd4", }; // Arcs to animate (pairs of indices) const arcs = [ [1, 10], [2, 8], [10, 14], [12, 1], [5, 10], [1, 14], [8, 12], [4, 9], [0, 6], [11, 14], [13, 11], ]; return ( {/* Faint outline contours suggesting coastline */} {/* Animated arcs (great-circle-ish curves between dots) */} {arcs.map(([a, b], i) => { const A = dots[a], B = dots[b]; const mx = (A.x + B.x) / 2; const my = (A.y + B.y) / 2; // Lift control point perpendicular to AB const dx = B.x - A.x, dy = B.y - A.y; const len = Math.hypot(dx, dy); const ox = -dy / len * len * 0.18; const oy = dx / len * len * 0.18; const cx = mx + ox, cy = my - Math.abs(oy); return ( ); })} {/* Dots with subtle pulse */} {dots.map((d, i) => ( ))} ); } function ModuleGlyph({ label, delay, children }) { return (
{children}
{label}
); } // ============== MODULE GLYPHS ============== const glyphStroke = "#cfe0f2"; const glyphAccent = "#80d1de"; const glyphMint = "#5fd1a8"; // Contract Management — a document with a clause underline + stamp seal const glyphContract = ( ); // Calculator — keypad grid with active key + result tape const glyphCalculator = ( $ 1, 284 {Array.from({ length: 4 }).map((_, r) => Array.from({ length: 3 }).map((_, c) => { const active = (r === 2 && c === 1); return ( {active && } ); }) )} ); // Volume Monitor — stacked bar chart with rising bar const glyphVolume = ( {[20, 32, 44].map(y => ( ))} {[ { x: 22, h1: 14, h2: 8 }, { x: 34, h1: 18, h2: 6 }, { x: 46, h1: 12, h2: 10 }, { x: 58, h1: 22, h2: 8 }, { x: 70, h1: 16, h2: 16 }, ].map((b, i) => ( ))} ); // TCO Analysis — waterfall + delta arrow const glyphTCO = ( ); Object.assign(window, { WelcomeOverlay });