pelagia-portal/Wireframe/Pelagia Portal Wireframes.html
2026-05-18 23:18:58 +05:30

1167 lines
66 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Pelagia Marine Portal Wireframes</title>
<link href="https://fonts.googleapis.com/css2?family=Caveat:wght@400;600;700&family=Special+Elite&display=swap" rel="stylesheet">
<script src="https://unpkg.com/react@18.3.1/umd/react.development.js" integrity="sha384-hD6/rw4ppMLGNu3tX5cjIb+uRZ7UkRJ6BPkLpg4hAu/6onKUg4lLsHAs9EBPT82L" crossorigin="anonymous"></script>
<script src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.development.js" integrity="sha384-u6aeetuaXnQ38mYT8rp6sbXaQe3NL9t+IBXmnYxwkUI2Hw4bsp2Wvmx4yRQF1uAm" crossorigin="anonymous"></script>
<script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js" integrity="sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y" crossorigin="anonymous"></script>
<script type="text/babel" src="design-canvas.jsx"></script>
<script type="text/babel" src="tweaks-panel.jsx"></script>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body { background: #f5f0e8; font-family: 'Caveat', cursive; }
/* Sketchy global style */
.wf { font-family: 'Caveat', cursive; }
.wf-label { font-size: 11px; font-family: 'Caveat', cursive; color: #888; letter-spacing: 0.05em; text-transform: uppercase; }
/* Sketch box */
.sk-box {
border: 2px solid #222;
border-radius: 3px;
background: #fff;
position: relative;
}
.sk-box.filled { background: #e8e4dc; }
.sk-box.dark { background: #222; }
.sk-box.accent { background: #d4e9f7; border-color: #3a7cbf; }
.sk-box.warn { background: #fdf3d0; border-color: #c8971a; }
.sk-box.success { background: #d8f0e0; border-color: #2a8a50; }
.sk-box.danger { background: #fde0e0; border-color: #c03030; }
.sk-btn {
display: inline-block;
border: 2px solid #222;
border-radius: 3px;
padding: 5px 14px;
font-family: 'Caveat', cursive;
font-size: 15px;
font-weight: 600;
cursor: default;
background: #fff;
}
.sk-btn.primary { background: #222; color: #fff; }
.sk-btn.accent { background: #3a7cbf; color: #fff; border-color: #3a7cbf; }
.sk-btn.sm { font-size: 13px; padding: 3px 10px; }
.sk-btn.warn { background: #c8971a; color: #fff; border-color: #c8971a; }
.sk-btn.success { background: #2a8a50; color: #fff; border-color: #2a8a50; }
.sk-btn.danger { background: #c03030; color: #fff; border-color: #c03030; }
.sk-input {
border: 2px solid #aaa;
border-radius: 2px;
background: #fafaf8;
padding: 4px 8px;
font-family: 'Caveat', cursive;
font-size: 14px;
color: #555;
width: 100%;
}
.sk-tag {
display: inline-block;
border: 1.5px solid #aaa;
border-radius: 20px;
padding: 2px 10px;
font-size: 12px;
font-family: 'Caveat', cursive;
background: #f5f0e8;
}
.sk-tag.blue { border-color: #3a7cbf; color: #3a7cbf; background: #d4e9f7; }
.sk-tag.green { border-color: #2a8a50; color: #2a8a50; background: #d8f0e0; }
.sk-tag.orange { border-color: #c8971a; color: #c8971a; background: #fdf3d0; }
.sk-tag.red { border-color: #c03030; color: #c03030; background: #fde0e0; }
.sk-tag.gray { border-color: #888; color: #666; background: #eee; }
.sk-divider { border: none; border-top: 1.5px dashed #ccc; margin: 8px 0; }
/* Squiggly underline annotation */
.annotation {
font-family: 'Caveat', cursive;
font-size: 12px;
color: #3a7cbf;
font-style: italic;
}
/* Sidebar nav item */
.nav-item {
display: flex; align-items: center; gap: 8px;
padding: 7px 12px;
font-family: 'Caveat', cursive;
font-size: 15px;
border-left: 3px solid transparent;
cursor: default;
border-radius: 2px;
}
.nav-item.active { background: #e8e4dc; border-left-color: #222; font-weight: 700; }
.nav-item:not(.active) { color: #555; }
/* Table rows */
.sk-table { width: 100%; border-collapse: collapse; font-family: 'Caveat', cursive; font-size: 13px; }
.sk-table th { border-bottom: 2px solid #222; padding: 4px 8px; text-align: left; font-size: 12px; text-transform: uppercase; color: #555; }
.sk-table td { border-bottom: 1px dashed #ccc; padding: 5px 8px; vertical-align: middle; }
.sk-table tr:last-child td { border-bottom: none; }
/* Stat card */
.stat-card { border: 2px solid #222; border-radius: 3px; background: #fff; padding: 10px 14px; }
.stat-num { font-size: 32px; font-weight: 700; line-height: 1; }
.stat-lbl { font-size: 12px; color: #888; margin-top: 2px; }
/* Avatar chip */
.avatar { width: 28px; height: 28px; border-radius: 50%; background: #222; border: 2px solid #222; display: inline-flex; align-items: center; justify-content: center; color: #fff; font-size: 12px; font-weight: 700; flex-shrink: 0; }
/* Screen label for annotation arrows */
.screen-note {
position: absolute;
font-family: 'Caveat', cursive;
font-size: 12px;
color: #3a7cbf;
pointer-events: none;
}
</style>
</head>
<body>
<script type="text/babel">
const { useState } = React;
/* ─── SHARED SHELL ─────────────────────────────────────────── */
function Shell({ role, activeNav, children, headerRight }) {
const roleColors = {
admin: '#8b3fbe', technical: '#3a7cbf', accounts: '#2a8a50',
manning: '#c8971a', supplies: '#c03030', manager: '#555'
};
const color = roleColors[role] || '#222';
const navItems = {
admin: ['Dashboard','Purchase Orders','Users','Settings'],
technical: ['Dashboard','New PO','My Orders'],
accounts: ['Dashboard','Payment Queue','All Orders'],
manning: ['Dashboard','New PO','My Orders'],
supplies: ['Dashboard','Inventory','Orders'],
manager: ['Dashboard','Approvals','Purchase Orders','Reports'],
};
const items = navItems[role] || [];
return (
<div style={{ display:'flex', flexDirection:'column', height:'100%', background:'#fafaf8', border:'2px solid #222', borderRadius:4, overflow:'hidden' }}>
{/* Top bar */}
<div style={{ display:'flex', alignItems:'center', gap:10, padding:'8px 14px', borderBottom:'2px solid #222', background:'#222' }}>
<div style={{ display:'flex', alignItems:'center', gap:6 }}>
{/* anchor icon placeholder */}
<svg width="18" height="18" viewBox="0 0 18 18" fill="none"><circle cx="9" cy="9" r="8" stroke="#fff" strokeWidth="2"/><line x1="9" y1="4" x2="9" y2="14" stroke="#fff" strokeWidth="2"/><line x1="5" y1="12" x2="13" y2="12" stroke="#fff" strokeWidth="1.5"/><circle cx="9" cy="4" r="1.5" fill="#fff"/></svg>
<span style={{ color:'#fff', fontWeight:700, fontSize:16 }}>PELAGIA MARINE</span>
</div>
<div style={{ flex:1 }}/>
<span className="sk-tag" style={{ background:'rgba(255,255,255,0.1)', border:`1.5px solid ${color}`, color:'#fff', fontSize:11 }}>{role.toUpperCase()}</span>
{headerRight}
<div className="avatar">{role[0].toUpperCase()}</div>
</div>
<div style={{ display:'flex', flex:1, overflow:'hidden' }}>
{/* Sidebar */}
<div style={{ width:130, borderRight:'2px solid #222', background:'#f5f0e8', padding:'10px 0', flexShrink:0 }}>
{items.map(item => (
<div key={item} className={`nav-item${item === activeNav ? ' active' : ''}`}>
<span style={{ fontSize:13 }}>{item}</span>
</div>
))}
</div>
{/* Content */}
<div style={{ flex:1, overflow:'auto', padding:16 }}>
{children}
</div>
</div>
</div>
);
}
/* ─── SCREEN 1: LOGIN ────────────────────────────────────────── */
function LoginScreen() {
return (
<div style={{ display:'flex', flexDirection:'column', height:'100%', background:'#fafaf8', position:'relative' }}>
{/* Ocean texture stripe */}
<div style={{ height:6, background:'repeating-linear-gradient(90deg,#3a7cbf 0,#3a7cbf 12px,#5a9cd0 12px,#5a9cd0 24px)' }}/>
<div style={{ flex:1, display:'flex', alignItems:'center', justifyContent:'center' }}>
<div style={{ display:'flex', flexDirection:'column', alignItems:'center', gap:20, width:260 }}>
{/* Logo block */}
<div style={{ display:'flex', flexDirection:'column', alignItems:'center', gap:6 }}>
<div style={{ width:56, height:56, border:'3px solid #222', borderRadius:4, display:'flex', alignItems:'center', justifyContent:'center', background:'#222' }}>
<svg width="32" height="32" viewBox="0 0 32 32" fill="none">
<circle cx="16" cy="10" r="4" stroke="#fff" strokeWidth="2"/>
<line x1="16" y1="14" x2="16" y2="26" stroke="#fff" strokeWidth="2"/>
<path d="M8 22 Q16 28 24 22" stroke="#fff" strokeWidth="2" fill="none"/>
<line x1="10" y1="26" x2="22" y2="26" stroke="#fff" strokeWidth="1.5"/>
</svg>
</div>
<div style={{ textAlign:'center' }}>
<div style={{ fontSize:20, fontWeight:700, letterSpacing:1 }}>PELAGIA MARINE</div>
<div style={{ fontSize:12, color:'#888', letterSpacing:2 }}>COMPANY PORTAL</div>
</div>
</div>
{/* Login card */}
<div className="sk-box" style={{ width:'100%', padding:20, display:'flex', flexDirection:'column', gap:12 }}>
<div style={{ fontSize:15, fontWeight:700 }}>Sign In</div>
<div style={{ display:'flex', flexDirection:'column', gap:4 }}>
<span className="wf-label">Employee ID or Email</span>
<div className="sk-input" style={{ color:'#bbb' }}>e.g. EMP-0042</div>
</div>
<div style={{ display:'flex', flexDirection:'column', gap:4 }}>
<span className="wf-label">Password</span>
<div className="sk-input" style={{ color:'#bbb' }}></div>
</div>
<div style={{ display:'flex', alignItems:'center', gap:6 }}>
<div style={{ width:14, height:14, border:'2px solid #aaa', borderRadius:2, flexShrink:0 }}/>
<span style={{ fontSize:13, color:'#666' }}>Remember this device</span>
</div>
<div className="sk-btn primary" style={{ textAlign:'center', marginTop:4 }}>Sign In </div>
<div style={{ textAlign:'center', fontSize:12, color:'#aaa' }}>Forgot password? Contact IT</div>
</div>
{/* Role badge hint */}
<div style={{ display:'flex', flexDirection:'column', alignItems:'center', gap:6 }}>
<span style={{ fontSize:12, color:'#aaa' }}>Access is role-based:</span>
<div style={{ display:'flex', gap:6, flexWrap:'wrap', justifyContent:'center' }}>
{['Admin','Accounts','Technical','Manning','Supplies','Manager'].map(r => (
<span key={r} className="sk-tag" style={{ fontSize:11 }}>{r}</span>
))}
</div>
</div>
</div>
</div>
{/* annotation */}
<div style={{ position:'absolute', bottom:12, right:16, fontSize:12, color:'#3a7cbf', fontStyle:'italic', fontFamily:'Caveat' }}>
single entry point, role resolved on login
</div>
</div>
);
}
/* ─── SCREEN 2: DASHBOARD (role-aware) ─────────────────────── */
function DashboardScreen({ role }) {
const configs = {
technical: {
stats: [{ n:'3', l:'My Open POs' },{ n:'1', l:'Awaiting Manager' },{ n:'7', l:'Fully Approved (30d)' }],
quick: 'New Purchase Order',
recentLabel: 'My Recent Orders',
rows: [
{ id:'PO-2041', item:'Hydraulic Pump Seal Kit', vessel:'MV Kestrel', amount:'$4,200', status:'mgr-review' },
{ id:'PO-2038', item:'Safety Harnesses ×12', vessel:'MV Falcon', amount:'$1,800', status:'payment' },
{ id:'PO-2031', item:'Anchor Chain Shackles', vessel:'MV Osprey', amount:'$650', status:'approved' },
]
},
accounts: {
stats: [{ n:'8', l:'Ready for Payment' },{ n:'$184k', l:'Payment Queue Value' },{ n:'47', l:'Paid (30d)' }],
quick: 'Process Payments',
recentLabel: 'Manager-Approved — Awaiting Payment',
rows: [
{ id:'PO-2042', item:'Dredge Cutter Head Parts', vessel:'MV Kestrel', amount:'$38,500', status:'payment' },
{ id:'PO-2041', item:'Hydraulic Pump Seal Kit', vessel:'MV Kestrel', amount:'$4,200', status:'payment' },
{ id:'PO-2039', item:'Navigation Radar Unit', vessel:'MV Osprey', amount:'$21,000', status:'payment' },
]
},
manager: {
stats: [{ n:'12', l:'Awaiting My Approval' },{ n:'$1.2M', l:'Spend (YTD)' },{ n:'194', l:'Total POs (YTD)' }],
quick: 'Review Approvals',
recentLabel: 'Pending My Review',
rows: [
{ id:'PO-2042', item:'Dredge Cutter Head Parts', vessel:'MV Kestrel', amount:'$38,500', status:'mgr-review' },
{ id:'PO-2041', item:'Hydraulic Pump Seal Kit', vessel:'MV Kestrel', amount:'$4,200', status:'payment' },
{ id:'PO-2038', item:'Safety Harnesses ×12', vessel:'MV Falcon', amount:'$1,800', status:'approved' },
]
},
admin: {
stats: [{ n:'6', l:'Active Roles' },{ n:'23', l:'Users' },{ n:'12', l:'Pending POs' }],
quick: 'Manage Users',
recentLabel: 'System Activity',
rows: [
{ id:'PO-2042', item:'Dredge Cutter Head Parts', vessel:'MV Kestrel', amount:'$38,500', status:'pending' },
{ id:'PO-2041', item:'Hydraulic Pump Seal Kit', vessel:'MV Kestrel', amount:'$4,200', status:'approved' },
{ id:'PO-2038', item:'Safety Harnesses ×12', vessel:'MV Falcon', amount:'$1,800', status:'approved' },
]
},
manning: {
stats: [{ n:'2', l:'My Open POs' },{ n:'0', l:'Pending Approval' },{ n:'5', l:'Approved (30d)' }],
quick: 'New Purchase Order',
recentLabel: 'My Recent Orders',
rows: [
{ id:'PO-2035', item:'Crew Uniforms ×20', vessel:'MV Falcon', amount:'$2,100', status:'approved' },
{ id:'PO-2030', item:'Safety Boots ×10', vessel:'MV Osprey', amount:'$900', status:'approved' },
]
},
};
const cfg = configs[role] || configs.technical;
const statusTag = (s) => {
if (s === 'mgr-review') return <span className="sk-tag orange">Mgr. Review</span>;
if (s === 'payment') return <span className="sk-tag blue">Awaiting Payment</span>;
if (s === 'approved') return <span className="sk-tag green">Paid </span>;
if (s === 'edits') return <span className="sk-tag red">Edits Requested</span>;
if (s === 'rejected') return <span className="sk-tag red">Rejected</span>;
return <span className="sk-tag gray">{s}</span>;
};
return (
<Shell role={role} activeNav="Dashboard">
<div style={{ display:'flex', flexDirection:'column', gap:14 }}>
<div style={{ display:'flex', alignItems:'center', justifyContent:'space-between' }}>
<div style={{ fontSize:18, fontWeight:700 }}>Welcome back, {role.charAt(0).toUpperCase()+role.slice(1)} 👋</div>
{(role === 'technical' || role === 'manning' || role === 'admin') && (
<div className="sk-btn accent">{cfg.quick}</div>
)}
{role === 'accounts' && <div className="sk-btn warn">{cfg.quick}</div>}
{role === 'manager' && <div className="sk-btn" style={{ border:'2px solid #555' }}>{cfg.quick}</div>}
</div>
{/* Stats row */}
<div style={{ display:'flex', gap:10 }}>
{cfg.stats.map((s, i) => (
<div key={i} className="stat-card" style={{ flex:1 }}>
<div className="stat-num">{s.n}</div>
<div className="stat-lbl">{s.l}</div>
</div>
))}
</div>
{/* Recent table */}
<div className="sk-box" style={{ padding:12 }}>
<div style={{ fontSize:14, fontWeight:700, marginBottom:8 }}>{cfg.recentLabel}</div>
<table className="sk-table">
<thead>
<tr>
<th>PO #</th><th>Item</th><th>Vessel</th><th>Amount</th><th>Status</th>
</tr>
</thead>
<tbody>
{cfg.rows.map(r => (
<tr key={r.id}>
<td style={{ color:'#3a7cbf', fontWeight:600 }}>{r.id}</td>
<td>{r.item}</td>
<td>{r.vessel}</td>
<td style={{ fontWeight:600 }}>{r.amount}</td>
<td>{statusTag(r.status)}</td>
</tr>
))}
</tbody>
</table>
</div>
{role === 'manager' && (
<div style={{ display:'flex', gap:10 }}>
<div className="sk-box" style={{ flex:1, padding:12 }}>
<div style={{ fontSize:13, fontWeight:700, marginBottom:8 }}>Spend by Vessel (placeholder)</div>
<div style={{ height:70, background:'repeating-linear-gradient(0deg,#e8e4dc 0px,#e8e4dc 2px,transparent 2px,transparent 10px)', display:'flex', alignItems:'flex-end', gap:6, padding:'0 8px 0' }}>
{[55,80,40,95,60,70,50].map((h,i)=>(
<div key={i} style={{ flex:1, height:`${h}%`, background:'#3a7cbf', opacity:0.7, borderRadius:'2px 2px 0 0' }}/>
))}
</div>
<div style={{ fontSize:11, color:'#aaa', marginTop:4, textAlign:'center' }}>last 7 vessels</div>
</div>
<div className="sk-box" style={{ flex:1, padding:12 }}>
<div style={{ fontSize:13, fontWeight:700, marginBottom:8 }}>Monthly Spend (placeholder)</div>
<div style={{ height:70, background:'repeating-linear-gradient(0deg,#e8e4dc 0px,#e8e4dc 2px,transparent 2px,transparent 10px)', display:'flex', alignItems:'flex-end', gap:6, padding:'0 8px 0' }}>
{[45,60,80,55,90,75,85,65,95,70,80,60].map((h,i)=>(
<div key={i} style={{ flex:1, height:`${h}%`, background:'#c8971a', opacity:0.7, borderRadius:'2px 2px 0 0' }}/>
))}
</div>
<div style={{ fontSize:11, color:'#aaa', marginTop:4, textAlign:'center' }}>Jan Dec</div>
</div>
</div>
)}
</div>
</Shell>
);
}
/* ─── SCREEN 3: NEW PURCHASE ORDER FORM ─────────────────────── */
function NewPOScreen({ role }) {
return (
<Shell role={role} activeNav="New PO">
<div style={{ display:'flex', gap:16 }}>
{/* Main form */}
<div style={{ flex:2, display:'flex', flexDirection:'column', gap:14 }}>
<div style={{ display:'flex', alignItems:'center', gap:10 }}>
<div style={{ fontSize:18, fontWeight:700 }}>New Purchase Order</div>
<span className="sk-tag gray">Draft</span>
</div>
{/* Section: Order Info */}
<div className="sk-box" style={{ padding:14, display:'flex', flexDirection:'column', gap:12 }}>
<div style={{ fontSize:13, fontWeight:700, borderBottom:'1.5px solid #eee', paddingBottom:6 }}>Order Information</div>
<div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:10 }}>
<div style={{ display:'flex', flexDirection:'column', gap:4 }}>
<span className="wf-label">PO Number (auto)</span>
<div className="sk-input" style={{ color:'#aaa', background:'#f5f0e8' }}>PO-2043</div>
</div>
<div style={{ display:'flex', flexDirection:'column', gap:4 }}>
<span className="wf-label">Date</span>
<div className="sk-input" style={{ color:'#aaa', background:'#f5f0e8' }}>28 Apr 2026</div>
</div>
<div style={{ display:'flex', flexDirection:'column', gap:4, gridColumn:'span 2' }}>
<span className="wf-label">Vessel *</span>
<div className="sk-input" style={{ color:'#bbb' }}>Select vessel</div>
</div>
<div style={{ display:'flex', flexDirection:'column', gap:4, gridColumn:'span 2' }}>
<span className="wf-label">Account ID *</span>
<div className="sk-input" style={{ color:'#bbb' }}>e.g. ACC-2210</div>
</div>
</div>
</div>
{/* Section: Line Items */}
<div className="sk-box" style={{ padding:14, display:'flex', flexDirection:'column', gap:10 }}>
<div style={{ display:'flex', justifyContent:'space-between', alignItems:'center', borderBottom:'1.5px solid #eee', paddingBottom:6 }}>
<div style={{ fontSize:13, fontWeight:700 }}>Line Items</div>
<div className="sk-btn sm">+ Add Item</div>
</div>
{/* Header */}
<div style={{ display:'grid', gridTemplateColumns:'2fr 1fr 80px 80px 30px', gap:6 }}>
<span className="wf-label">Item Description</span>
<span className="wf-label">Item Code</span>
<span className="wf-label">Qty</span>
<span className="wf-label">Unit Cost</span>
<span/>
</div>
{/* Row 1 */}
{[
{ desc:'Hydraulic Pump Seal Kit', code:'ENG-4421', qty:'2', cost:'$2,100' },
{ desc:'Stainless Bolts M16 ×50', code:'FAB-1102', qty:'5', cost:'$120' },
].map((row, i) => (
<div key={i} style={{ display:'grid', gridTemplateColumns:'2fr 1fr 80px 80px 30px', gap:6, alignItems:'center' }}>
<div className="sk-input">{row.desc}</div>
<div className="sk-input">{row.code}</div>
<div className="sk-input">{row.qty}</div>
<div className="sk-input">{row.cost}</div>
<div style={{ color:'#c03030', cursor:'default', fontSize:16, textAlign:'center' }}></div>
</div>
))}
<hr className="sk-divider"/>
<div style={{ display:'flex', justifyContent:'flex-end', gap:20, fontSize:14 }}>
<span style={{ color:'#888' }}>Subtotal</span>
<span style={{ fontWeight:700 }}>$4,440</span>
</div>
</div>
{/* Vendor */}
<div className="sk-box" style={{ padding:14, display:'flex', flexDirection:'column', gap:10, borderColor:'#5c2a5c' }}>
<div style={{ display:'flex', justifyContent:'space-between', alignItems:'center', borderBottom:'1.5px solid #eee', paddingBottom:6 }}>
<div style={{ fontSize:13, fontWeight:700 }}>Vendor <span style={{ color:'#888', fontWeight:400, fontSize:12 }}>(optional can be added later)</span></div>
<span className="sk-tag" style={{ fontSize:11, borderColor:'#5c2a5c', color:'#5c2a5c', background:'#f8f0ff' }}>NEW</span>
</div>
<div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:10 }}>
<div style={{ display:'flex', flexDirection:'column', gap:4 }}>
<span className="wf-label">Vendor ID</span>
<div className="sk-input" style={{ color:'#bbb' }}>e.g. VND-0042</div>
</div>
<div style={{ display:'flex', flexDirection:'column', gap:4 }}>
<span className="wf-label">Vendor Name</span>
<div className="sk-input" style={{ color:'#bbb' }}>Search or enter vendor</div>
</div>
</div>
<div className="annotation" style={{ fontSize:11 }}>If blank, manager may request Vendor ID before approving</div>
</div>
{/* Notes */}
<div className="sk-box" style={{ padding:14, display:'flex', flexDirection:'column', gap:6 }}>
<div style={{ fontSize:13, fontWeight:700, borderBottom:'1.5px solid #eee', paddingBottom:6 }}>Notes / Justification</div>
<div className="sk-input" style={{ minHeight:60, color:'#bbb' }}>Add any notes for the approver</div>
</div>
{/* Actions */}
<div style={{ display:'flex', gap:10, justifyContent:'flex-end' }}>
<div className="sk-btn">Save Draft</div>
<div className="sk-btn accent">Submit for Approval </div>
</div>
</div>
{/* Side panel: PDF upload & summary */}
<div style={{ flex:1, display:'flex', flexDirection:'column', gap:12 }}>
<div className="sk-box" style={{ padding:14, display:'flex', flexDirection:'column', gap:10 }}>
<div style={{ fontSize:13, fontWeight:700 }}>Attach Documents</div>
<div className="sk-box filled" style={{ padding:20, textAlign:'center', borderStyle:'dashed', display:'flex', flexDirection:'column', alignItems:'center', gap:6 }}>
<svg width="28" height="28" viewBox="0 0 28 28" fill="none"><rect x="6" y="3" width="16" height="22" rx="2" stroke="#888" strokeWidth="2"/><line x1="10" y1="10" x2="18" y2="10" stroke="#888" strokeWidth="1.5"/><line x1="10" y1="14" x2="18" y2="14" stroke="#888" strokeWidth="1.5"/><line x1="10" y1="18" x2="15" y2="18" stroke="#888" strokeWidth="1.5"/></svg>
<span style={{ fontSize:12, color:'#888' }}>Drop PDF / Quote here</span>
<div className="sk-btn sm">Browse</div>
</div>
<div style={{ display:'flex', alignItems:'center', gap:8, fontSize:12 }}>
<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><rect x="2" y="1" width="12" height="14" rx="1" stroke="#c03030" strokeWidth="1.5"/><line x1="5" y1="6" x2="11" y2="6" stroke="#c03030" strokeWidth="1"/><line x1="5" y1="9" x2="11" y2="9" stroke="#c03030" strokeWidth="1"/></svg>
<span>Supplier_Quote_Apr2026.pdf</span>
<span style={{ color:'#c03030', marginLeft:'auto' }}></span>
</div>
</div>
{/* PO Summary */}
<div className="sk-box" style={{ padding:14, display:'flex', flexDirection:'column', gap:8 }}>
<div style={{ fontSize:13, fontWeight:700 }}>PO Summary</div>
{[['Items','2'],['Vessel','MV Kestrel'],['Account','ACC-2210'],['Total','$4,440']].map(([k,v]) => (
<div key={k} style={{ display:'flex', justifyContent:'space-between', fontSize:13 }}>
<span style={{ color:'#888' }}>{k}</span>
<span style={{ fontWeight:600 }}>{v}</span>
</div>
))}
<hr className="sk-divider"/>
<div className="annotation" style={{ fontSize:11 }}> Submitted POs go to Manager for approval first</div>
</div>
{/* Approval flow visual */}
<div className="sk-box" style={{ padding:12, display:'flex', flexDirection:'column', gap:6 }}>
<div style={{ fontSize:12, fontWeight:700, color:'#888' }}>Approval Flow</div>
{[
{ label:'Draft', active:true },
{ label:'Submitted', active:true },
{ label:'Manager Review', active:false, note:'Reject / Ask Edits / Approve' },
{ label:'Accounts Payment', active:false, note:'Payment processing' },
{ label:'Complete', active:false },
].map((step, i) => (
<div key={step.label} style={{ display:'flex', alignItems:'flex-start', gap:8 }}>
<div style={{ width:20, height:20, border:'2px solid', borderColor: step.active ? '#3a7cbf' : '#ccc', borderRadius:'50%', display:'flex', alignItems:'center', justifyContent:'center', fontSize:10, fontWeight:700, color: step.active ? '#3a7cbf':'#ccc', flexShrink:0, marginTop:1 }}>{i+1}</div>
<div>
<div style={{ fontSize:12, color: step.active ? '#222':'#aaa' }}>{step.label}</div>
{step.note && <div style={{ fontSize:10, color:'#aaa' }}>{step.note}</div>}
</div>
</div>
))}
</div>
</div>
</div>
</Shell>
);
}
/* ─── SCREEN 4: MANAGER PENDING APPROVALS ──────────────── */
function ManagerApprovalsScreen() {
const orders = [
{ id:'PO-2042', item:'Dredge Cutter Head Parts', code:'ENG-8801', vessel:'MV Kestrel', account:'ACC-1140', submitter:'J. Santos (Tech)', amount:'$38,500', date:'28 Apr', docs:true },
{ id:'PO-2041', item:'Hydraulic Pump Seal Kit', code:'ENG-4421', vessel:'MV Kestrel', account:'ACC-1140', submitter:'J. Santos (Tech)', amount:'$4,200', date:'27 Apr', docs:true },
{ id:'PO-2039', item:'Navigation Radar Unit', code:'NAV-0212', vessel:'MV Osprey', account:'ACC-2290', submitter:'R. Cruz (Tech)', amount:'$21,000', date:'26 Apr', docs:false },
{ id:'PO-2037', item:'Crew Uniforms ×20', code:'MAN-3301', vessel:'MV Falcon', account:'ACC-3310', submitter:'M. Reyes (Manning)', amount:'$2,100', date:'25 Apr', docs:true },
{ id:'PO-2033', item:'Anchor Chain Shackles', code:'FAB-0044', vessel:'MV Osprey', account:'ACC-2290', submitter:'D. Lee (Tech)', amount:'$650', date:'24 Apr', docs:false },
];
return (
<Shell role="manager" activeNav="Approvals">
<div style={{ display:'flex', flexDirection:'column', gap:14 }}>
<div style={{ display:'flex', alignItems:'center', gap:10 }}>
<div style={{ fontSize:18, fontWeight:700 }}>Pending My Approval</div>
<span className="sk-tag orange">12 awaiting</span>
</div>
<div style={{ display:'flex', gap:8, alignItems:'center' }}>
<div style={{ flex:1, display:'flex', alignItems:'center', gap:8, border:'2px solid #aaa', borderRadius:3, padding:'5px 10px', background:'#fff' }}>
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="6" cy="6" r="4" stroke="#888" strokeWidth="1.5"/><line x1="9" y1="9" x2="13" y2="13" stroke="#888" strokeWidth="1.5"/></svg>
<span style={{ fontFamily:'Caveat', fontSize:14, color:'#aaa' }}>Search by item, code, vessel, account, submitter</span>
</div>
<div style={{ display:'flex', gap:6 }}>
<div className="sk-btn sm">Vessel </div>
<div className="sk-btn sm">Account </div>
<div className="sk-btn sm">Date </div>
</div>
</div>
<div className="annotation" style={{ marginTop:-6 }}>full-text search across all PO fields </div>
<div style={{ display:'flex', flexDirection:'column', gap:10 }}>
{orders.map((o, idx) => (
<div key={o.id} className="sk-box" style={{ padding:12, display:'flex', gap:12, alignItems:'flex-start' }}>
{idx === 0 && <div style={{ position:'absolute', top:0, left:0, width:4, height:'100%', background:'#c8971a', borderRadius:'2px 0 0 2px' }}/>}
<div style={{ flex:1, display:'flex', flexDirection:'column', gap:4 }}>
<div style={{ display:'flex', alignItems:'center', gap:8 }}>
<span style={{ fontWeight:700, color:'#3a7cbf' }}>{o.id}</span>
<span style={{ fontWeight:600, fontSize:15 }}>{o.item}</span>
<span className="sk-tag gray" style={{ fontSize:11 }}>{o.code}</span>
{o.docs && <span className="sk-tag blue" style={{ fontSize:11 }}>📄 PDF</span>}
</div>
<div style={{ display:'flex', gap:16, fontSize:13, color:'#666' }}>
<span> {o.vessel}</span>
<span>🗂 {o.account}</span>
<span>👤 {o.submitter}</span>
<span>📅 {o.date}</span>
</div>
</div>
<div style={{ display:'flex', flexDirection:'column', alignItems:'flex-end', gap:8, flexShrink:0 }}>
<span style={{ fontWeight:700, fontSize:16 }}>{o.amount}</span>
<div style={{ display:'flex', gap:6 }}>
<div className="sk-btn sm">View </div>
</div>
</div>
</div>
))}
</div>
<div style={{ fontSize:12, color:'#aaa', textAlign:'center' }}>showing 5 of 12 pending load more </div>
</div>
</Shell>
);
}
/* ─── SCREEN 5: MANAGER ORDER DETAIL / REVIEW ──────────── */
function ManagerOrderDetailScreen() {
const [action, setAction] = React.useState(null);
return (
<Shell role="manager" activeNav="Approvals">
<div style={{ display:'flex', gap:16 }}>
<div style={{ flex:2, display:'flex', flexDirection:'column', gap:14 }}>
<div style={{ fontSize:13, color:'#888' }}> Approvals / <span style={{ color:'#222' }}>PO-2042</span></div>
<div style={{ display:'flex', alignItems:'center', gap:10 }}>
<div style={{ fontSize:18, fontWeight:700 }}>PO-2042 Dredge Cutter Head Parts</div>
<span className="sk-tag orange">Awaiting Manager</span>
</div>
<div className="sk-box" style={{ padding:12, display:'grid', gridTemplateColumns:'1fr 1fr 1fr', gap:10 }}>
{[['Vessel','MV Kestrel'],['Account ID','ACC-1140'],['Submitted By','J. Santos'],['Date','28 Apr 2026'],['Department','Technical'],['Total','$38,500']].map(([k,v]) => (
<div key={k} style={{ display:'flex', flexDirection:'column', gap:2 }}>
<span className="wf-label">{k}</span>
<span style={{ fontWeight:600, fontSize:14 }}>{v}</span>
</div>
))}
</div>
<div className="sk-box" style={{ padding:12 }}>
<div style={{ fontSize:13, fontWeight:700, marginBottom:8 }}>Line Items</div>
<table className="sk-table">
<thead><tr><th>Item</th><th>Code</th><th>Qty</th><th>Unit</th><th>Total</th></tr></thead>
<tbody>
{[
{ item:'Cutter Head Wear Plate', code:'ENG-8801A', qty:4, unit:'$7,500', total:'$30,000' },
{ item:'Cutter Arm Bearing Set', code:'ENG-8801B', qty:2, unit:'$4,000', total:'$8,000' },
{ item:'Mounting Hardware Kit', code:'FAB-0091', qty:1, unit:'$500', total:'$500' },
].map(r => (
<tr key={r.code}>
<td>{r.item}</td><td style={{ color:'#888' }}>{r.code}</td><td>{r.qty}</td><td>{r.unit}</td><td style={{ fontWeight:600 }}>{r.total}</td>
</tr>
))}
<tr><td colSpan={4} style={{ textAlign:'right', color:'#888' }}>Total</td><td style={{ fontWeight:700 }}>$38,500</td></tr>
</tbody>
</table>
</div>
<div className="sk-box" style={{ padding:12 }}>
<div style={{ fontSize:13, fontWeight:700, marginBottom:6 }}>Submitter Notes</div>
<div style={{ fontSize:14, color:'#555', lineHeight:1.5 }}>
Cutter head parts are due for replacement per March 2026 inspection. Vessel returns to port 5 May parts must be on hand for immediate installation.
</div>
</div>
{/* Vendor Review — NEW */}
<div className="sk-box" style={{ padding:12, borderColor:'#5c2a5c', background:'#fdf8ff' }}>
<div style={{ display:'flex', justifyContent:'space-between', alignItems:'center', marginBottom:8 }}>
<div style={{ fontSize:13, fontWeight:700 }}>Vendor Details</div>
<div style={{ display:'flex', gap:6 }}>
<span className="sk-tag" style={{ fontSize:11, borderColor:'#5c2a5c', color:'#5c2a5c', background:'#f8f0ff' }}>VND-0042</span>
<span className="sk-tag" style={{ fontSize:11, borderColor:'#5c2a5c', color:'#5c2a5c', background:'#f8f0ff' }}>NEW</span>
</div>
</div>
<div style={{ display:'grid', gridTemplateColumns:'1fr 1fr 1fr', gap:10, fontSize:13, marginBottom:10 }}>
{[['Vendor','Sea-Tech Marine Supplies'],['Contact','Mr. A. Tan'],['Country','Singapore']].map(([k,v]) => (
<div key={k}>
<span className="wf-label">{k}</span>
<div style={{ fontWeight:600, marginTop:2 }}>{v}</div>
</div>
))}
</div>
<div style={{ display:'flex', gap:8, alignItems:'center' }}>
<div className="sk-btn sm success">Vendor Verified </div>
<span style={{ color:'#aaa', fontSize:12 }}> or </span>
<div className="sk-btn sm" style={{ borderColor:'#c8971a', color:'#c8971a' }}>Request Vendor ID from Submitter</div>
</div>
<div className="annotation" style={{ marginTop:6, fontSize:11 }}>Requesting sends PO back to VENDOR_ID_PENDING state, notifies submitter</div>
</div>
{/* Manager comment box — always shown */}
<div className="sk-box warn" style={{ padding:12, display:'flex', flexDirection:'column', gap:6 }}>
<div style={{ fontSize:13, fontWeight:700 }}>Manager Comment <span style={{ fontWeight:400, color:'#aaa' }}>(sent back to submitter)</span></div>
<div className="sk-input" style={{ minHeight:54, color:'#bbb', background:'#fff' }}>Add a comment required for Reject and Ask for Edits</div>
</div>
{/* 4-action bar */}
<div style={{ display:'flex', flexDirection:'column', gap:8 }}>
<div style={{ fontSize:12, color:'#888', fontWeight:700 }}>Manager Decision</div>
<div style={{ display:'grid', gridTemplateColumns:'1fr 1fr 1fr 1fr', gap:8 }}>
<div style={{ display:'flex', flexDirection:'column', gap:4 }}>
<div className="sk-btn danger" style={{ textAlign:'center', fontSize:13 }}>Reject</div>
<div style={{ fontSize:10, color:'#aaa', textAlign:'center' }}>Closes PO. Notifies submitter with comment.</div>
</div>
<div style={{ display:'flex', flexDirection:'column', gap:4 }}>
<div className="sk-btn" style={{ textAlign:'center', fontSize:13, borderColor:'#c8971a', color:'#c8971a' }}>Ask for Edits</div>
<div style={{ fontSize:10, color:'#aaa', textAlign:'center' }}>Returns to submitter. Comment required.</div>
</div>
<div style={{ display:'flex', flexDirection:'column', gap:4 }}>
<div className="sk-btn success" style={{ textAlign:'center', fontSize:13 }}>Approve </div>
<div style={{ fontSize:10, color:'#aaa', textAlign:'center' }}>Sends to Accounts for payment.</div>
</div>
<div style={{ display:'flex', flexDirection:'column', gap:4 }}>
<div className="sk-btn" style={{ textAlign:'center', fontSize:13, borderColor:'#2a8a50', color:'#2a8a50' }}>Approve + Note</div>
<div style={{ fontSize:10, color:'#aaa', textAlign:'center' }}>Approved with comment to Accounts.</div>
</div>
</div>
<div className="annotation">all decisions notify the submitter instantly </div>
</div>
</div>
{/* Side panel */}
<div style={{ flex:1, display:'flex', flexDirection:'column', gap:12 }}>
<div className="sk-box" style={{ padding:12 }}>
<div style={{ fontSize:13, fontWeight:700, marginBottom:8 }}>Attached Document</div>
<div style={{ height:160, background:'repeating-linear-gradient(135deg,#e8e4dc 0px,#e8e4dc 10px,#f5f0e8 10px,#f5f0e8 20px)', display:'flex', alignItems:'center', justifyContent:'center', border:'1.5px dashed #aaa', borderRadius:2 }}>
<div style={{ textAlign:'center' }}>
<div style={{ fontSize:28 }}>📄</div>
<div style={{ fontSize:11, color:'#888' }}>Supplier_Quote_Apr2026.pdf</div>
<div className="sk-btn sm" style={{ marginTop:6, display:'inline-block' }}>Open PDF</div>
</div>
</div>
</div>
{/* Status trail */}
<div className="sk-box" style={{ padding:12, display:'flex', flexDirection:'column', gap:8 }}>
<div style={{ fontSize:13, fontWeight:700 }}>PO Timeline</div>
{[
{ label:'Created', sub:'J. Santos · 28 Apr 09:14', done:true },
{ label:'Submitted', sub:'J. Santos · 28 Apr 09:22', done:true },
{ label:'Manager Review', sub:'Awaiting decision', done:false, active:true },
{ label:'Accounts Payment', sub:'—', done:false },
{ label:'Complete', sub:'—', done:false },
].map((s,i) => (
<div key={i} style={{ display:'flex', gap:8, alignItems:'flex-start' }}>
<div style={{ width:16, height:16, borderRadius:'50%', border:'2px solid', borderColor: s.done ? '#2a8a50' : s.active ? '#c8971a' : '#ccc', background: s.done ? '#2a8a50' : '#fff', flexShrink:0, marginTop:2 }}/>
<div>
<div style={{ fontSize:12, fontWeight: s.active ? 700:400, color: s.done||s.active ? '#222':'#aaa' }}>{s.label}</div>
<div style={{ fontSize:10, color:'#aaa' }}>{s.sub}</div>
</div>
</div>
))}
</div>
</div>
</div>
</Shell>
);
}
/* ─── SCREEN 6: ACCOUNTS PAYMENT QUEUE ─────────────────── */
function AccountsPaymentScreen() {
const orders = [
{ id:'PO-2040', item:'Fuel Pump Assembly', code:'ENG-5510', vessel:'MV Kestrel', account:'ACC-1140', amount:'$12,800', approved:'Mgr. Chen · 27 Apr', note:'Urgent — vessel departs 2 May', docs:true },
{ id:'PO-2038', item:'Safety Harnesses ×12', code:'MAN-2201', vessel:'MV Falcon', account:'ACC-3310', amount:'$1,800', approved:'Mgr. Chen · 27 Apr', note:'', docs:true },
{ id:'PO-2035', item:'Navigation Charts 2026', code:'NAV-0055', vessel:'MV Osprey', account:'ACC-2290', amount:'$420', approved:'Mgr. Chen · 26 Apr', note:'', docs:false },
{ id:'PO-2031', item:'GPS Transponder', code:'NAV-0212', vessel:'MV Kestrel', account:'ACC-1140', amount:'$5,800', approved:'Mgr. Chen · 25 Apr', note:'Approved with note: verify supplier warranty', docs:true },
];
return (
<Shell role="accounts" activeNav="Payment Queue">
<div style={{ display:'flex', flexDirection:'column', gap:14 }}>
<div style={{ display:'flex', alignItems:'center', gap:10 }}>
<div style={{ fontSize:18, fontWeight:700 }}>Payment Queue</div>
<span className="sk-tag blue">8 ready</span>
<span style={{ fontSize:12, color:'#888', marginLeft:4 }}>Manager-approved POs awaiting payment processing</span>
</div>
<div style={{ display:'flex', gap:8, alignItems:'center' }}>
<div style={{ flex:1, display:'flex', alignItems:'center', gap:8, border:'2px solid #aaa', borderRadius:3, padding:'5px 10px', background:'#fff' }}>
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="6" cy="6" r="4" stroke="#888" strokeWidth="1.5"/><line x1="9" y1="9" x2="13" y2="13" stroke="#888" strokeWidth="1.5"/></svg>
<span style={{ fontFamily:'Caveat', fontSize:14, color:'#aaa' }}>Search by item, vessel, account</span>
</div>
<div className="sk-btn sm">Vessel </div>
<div className="sk-btn sm">Account </div>
</div>
<div style={{ display:'flex', flexDirection:'column', gap:10 }}>
{orders.map((o) => (
<div key={o.id} className="sk-box" style={{ padding:12, display:'flex', gap:12, alignItems:'flex-start' }}>
<div style={{ flex:1, display:'flex', flexDirection:'column', gap:4 }}>
<div style={{ display:'flex', alignItems:'center', gap:8 }}>
<span style={{ fontWeight:700, color:'#3a7cbf' }}>{o.id}</span>
<span style={{ fontWeight:600, fontSize:15 }}>{o.item}</span>
<span className="sk-tag gray" style={{ fontSize:11 }}>{o.code}</span>
{o.docs && <span className="sk-tag blue" style={{ fontSize:11 }}>📄 PDF</span>}
</div>
<div style={{ display:'flex', gap:16, fontSize:13, color:'#666' }}>
<span> {o.vessel}</span>
<span>🗂 {o.account}</span>
<span style={{ color:'#2a8a50' }}> {o.approved}</span>
</div>
{o.note && (
<div style={{ fontSize:12, color:'#c8971a', background:'#fdf3d0', border:'1px solid #c8971a', borderRadius:2, padding:'2px 8px', display:'inline-block', marginTop:2 }}>
💬 Manager note: {o.note}
</div>
)}
</div>
<div style={{ display:'flex', flexDirection:'column', alignItems:'flex-end', gap:8, flexShrink:0 }}>
<span style={{ fontWeight:700, fontSize:16 }}>{o.amount}</span>
<div style={{ display:'flex', gap:6 }}>
<div className="sk-btn sm">View</div>
<div className="sk-btn sm success">Mark Paid </div>
</div>
</div>
</div>
))}
</div>
<div className="annotation">Accounts only sees manager-approved POs no approval decisions here </div>
</div>
</Shell>
);
}
/* ─── SCREEN 7: MY ORDERS SUBMITTER STATUS TRACKER ─────── */
function MyOrdersScreen({ role }) {
const orders = [
{ id:'PO-2042', item:'Dredge Cutter Head Parts', vessel:'MV Kestrel', amount:'$38,500', status:'vendor-pending', date:'28 Apr', comment:'Please provide a Vendor ID before we can proceed with approval.' },
{ id:'PO-2041', item:'Hydraulic Pump Seal Kit', vessel:'MV Kestrel', amount:'$4,200', status:'edits', date:'27 Apr', comment:'Please attach updated supplier quote — previous one is expired.' },
{ id:'PO-2038', item:'Safety Harnesses ×12', vessel:'MV Falcon', amount:'$1,800', status:'paid-delivered', date:'25 Apr', comment:'Approved. Ensure ISO-certified supplier.' },
{ id:'PO-2031', item:'Anchor Chain Shackles', vessel:'MV Osprey', amount:'$650', status:'approved', date:'22 Apr', comment:null },
{ id:'PO-2028', item:'Fire Suppression Refill', vessel:'MV Osprey', amount:'$380', status:'rejected', date:'18 Apr', comment:'Budget exceeded for ACC-2290 this quarter. Re-submit next period.' },
];
const statusTag = (s) => {
if (s === 'mgr-review') return <span className="sk-tag orange">Mgr. Review</span>;
if (s === 'vendor-pending') return <span className="sk-tag" style={{ borderColor:'#5c2a5c', color:'#5c2a5c', background:'#f8f0ff' }}>Vendor ID Needed</span>;
if (s === 'edits') return <span className="sk-tag red">Edits Requested</span>;
if (s === 'payment') return <span className="sk-tag blue">Awaiting Payment</span>;
if (s === 'paid-delivered') return <span className="sk-tag" style={{ borderColor:'#1a6a3a', color:'#1a6a3a', background:'#e0f4ea' }}>Confirm Receipt !</span>;
if (s === 'approved') return <span className="sk-tag green">Closed </span>;
if (s === 'rejected') return <span className="sk-tag red">Rejected</span>;
};
return (
<Shell role={role} activeNav="My Orders">
<div style={{ display:'flex', flexDirection:'column', gap:14 }}>
<div style={{ fontSize:18, fontWeight:700 }}>My Purchase Orders</div>
{/* Status filter tabs */}
<div style={{ display:'flex', gap:0, borderBottom:'2px solid #222' }}>
{[['All','5'],['Edits Needed','1'],['In Progress','2'],['Complete','2']].map(([l,c], i) => (
<div key={l} style={{ padding:'5px 14px', borderBottom: i===0 ? '3px solid #222':'3px solid transparent', marginBottom:-2, fontFamily:'Caveat', fontSize:13, fontWeight: i===0 ? 700:400, cursor:'default' }}>
{l} <span style={{ fontSize:11, color:'#888' }}>({c})</span>
</div>
))}
</div>
<div style={{ display:'flex', flexDirection:'column', gap:10 }}>
{orders.map((o) => (
<div key={o.id} className="sk-box" style={{ padding:12, display:'flex', flexDirection:'column', gap:8, borderColor: o.status === 'edits' ? '#c8971a' : o.status === 'rejected' ? '#c03030' : '#222', background: o.status === 'edits' ? '#fffdf5' : o.status === 'rejected' ? '#fff8f8' : '#fff' }}>
<div style={{ display:'flex', alignItems:'center', gap:8 }}>
<span style={{ fontWeight:700, color:'#3a7cbf' }}>{o.id}</span>
<span style={{ fontWeight:600 }}>{o.item}</span>
<span style={{ color:'#888', fontSize:13 }}> {o.vessel}</span>
<span style={{ marginLeft:'auto', fontWeight:700 }}>{o.amount}</span>
{statusTag(o.status)}
</div>
{/* Progress track */}
<div style={{ display:'flex', gap:0, alignItems:'center' }}>
{['Submitted','Mgr. Review','Accounts Pmt','Paid','Closed'].map((step, i) => {
const stepIdx = { 'mgr-review':1, 'vendor-pending':1, 'edits':1, 'payment':2, 'paid-delivered':3, 'approved':4, 'rejected':1 }[o.status] ?? 0;
const done = i < stepIdx;
const active = i === stepIdx;
const isRejected = o.status === 'rejected' && i === 1;
return (
<React.Fragment key={step}>
<div style={{ display:'flex', flexDirection:'column', alignItems:'center', gap:2 }}>
<div style={{ width:18, height:18, borderRadius:'50%', border:'2px solid', borderColor: isRejected ? '#c03030' : done ? '#2a8a50' : active ? '#c8971a' : '#ccc', background: isRejected ? '#c03030' : done ? '#2a8a50' : '#fff', display:'flex', alignItems:'center', justifyContent:'center' }}>
{done && <span style={{ color:'#fff', fontSize:9, fontWeight:700 }}></span>}
{isRejected && <span style={{ color:'#fff', fontSize:9, fontWeight:700 }}></span>}
</div>
<span style={{ fontSize:9, color: done||active ? '#444':'#bbb', whiteSpace:'nowrap' }}>{step}</span>
</div>
{i < 3 && <div style={{ flex:1, height:2, background: done ? '#2a8a50' : '#e0e0e0', marginBottom:14 }}/>}
</React.Fragment>
);
})}
</div>
{/* Manager comment — shown when there's feedback */}
{o.comment && (
<div style={{ display:'flex', gap:8, alignItems:'flex-start', background: o.status === 'edits' ? '#fdf3d0' : o.status === 'rejected' ? '#fde0e0' : '#d8f0e0', border:`1.5px solid ${o.status === 'edits' ? '#c8971a' : o.status === 'rejected' ? '#c03030' : '#2a8a50'}`, borderRadius:3, padding:'8px 10px' }}>
<span style={{ fontSize:13, fontWeight:700, flexShrink:0 }}>Manager:</span>
<span style={{ fontSize:13, color:'#444' }}>{o.comment}</span>
</div>
)}
<div style={{ display:'flex', gap:8, justifyContent:'flex-end' }}>
<div className="sk-btn sm">View Details</div>
{o.status === 'edits' && <div className="sk-btn sm accent">Edit & Resubmit </div>}
{o.status === 'vendor-pending' && <div className="sk-btn sm" style={{ borderColor:'#5c2a5c', color:'#5c2a5c' }}>Provide Vendor ID </div>}
{o.status === 'paid-delivered' && <div className="sk-btn sm success">Confirm Receipt & Close </div>}
</div>
</div>
))}
</div>
<div className="annotation">submitter sees live status + manager comments at every stage </div>
</div>
</Shell>
);
}
/* ─── SCREEN 6: MANAGER HISTORICAL VIEW ─────────────────────── */
function ManagerHistoryScreen() {
const rows = [
{ id:'PO-2042', item:'Dredge Cutter Head Parts', vessel:'MV Kestrel', account:'ACC-1140', amount:'$38,500', status:'mgr-review', submitter:'J. Santos', date:'28 Apr' },
{ id:'PO-2041', item:'Hydraulic Pump Seal Kit', vessel:'MV Kestrel', account:'ACC-1140', amount:'$4,200', status:'payment', submitter:'J. Santos', date:'27 Apr' },
{ id:'PO-2039', item:'Navigation Radar Unit', vessel:'MV Osprey', account:'ACC-2290', amount:'$21,000', status:'payment', submitter:'R. Cruz', date:'26 Apr' },
{ id:'PO-2037', item:'Crew Uniforms ×20', vessel:'MV Falcon', account:'ACC-3310', amount:'$2,100', status:'approved', submitter:'M. Reyes', date:'25 Apr' },
{ id:'PO-2033', item:'Anchor Chain Shackles', vessel:'MV Osprey', account:'ACC-2290', amount:'$650', status:'rejected', submitter:'D. Lee', date:'24 Apr' },
{ id:'PO-2031', item:'GPS Transponder', vessel:'MV Kestrel', account:'ACC-1140', amount:'$5,800', status:'approved', submitter:'J. Santos', date:'22 Apr' },
{ id:'PO-2028', item:'Engine Room Extinguisher', vessel:'MV Falcon', account:'ACC-3310', amount:'$3,200', status:'approved', submitter:'M. Reyes', date:'20 Apr' },
];
const st = (s) => {
if (s === 'mgr-review') return <span className="sk-tag orange">Mgr. Review</span>;
if (s === 'payment') return <span className="sk-tag blue">Awaiting Payment</span>;
if (s === 'approved') return <span className="sk-tag green">Paid </span>;
if (s === 'rejected') return <span className="sk-tag red">Rejected</span>;
return <span className="sk-tag gray">{s}</span>;
};
return (
<Shell role="manager" activeNav="Purchase Orders">
<div style={{ display:'flex', flexDirection:'column', gap:14 }}>
<div style={{ display:'flex', alignItems:'center', justifyContent:'space-between' }}>
<div style={{ fontSize:18, fontWeight:700 }}>All Purchase Orders</div>
<div style={{ display:'flex', gap:6 }}>
<div className="sk-btn sm">Export CSV</div>
<div className="sk-btn sm">Export PDF</div>
</div>
</div>
{/* Filters */}
<div style={{ display:'flex', gap:8, flexWrap:'wrap' }}>
<div style={{ display:'flex', alignItems:'center', gap:8, border:'2px solid #aaa', borderRadius:3, padding:'5px 10px', background:'#fff', flex:2 }}>
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="6" cy="6" r="4" stroke="#888" strokeWidth="1.5"/><line x1="9" y1="9" x2="13" y2="13" stroke="#888" strokeWidth="1.5"/></svg>
<span style={{ fontFamily:'Caveat', fontSize:14, color:'#aaa' }}>Search</span>
</div>
<div className="sk-btn sm">Status </div>
<div className="sk-btn sm">Vessel </div>
<div className="sk-btn sm">Account </div>
<div className="sk-btn sm">Date Range </div>
<div className="sk-btn sm">Submitter </div>
</div>
{/* Status tabs */}
<div style={{ display:'flex', gap:0, borderBottom:'2px solid #222' }}>
{[['All','194'],['Mgr. Review','12'],['Awaiting Payment','28'],['Paid','136'],['Rejected','18']].map(([label, count], i) => (
<div key={label} style={{ padding:'6px 16px', borderBottom: i === 0 ? '3px solid #222':'3px solid transparent', marginBottom:-2, fontFamily:'Caveat', fontSize:14, fontWeight: i === 0 ? 700:400, cursor:'default' }}>
{label} <span style={{ fontSize:11, color:'#888' }}>({count})</span>
</div>
))}
</div>
<table className="sk-table">
<thead>
<tr>
<th>PO #</th><th>Item</th><th>Vessel</th><th>Account</th><th>Submitter</th><th>Amount</th><th>Date</th><th>Status</th><th></th>
</tr>
</thead>
<tbody>
{rows.map(r => (
<tr key={r.id}>
<td style={{ color:'#3a7cbf', fontWeight:600 }}>{r.id}</td>
<td>{r.item}</td>
<td>{r.vessel}</td>
<td style={{ color:'#888' }}>{r.account}</td>
<td>{r.submitter}</td>
<td style={{ fontWeight:600 }}>{r.amount}</td>
<td style={{ color:'#888' }}>{r.date}</td>
<td>{st(r.status)}</td>
<td><span style={{ fontSize:12, color:'#3a7cbf', cursor:'default' }}>View </span></td>
</tr>
))}
</tbody>
</table>
<div style={{ fontSize:12, color:'#aaa', textAlign:'center' }}>Showing 7 of 194 total orders</div>
<div className="annotation">Manager can see everything pending & historic with full filter/export </div>
</div>
</Shell>
);
}
/* ─── SCREEN 8: RECEIPT CONFIRMATION ────────────────────── */
function ReceiptConfirmScreen() {
return (
<Shell role="technical" activeNav="My Orders">
<div style={{ display:'flex', gap:16 }}>
<div style={{ flex:2, display:'flex', flexDirection:'column', gap:14 }}>
<div style={{ fontSize:13, color:'#888' }}> My Orders / <span style={{ color:'#222' }}>PO-2038</span></div>
<div style={{ display:'flex', alignItems:'center', gap:10 }}>
<div style={{ fontSize:18, fontWeight:700 }}>Confirm Receipt PO-2038</div>
<span className="sk-tag" style={{ borderColor:'#1a6a3a', color:'#1a6a3a', background:'#e0f4ea' }}>Paid Awaiting Confirmation</span>
</div>
{/* PO Summary read-only */}
<div className="sk-box" style={{ padding:12, background:'#f9f8f5', display:'grid', gridTemplateColumns:'1fr 1fr 1fr', gap:10 }}>
{[['Item','Safety Harnesses ×12'],['Vessel','MV Falcon'],['Account','ACC-3310'],['Vendor','SafeWork Marine Pte'],['Amount Paid','$1,800.00'],['Paid On','27 Apr 2026']].map(([k,v]) => (
<div key={k}>
<span className="wf-label">{k}</span>
<div style={{ fontWeight:600, fontSize:13, marginTop:2 }}>{v}</div>
</div>
))}
</div>
{/* Manager approval note */}
<div style={{ background:'#d8f0e0', border:'1.5px solid #2a8a50', borderRadius:3, padding:'8px 12px', fontSize:13, color:'#1a5a30' }}>
<strong>Manager note:</strong> Ensure ISO-certified supplier. Mgr. Chen, 25 Apr
</div>
{/* Receipt upload */}
<div className="sk-box" style={{ padding:14, display:'flex', flexDirection:'column', gap:10 }}>
<div style={{ fontSize:13, fontWeight:700, borderBottom:'1.5px solid #eee', paddingBottom:6 }}>Upload Receipt / Invoice *</div>
<div className="sk-box filled" style={{ padding:18, textAlign:'center', borderStyle:'dashed', display:'flex', flexDirection:'column', alignItems:'center', gap:6 }}>
<svg width="26" height="26" viewBox="0 0 28 28" fill="none"><rect x="6" y="3" width="16" height="22" rx="2" stroke="#888" strokeWidth="2"/><line x1="10" y1="10" x2="18" y2="10" stroke="#888" strokeWidth="1.5"/><line x1="10" y1="14" x2="18" y2="14" stroke="#888" strokeWidth="1.5"/><line x1="10" y1="18" x2="15" y2="18" stroke="#888" strokeWidth="1.5"/></svg>
<span style={{ fontSize:12, color:'#888' }}>Drop receipt / delivery note / invoice PDF</span>
<div className="sk-btn sm">Browse</div>
</div>
<div style={{ display:'flex', alignItems:'center', gap:8, padding:'6px 8px', background:'#f0ede6', borderRadius:2, fontSize:12 }}>
<span>📄</span>
<span style={{ flex:1 }}>Invoice_SafeWork_Apr2026.pdf</span>
<span style={{ color:'#c03030', cursor:'default' }}></span>
</div>
</div>
{/* Delivery confirmation */}
<div className="sk-box" style={{ padding:14, display:'flex', flexDirection:'column', gap:10 }}>
<div style={{ fontSize:13, fontWeight:700, borderBottom:'1.5px solid #eee', paddingBottom:6 }}>Delivery Confirmation *</div>
<label style={{ display:'flex', gap:10, alignItems:'flex-start', cursor:'pointer' }}>
<div style={{ width:18, height:18, border:'2px solid #222', borderRadius:3, background:'#222', display:'flex', alignItems:'center', justifyContent:'center', flexShrink:0, marginTop:1 }}>
<span style={{ color:'#fff', fontSize:10, fontWeight:700 }}></span>
</div>
<span style={{ fontSize:14, lineHeight:1.4 }}>I confirm that the goods/services for this PO have been received in satisfactory condition.</span>
</label>
<div style={{ display:'flex', flexDirection:'column', gap:4 }}>
<span className="wf-label">Delivery Notes (optional)</span>
<div className="sk-input" style={{ minHeight:48, color:'#bbb' }}>Condition, partial delivery, discrepancies</div>
</div>
</div>
<div style={{ display:'flex', gap:10, justifyContent:'flex-end' }}>
<div className="sk-btn">Save Draft</div>
<div className="sk-btn success">Confirm Receipt & Close PO </div>
</div>
<div className="annotation">Once confirmed PO moves to CLOSED. All parties notified by email. </div>
</div>
{/* Side: full timeline */}
<div style={{ flex:1, display:'flex', flexDirection:'column', gap:12 }}>
<div className="sk-box" style={{ padding:12 }}>
<div style={{ fontSize:13, fontWeight:700, marginBottom:10 }}>PO Timeline</div>
{[
{ label:'Created', sub:'J. Santos · 25 Apr 08:30', done:true },
{ label:'Submitted', sub:'J. Santos · 25 Apr 09:00', done:true },
{ label:'Manager Approved', sub:'Mgr. Chen · 25 Apr 14:22', done:true },
{ label:'Sent for Payment', sub:'Accounts · 26 Apr 10:00', done:true },
{ label:'Payment Processed', sub:'Accounts · 27 Apr 11:05', done:true },
{ label:'Receipt Confirmation', sub:'Awaiting your action ⬅', done:false, active:true },
{ label:'Closed', sub:'—', done:false },
].map((s,i) => (
<div key={i} style={{ display:'flex', gap:8, alignItems:'flex-start', marginBottom:8 }}>
<div style={{ display:'flex', flexDirection:'column', alignItems:'center' }}>
<div style={{ width:16, height:16, borderRadius:'50%', border:'2px solid', borderColor: s.done ? '#2a8a50' : s.active ? '#1a6a3a' : '#ccc', background: s.done ? '#2a8a50' : '#fff', display:'flex', alignItems:'center', justifyContent:'center', flexShrink:0 }}>
{s.done && <span style={{ color:'#fff', fontSize:8, fontWeight:700 }}></span>}
{s.active && <span style={{ color:'#1a6a3a', fontSize:8, fontWeight:700 }}></span>}
</div>
{i < 6 && <div style={{ width:2, height:14, background: s.done ? '#2a8a50':'#e0e0e0', marginTop:2 }}/>}
</div>
<div style={{ paddingTop:1 }}>
<div style={{ fontSize:12, fontWeight: s.active ? 700:400, color: s.done||s.active ? '#222':'#aaa' }}>{s.label}</div>
<div style={{ fontSize:10, color: s.active ? '#1a6a3a':'#aaa' }}>{s.sub}</div>
</div>
</div>
))}
</div>
<div className="sk-box" style={{ padding:12 }}>
<div style={{ fontSize:13, fontWeight:700, marginBottom:6 }}>What happens next?</div>
<div style={{ fontSize:12, color:'#555', lineHeight:1.6 }}>
After you confirm receipt:<br/>
PO status <strong>CLOSED</strong><br/>
Receipt stored on the PO record<br/>
Manager + Accounts notified<br/>
PO visible in Manager history
</div>
</div>
</div>
</div>
</Shell>
);
}
/* ─── MAIN APP ───────────────────────────────────────────────── */
function App() {
const { useState: us } = React;
const [role, setRole] = us('technical');
// Tweaks panel
window.addEventListener('message', (e) => {
if (e.data?.type === '__activate_edit_mode') setShowTweaks(true);
if (e.data?.type === '__deactivate_edit_mode') setShowTweaks(false);
});
const [showTweaks, setShowTweaks] = us(false);
React.useEffect(() => {
window.parent.postMessage({ type: '__edit_mode_available' }, '*');
}, []);
return (
<>
<DesignCanvas title="Pelagia Marine Portal — Wireframes">
{/* Row 1: Entry & Dashboards */}
<DCSection id="s1" title="Authentication & Dashboards">
<DCArtboard id="a1" label="Login Screen" width={320} height={480}>
<LoginScreen/>
</DCArtboard>
<DCArtboard id="a2" label="Dashboard — Technical" width={640} height={480}>
<DashboardScreen role="technical"/>
</DCArtboard>
<DCArtboard id="a3" label="Dashboard — Accounts" width={640} height={480}>
<DashboardScreen role="accounts"/>
</DCArtboard>
<DCArtboard id="a4" label="Dashboard — Manager" width={640} height={480}>
<DashboardScreen role="manager"/>
</DCArtboard>
</DCSection>
{/* Row 2: Submitting & Tracking */}
<DCSection id="s2" title="Submit & Track — Technical / Manning">
<DCArtboard id="a5" label="New PO Form (+ Vendor)" width={720} height={660}>
<NewPOScreen role="technical"/>
</DCArtboard>
<DCArtboard id="a6" label="My Orders — Status Tracker" width={700} height={600}>
<MyOrdersScreen role="technical"/>
</DCArtboard>
<DCArtboard id="a11" label="Receipt Confirmation & Close PO" width={720} height={640}>
<ReceiptConfirmScreen/>
</DCArtboard>
</DCSection>
{/* Row 3: Manager approval */}
<DCSection id="s3" title="Manager Approval Flow">
<DCArtboard id="a7" label="Pending Approvals — Manager" width={680} height={580}>
<ManagerApprovalsScreen/>
</DCArtboard>
<DCArtboard id="a8" label="PO Review & Decision — Manager (+ Vendor)" width={760} height={720}>
<ManagerOrderDetailScreen/>
</DCArtboard>
</DCSection>
{/* Row 4: Accounts payment & history */}
<DCSection id="s4" title="Accounts Payment & History">
<DCArtboard id="a9" label="Payment Queue — Accounts" width={700} height={560}>
<AccountsPaymentScreen/>
</DCArtboard>
<DCArtboard id="a10" label="All POs — Manager History" width={720} height={560}>
<ManagerHistoryScreen/>
</DCArtboard>
</DCSection>
</DesignCanvas>
{/* Tweaks Panel */}
{showTweaks && (
<TweaksPanel onClose={() => {
setShowTweaks(false);
window.parent.postMessage({ type: '__edit_mode_dismissed' }, '*');
}}>
<TweakSection label="Preview Role">
<TweakRadio
label="Role"
options={['technical','accounts','manager','admin','manning']}
value={role}
onChange={v => setRole(v)}
/>
</TweakSection>
</TweaksPanel>
)}
</>
);
}
ReactDOM.createRoot(document.getElementById('root')).render(<App/>);
</script>
<div id="root"></div>
</body>
</html>