// 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 */}
TCS
TCS
Ocean Procurement
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 Cost Simulation System

As part of our standardization and simplification initiative, we are pleased to roll out the new Terminal Cost Simulation system. Built on CYB and CYM data from Rateflow, it serves as the single source of truth for terminal contracts and rates — enhancing data consistency and accuracy across APA.

{/* Module illustration row */}
{glyphContract} {glyphCalculator} {glyphHealth} {glyphTCO}
{/* RIGHT — visual hero */}
{/* Bottom CTA */}
{authed ? (
Click, scroll, or press any key to enter
Authenticated via Maersk SSO · session 8h
) : (
Authenticating via Maersk SSO…
)}
{/* 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 && } ); }) )} ); // Rate Health — shield outline + EKG pulse line + status dots const glyphHealth = ( {/* Shield */} {/* EKG pulse line across shield */} {/* Pulsing dot at end of line */} {/* Status dots — present / expiring / missing */} ); // 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 });