// 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 */}
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 (
);
}
// ============== 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 });