/* Pelagia Portal — Sites, Cart, Vessels, Accounts, Users, Import PO */
/* ═══════════════════ SITES ═══════════════════ */
const SitesPage = ({ go }) => (
<>
Sites
{SITES.length} ports, depots, and offices that hold inventory
| Name | Code | Address |
Vessels | Items |
Location | Status | |
{SITES.map(s => (
go("site-detail", s.id)}>
| {s.name} |
{s.code} |
{s.address} |
{s.vessels} |
{s.items} |
{["9.95° N","19.04° N","13.07° N","17.69° N"][SITES.indexOf(s)]} · {["76.26° E","72.85° E","80.26° E","83.21° E"][SITES.indexOf(s)]} |
Active |
|
))}
>
);
/* ═══════════════════ SITE DETAIL ═══════════════════ */
const SiteDetailPage = ({ go, id }) => {
const s = SITES.find(x => x.id === id) || SITES[0];
const max = Math.max(...SITE_INVENTORY.map(i => i.qty));
return (
<>
{s.name}
{s.code}·
{s.address}·
9.9489° N · 76.2622° E
last calculated 12:30} />
across all items} />
Quantity on hand}>
{SITE_INVENTORY.map((it, i) => (
))}
Daily draw-down}>
{SITE_INVENTORY.slice(0, 5).map((it, i) => (
{it.name.split("—")[0].trim().split(" ").slice(0,2).join(" ")}
))}
Inventory
| Product | Qty on hand | Last updated | |
{SITE_INVENTORY.map((it, i) => (
go("item-detail", "p1")}>
| {it.name} |
{it.qty} ea |
{it.updated} |
|
))}
Recent POs for this site
| PO Number | Status | Vendor | Created | Amount |
{ORDERS.slice(0, 5).map(o => (
go("po-detail", o.id)}>
| {o.id} |
|
{o.vendor || "—"} |
{o.submitted || "—"} |
{inr(o.amount)} |
))}
MV Pelagia Voyager
MV Coral Crescent
>
);
};
/* ═══════════════════ VESSELS ═══════════════════ */
const VesselsPage = () => (
<>
Vessels
{VESSELS.length} vessels in service
| Name | IMO Number | Assigned site | Status | |
{VESSELS.map(v => (
| {v.name} |
{v.imo} |
{["Cochin Port Depot","Mumbai BPX Office","Visakhapatnam Yard","Chennai South Dock","Cochin Port Depot"][VESSELS.indexOf(v)]} |
Active |
|
))}
>
);
/* ═══════════════════ ACCOUNTS ═══════════════════ */
const AccountsPage = () => (
<>
Accounts / Cost centres
{ACCOUNTS.length} active cost centres
| Code | Name | Description | Status | |
{ACCOUNTS.map(a => (
| {a.code} |
{a.name} |
{a.desc} |
Active |
|
))}
>
);
/* ═══════════════════ USERS ═══════════════════ */
const UsersPage = () => (
<>
Users
{USERS.length} active users · 7 roles
| Employee ID | Name | Email | Role | Status | Created | |
{USERS.map(u => (
| {u.emp} |
{u.name} |
{u.email} |
{u.role} |
Active |
{u.created} |
|
))}
>
);
/* ═══════════════════ CART ═══════════════════ */
const CartPage = ({ go }) => {
const [items, setItems] = useS([
{ id: 1, name: "Marine Bearing 6310-2RS", desc: "50×110×27mm sealed", vendor: "Mahalakshmi Marine Stores", price: 4250, qty: 24, gst: 18 },
{ id: 2, name: "Lube Oil Filter — Element", desc: "Cellulose, 10µ", vendor: "Coastline Engineering Co.", price: 1180, qty: 48, gst: 18 },
{ id: 3, name: "CO₂ Fire Extinguisher 9kg", desc: "Marine-grade, BIS certified", vendor: "Sealine Maritime Pvt Ltd", price: 8400, qty: 4, gst: 18 },
]);
const taxable = items.reduce((s, i) => s + i.price * i.qty, 0);
const gst = items.reduce((s, i) => s + i.price * i.qty * i.gst / 100, 0);
return (
<>
Cart
{items.length} items · saved locally to this device
{items.length === 0 ? Cart is empty. Add items from the Item catalogue.
: (
<>
Item · Vendor
Unit price
Quantity
Subtotal
{items.map(it => (
{it.name}
{it.desc} · {it.vendor}
{inrFull(it.price)}
setItems(items.map(x => x.id === it.id ? { ...x, qty: Number(e.target.value) || 0 } : x))}
style={{ height: 28, width: 64, textAlign: "right", fontSize: 12 }} />
{inrFull(it.price * it.qty)}
))}
>
)}
- Taxable
- {inrFull(taxable)}
- GST
- {inrFull(gst)}
Grand total
{inrFull(taxable + gst)}
The selected site pre-fills as place of delivery on the new PO.
>
);
};
/* ═══════════════════ IMPORT PO ═══════════════════ */
const ImportPOPage = ({ go }) => (
<>
Import PO from Excel
Upload a file in Pelagia's standard PO template format
Drop .xlsx file here or
browse
Template downloadable from /docs/po-template.xlsx
Q-Mahalakshmi-2841.xlsx · 84 KB · parsed
5 line items detected
3 · Extracted line items — review before saving
| Item | Description | Qty | Unit |
Unit price | GST | Total |
{ORDERS[0].items.concat([
{ name: "Marine Grease — EP2", desc: "Lithium complex, 18kg pail", qty: 6, unit: "ea", price: 4800, gst: 18 },
{ name: "O-Ring Set — FKM", desc: "Assorted sizes 40-pc kit", qty: 2, unit: "set", price: 2400, gst: 18 },
]).map((i, idx) => (
| {i.name} |
{i.desc} |
{i.qty} |
{i.unit} |
{inrFull(i.price)} |
{i.gst}% |
{inrFull(i.qty * i.price * (1 + i.gst / 100))} |
))}
>
);
Object.assign(window, { SitesPage, SiteDetailPage, VesselsPage, AccountsPage, UsersPage, CartPage, ImportPOPage });