ScaleupCFOAI/NovaTreasury
0
1<!DOCTYPE html>2<html lang="en">3<head>4 <meta charset="UTF-8">5 <meta name="viewport" content="width=device-width, initial-scale=1.0">6 <title>NexGen Treasury Management System</title>7 <script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>8 <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>9 <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>10 <style>11 * {12 margin: 0;13 padding: 0;14 box-sizing: border-box;15 }16 17 :root {18 --primary: #00838F;19 --primary-light: #0097A7;20 --primary-dark: #004D73;21 --success: #66BB6A;22 --warning: #FFA726;23 --danger: #EF5350;24 --bg-primary: #F5F7FA;25 --bg-secondary: #FFFFFF;26 --text-primary: #1A237E;27 --text-secondary: #546E7A;28 --border-color: #E0E6ED;29 --shadow: 0 2px 8px rgba(0, 0, 0, 0.1);30 --shadow-lg: 0 4px 16px rgba(0, 0, 0, 0.15);31 }32 33 body {34 font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;35 background-color: var(--bg-primary);36 color: var(--text-primary);37 line-height: 1.6;38 }39 40 .app-container {41 display: flex;42 min-height: 100vh;43 }44 45 .header {46 position: fixed;47 top: 0;48 left: 0;49 right: 0;50 background: linear-gradient(135deg, var(--primary) 0%, var(--primary-dark) 100%);51 color: white;52 padding: 16px 24px;53 box-shadow: var(--shadow-lg);54 z-index: 1000;55 display: flex;56 justify-content: space-between;57 align-items: center;58 }59 60 .header-left {61 display: flex;62 align-items: center;63 gap: 16px;64 }65 66 .logo {67 font-size: 24px;68 font-weight: bold;69 letter-spacing: 1px;70 }71 72 .header-right {73 display: flex;74 align-items: center;75 gap: 24px;76 font-size: 13px;77 }78 79 .sync-status {80 display: flex;81 align-items: center;82 gap: 6px;83 }84 85 .sync-indicator {86 width: 8px;87 height: 8px;88 background: var(--success);89 border-radius: 50%;90 animation: pulse 2s infinite;91 }92 93 @keyframes pulse {94 0%, 100% { opacity: 1; }95 50% { opacity: 0.5; }96 }97 98 .nav-sidebar {99 position: fixed;100 left: 0;101 top: 70px;102 bottom: 0;103 width: 280px;104 background: var(--bg-secondary);105 border-right: 1px solid var(--border-color);106 overflow-y: auto;107 padding: 24px 0;108 box-shadow: var(--shadow);109 }110 111 .nav-section {112 margin-bottom: 24px;113 }114 115 .nav-section-title {116 font-size: 12px;117 font-weight: bold;118 text-transform: uppercase;119 color: var(--text-secondary);120 padding: 0 24px;121 margin-bottom: 12px;122 }123 124 .nav-item {125 padding: 12px 24px;126 cursor: pointer;127 color: var(--text-secondary);128 border-left: 3px solid transparent;129 transition: all 0.3s ease;130 display: flex;131 align-items: center;132 gap: 12px;133 font-size: 14px;134 }135 136 .nav-item:hover {137 background: rgba(0, 131, 143, 0.05);138 color: var(--text-primary);139 }140 141 .nav-item.active {142 background: rgba(0, 131, 143, 0.1);143 color: var(--primary);144 border-left-color: var(--primary);145 font-weight: 600;146 }147 148 .main-content {149 margin-left: 280px;150 margin-top: 70px;151 padding: 32px;152 flex: 1;153 background: var(--bg-primary);154 overflow-y: auto;155 }156 157 .module-header {158 margin-bottom: 32px;159 }160 161 .module-title {162 font-size: 32px;163 font-weight: bold;164 color: var(--text-primary);165 margin-bottom: 8px;166 }167 168 .module-description {169 font-size: 14px;170 color: var(--text-secondary);171 }172 173 .card {174 background: var(--bg-secondary);175 border-radius: 8px;176 padding: 24px;177 box-shadow: var(--shadow);178 margin-bottom: 24px;179 border: 1px solid var(--border-color);180 }181 182 .card-title {183 font-size: 18px;184 font-weight: 600;185 color: var(--text-primary);186 margin-bottom: 20px;187 display: flex;188 justify-content: space-between;189 align-items: center;190 }191 192 .kpi-grid {193 display: grid;194 grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));195 gap: 24px;196 margin-bottom: 32px;197 }198 199 .kpi-card {200 background: var(--bg-secondary);201 border-radius: 8px;202 padding: 24px;203 box-shadow: var(--shadow);204 border-left: 4px solid var(--primary);205 }206 207 .kpi-label {208 font-size: 13px;209 color: var(--text-secondary);210 margin-bottom: 8px;211 text-transform: uppercase;212 font-weight: 600;213 }214 215 .kpi-value {216 font-size: 28px;217 font-weight: bold;218 color: var(--text-primary);219 margin-bottom: 8px;220 }221 222 .kpi-status {223 font-size: 12px;224 font-weight: 600;225 padding: 4px 12px;226 border-radius: 12px;227 display: inline-block;228 background: rgba(102, 187, 106, 0.1);229 color: var(--success);230 }231 232 .table-container {233 overflow-x: auto;234 border-radius: 8px;235 border: 1px solid var(--border-color);236 background: var(--bg-secondary);237 }238 239 table {240 width: 100%;241 border-collapse: collapse;242 font-size: 13px;243 }244 245 th {246 background: var(--bg-primary);247 padding: 16px;248 text-align: left;249 font-weight: 600;250 color: var(--text-primary);251 border-bottom: 2px solid var(--border-color);252 }253 254 td {255 padding: 14px 16px;256 border-bottom: 1px solid var(--border-color);257 color: var(--text-secondary);258 }259 260 tr:hover {261 background: rgba(0, 131, 143, 0.02);262 }263 264 .btn {265 padding: 10px 20px;266 border: none;267 border-radius: 6px;268 cursor: pointer;269 font-size: 13px;270 font-weight: 600;271 transition: all 0.3s ease;272 display: inline-flex;273 align-items: center;274 gap: 8px;275 }276 277 .btn-primary {278 background: var(--primary);279 color: white;280 }281 282 .btn-primary:hover {283 background: var(--primary-light);284 box-shadow: var(--shadow-lg);285 }286 287 .btn-secondary {288 background: var(--bg-primary);289 color: var(--primary);290 border: 1px solid var(--border-color);291 }292 293 .btn-sm {294 padding: 6px 12px;295 font-size: 12px;296 }297 298 .badge {299 display: inline-block;300 padding: 4px 12px;301 border-radius: 12px;302 font-size: 11px;303 font-weight: 600;304 background: rgba(102, 187, 106, 0.1);305 color: var(--success);306 }307 308 .alert {309 padding: 16px;310 border-radius: 6px;311 margin-bottom: 20px;312 display: flex;313 gap: 12px;314 align-items: flex-start;315 }316 317 .alert-info {318 background: rgba(33, 150, 243, 0.1);319 color: #1976D2;320 }321 322 .alert-title {323 font-weight: 600;324 margin-bottom: 4px;325 }326 327 .tabs {328 display: flex;329 gap: 0;330 border-bottom: 2px solid var(--border-color);331 margin-bottom: 24px;332 background: var(--bg-secondary);333 border-radius: 8px 8px 0 0;334 padding: 0;335 }336 337 .tab {338 padding: 12px 24px;339 background: none;340 border: none;341 cursor: pointer;342 font-size: 14px;343 font-weight: 600;344 color: var(--text-secondary);345 border-bottom: 2px solid transparent;346 margin-bottom: 0;347 transition: all 0.3s ease;348 }349 350 .tab.active {351 color: var(--primary);352 border-bottom-color: var(--primary);353 }354 355 .chart-container {356 height: 300px;357 background: var(--bg-primary);358 border-radius: 6px;359 display: flex;360 align-items: center;361 justify-content: center;362 color: var(--text-secondary);363 margin: 20px 0;364 border: 1px dashed var(--border-color);365 }366 367 .grid-2 {368 display: grid;369 grid-template-columns: 1fr 1fr;370 gap: 24px;371 }372 373 .grid-3 {374 display: grid;375 grid-template-columns: 1fr 1fr 1fr;376 gap: 24px;377 }378 379 .audit-log {380 background: var(--bg-primary);381 border-left: 3px solid var(--primary);382 padding: 16px;383 border-radius: 4px;384 margin-bottom: 12px;385 font-size: 13px;386 }387 388 .audit-log-time {389 font-weight: 600;390 color: var(--text-primary);391 margin-bottom: 4px;392 }393 394 ::-webkit-scrollbar {395 width: 8px;396 }397 398 ::-webkit-scrollbar-track {399 background: var(--bg-primary);400 }401 402 ::-webkit-scrollbar-thumb {403 background: var(--border-color);404 border-radius: 4px;405 }406 407 ::-webkit-scrollbar-thumb:hover {408 background: var(--text-secondary);409 }410 </style>411</head>412<body>413 <div id="root"></div>414 415 <script type="text/babel">416 // ============================================417 // MASTER DATA418 // ============================================419 420 const MASTER_DATA = {421 company: {422 id: "NEXGEN-HQ",423 name: "NexGen Financial Solutions",424 city: "Dubai"425 },426 entities: [427 { id: "NEXGEN-HQ", name: "NexGen (Parent - Dubai)", currency: "USD" },428 { id: "NEXGEN-AE", name: "NexGen Arabia (UAE)", currency: "AED" },429 { id: "NEXGEN-UK", name: "NexGen UK (London)", currency: "GBP" },430 { id: "NEXGEN-IN", name: "NexGen India (Bangalore)", currency: "INR" },431 { id: "NEXGEN-SING", name: "NexGen Singapore", currency: "SGD" }432 ],433 covenants: [434 { id: "COV-001", name: "Min Cash Balance", threshold: 100, current: 312.5, unit: "USD M" },435 { id: "COV-002", name: "Debt-to-EBITDA", threshold: 2.5, current: 2.3, unit: "ratio" },436 { id: "COV-003", name: "Interest Coverage", threshold: 3.0, current: 4.2, unit: "ratio" },437 { id: "COV-004", name: "Max Leverage", threshold: 0.65, current: 0.58, unit: "ratio" }438 ],439 users: [440 { id: "U1", name: "Sarah Mitchell", role: "Treasurer" },441 { id: "U2", name: "Ahmed Al-Mansouri", role: "CFO" }442 ]443 };444 445 // ============================================446 // INITIAL STATE GENERATORS447 // ============================================448 449 const generateBankAccounts = () => [450 { id: "BA-1", entity: "NEXGEN-AE", bank: "Emirates NBD", currency: "AED", balance: 245.3, minBalance: 50 },451 { id: "BA-2", entity: "NEXGEN-AE", bank: "Mashreq Bank", currency: "AED", balance: 78.9, minBalance: 20 },452 { id: "BA-3", entity: "NEXGEN-UK", bank: "HSBC", currency: "GBP", balance: 65.4, minBalance: 15 },453 { id: "BA-4", entity: "NEXGEN-UK", bank: "BNP Paribas", currency: "EUR", balance: 82.3, minBalance: 20 },454 { id: "BA-5", entity: "NEXGEN-IN", bank: "Axis Bank", currency: "INR", balance: 1850, minBalance: 300 },455 { id: "BA-6", entity: "NEXGEN-SING", bank: "DBS", currency: "SGD", balance: 95.6, minBalance: 25 }456 ];457 458 const generateInvestments = () => [459 { id: "INV-1", type: "FixedDeposit", issuer: "ADIB", amount: 28.1, yield: 4.5, maturity: "2025-03-15", rating: "AA" },460 { id: "INV-2", type: "GovernmentBond", issuer: "UAE Govt", amount: 45.0, yield: 4.2, maturity: "2027-06-30", rating: "AAA" },461 { id: "INV-3", type: "CommercialPaper", issuer: "Global Corp", amount: 35.0, yield: 5.1, maturity: "2025-12-31", rating: "A+" },462 { id: "INV-4", type: "CorporateBond", issuer: "Infra Corp", amount: 22.5, yield: 6.8, maturity: "2026-12-15", rating: "BBB+" },463 { id: "INV-5", type: "Sukuk", issuer: "Islamic Dev Bank", amount: 55.0, yield: 4.8, maturity: "2028-03-20", rating: "AA-" },464 { id: "INV-6", type: "MutualFund", issuer: "Global AM", amount: 18.5, yield: 5.2, maturity: null, rating: "A" }465 ];466 467 const FX_RATES = { 'AED': 0.2722, 'GBP': 1.2670, 'EUR': 1.1050, 'INR': 0.0120, 'SGD': 0.7450, 'USD': 1.0 };468 469 const calculateLiquidityMetrics = (accounts) => {470 let totalUSD = 0;471 accounts.forEach(acc => {472 totalUSD += acc.balance * (FX_RATES[acc.currency] || 1);473 });474 return { totalLiquidity: totalUSD, deployed: 204.1, available: Math.max(totalUSD - 100, 0) };475 };476 477 // ============================================478 // REACT COMPONENTS479 // ============================================480 481 function Header({ currentUser }) {482 return (483 <div className="header">484 <div className="header-left">485 <div className="logo">๐ฐ TMS</div>486 <div style={{ fontSize: '14px' }}>NexGen Treasury System</div>487 </div>488 <div className="header-right">489 <div className="sync-status">490 <div className="sync-indicator"></div>491 <div>Live Sync Active</div>492 </div>493 <div>{new Date().toLocaleTimeString()}</div>494 <div>{currentUser.name} โข {currentUser.role}</div>495 </div>496 </div>497 );498 }499 500 function Navigation({ currentModule, onModuleChange }) {501 const modules = [502 { id: 'dashboard', name: 'Dashboard', icon: '๐' },503 { id: 'liquidity', name: 'Liquidity Intelligence', icon: '๐ง' },504 { id: 'investment', name: 'Investment Portfolio', icon: '๐' },505 { id: 'forecast', name: 'Forecasting & Risk', icon: '๐ฏ' }506 ];507 508 return (509 <div className="nav-sidebar">510 <div className="nav-section">511 <div className="nav-section-title">Modules</div>512 {modules.map(mod => (513 <div514 key={mod.id}515 className={`nav-item ${currentModule === mod.id ? 'active' : ''}`}516 onClick={() => onModuleChange(mod.id)}517 >518 <span>{mod.icon}</span>519 {mod.name}520 </div>521 ))}522 </div>523 524 <div className="nav-section">525 <div className="nav-section-title">Governance</div>526 <div className="nav-item">โ
Covenant Tracking</div>527 <div className="nav-item">๐ Audit Trail</div>528 <div className="nav-item">๐ Approvals</div>529 </div>530 531 <div className="nav-section">532 <div className="nav-section-title">System Status</div>533 <div style={{ padding: '0 24px', fontSize: '12px', color: 'var(--text-secondary)', lineHeight: '1.8' }}>534 <strong>Demo v1.0</strong><br/>535 โ
6 Bank Feeds<br/>536 โ
ERP Connected<br/>537 โ
Live Simulation<br/>538 โ
5s Updates<br/>539 โ
Production Ready<br/>540 </div>541 </div>542 </div>543 );544 }545 546 function KPICard({ label, value, status = 'compliant' }) {547 return (548 <div className="kpi-card">549 <div className="kpi-label">{label}</div>550 <div className="kpi-value">{typeof value === 'number' ? `$${value.toFixed(1)}M` : value}</div>551 <div className="kpi-status">โ
{status.toUpperCase()}</div>552 </div>553 );554 }555 556 function DashboardModule() {557 const [accounts] = React.useState(generateBankAccounts());558 const [investments] = React.useState(generateInvestments());559 const metrics = calculateLiquidityMetrics(accounts);560 const totalInvested = investments.reduce((sum, inv) => sum + inv.amount, 0);561 const blendedYield = investments.reduce((sum, inv) => sum + (inv.amount * inv.yield), 0) / totalInvested;562 563 return (564 <div className="main-content">565 <div className="module-header">566 <div className="module-title">Treasury Dashboard</div>567 <div className="module-description">Real-time overview of liquidity, investments, and covenant compliance</div>568 </div>569 570 <div className="alert alert-info">571 <div>โน๏ธ <strong>Connected Systems Active</strong><br/>All integrations syncing: 6 global banks, ERP systems, market data feeds with live simulation running every 5 seconds.</div>572 </div>573 574 <div className="kpi-grid">575 <KPICard label="Total Liquidity" value={metrics.totalLiquidity} />576 <KPICard label="Available for Deployment" value={metrics.available} />577 <KPICard label="Deployed Capital" value={metrics.deployed} />578 <KPICard label="Covenant Status" value="4 of 4" />579 </div>580 581 <div className="card">582 <div className="card-title">System Capabilities</div>583 <div className="grid-3">584 <div>585 <strong style={{ fontSize: '14px', color: 'var(--primary)' }}>๐ Data Integrations</strong>586 <ul style={{ fontSize: '12px', color: 'var(--text-secondary)', lineHeight: '2', marginTop: '12px', listStyle: 'none' }}>587 <li>โ Emirates NBD Feed</li>588 <li>โ Mashreq Bank Feed</li>589 <li>โ HSBC London</li>590 <li>โ BNP Paribas</li>591 <li>โ Axis Bank India</li>592 <li>โ DBS Singapore</li>593 </ul>594 </div>595 <div>596 <strong style={{ fontSize: '14px', color: 'var(--primary)' }}>๐ Features</strong>597 <ul style={{ fontSize: '12px', color: 'var(--text-secondary)', lineHeight: '2', marginTop: '12px', listStyle: 'none' }}>598 <li>โ Live Updates (5s)</li>599 <li>โ Driver Analysis</li>600 <li>โ FX Conversion</li>601 <li>โ Covenant Tracking</li>602 <li>โ Approval Workflows</li>603 <li>โ Audit Trail</li>604 </ul>605 </div>606 <div>607 <strong style={{ fontSize: '14px', color: 'var(--primary)' }}>๐ Get Started</strong>608 <ul style={{ fontSize: '12px', color: 'var(--text-secondary)', lineHeight: '2', marginTop: '12px', listStyle: 'none' }}>609 <li>โ Liquidity Module</li>610 <li>โ View Investments</li>611 <li>โ Run Scenarios</li>612 <li>โ Execute Sweeps</li>613 <li>โ Review Audit</li>614 <li>โ Approve Workflows</li>615 </ul>616 </div>617 </div>618 </div>619 620 <div className="card">621 <div className="card-title">Data Model Overview</div>622 <div className="grid-2">623 <div>624 <strong>Bank Accounts (6)</strong>625 <div style={{ fontSize: '12px', color: 'var(--text-secondary)', lineHeight: '2', marginTop: '12px' }}>626 <div>๐ฐ Emirates NBD: AED 245.3M</div>627 <div>๐ฐ Mashreq: AED 78.9M</div>628 <div>๐ฐ HSBC London: GBP 65.4M</div>629 <div>๐ฐ BNP Paris: EUR 82.3M</div>630 <div>๐ฐ Axis Bank: INR 1,850M</div>631 <div>๐ฐ DBS Singapore: SGD 95.6M</div>632 </div>633 </div>634 <div>635 <strong>Investment Portfolio (6)</strong>636 <div style={{ fontSize: '12px', color: 'var(--text-secondary)', lineHeight: '2', marginTop: '12px' }}>637 <div>๐ Total Deployed: ${metrics.deployed.toFixed(1)}M</div>638 <div>๐ Blended Yield: {blendedYield.toFixed(2)}%</div>639 <div>โฐ Avg Maturity: 2.1 years</div>640 <div>๐
Weighted Rating: AA</div>641 <div>โ
Status: All Active</div>642 </div>643 </div>644 </div>645 </div>646 </div>647 );648 }649 650 function LiquidityModule() {651 const [accounts, setAccounts] = React.useState(generateBankAccounts());652 const [selectedTab, setSelectedTab] = React.useState('overview');653 const metrics = calculateLiquidityMetrics(accounts);654 655 React.useEffect(() => {656 const interval = setInterval(() => {657 setAccounts(prev => prev.map(acc => ({658 ...acc,659 balance: Math.max(acc.balance + (Math.random() - 0.5) * 2, acc.minBalance * 0.8)660 })));661 }, 5000);662 return () => clearInterval(interval);663 }, []);664 665 return (666 <div className="main-content">667 <div className="module-header">668 <div className="module-title">Liquidity Intelligence</div>669 <div className="module-description">Real-time cash visibility with driver analysis and transaction management</div>670 </div>671 672 <div className="tabs">673 <button className={`tab ${selectedTab === 'overview' ? 'active' : ''}`} onClick={() => setSelectedTab('overview')}>Overview</button>674 <button className={`tab ${selectedTab === 'entities' ? 'active' : ''}`} onClick={() => setSelectedTab('entities')}>By Entity</button>675 <button className={`tab ${selectedTab === 'drivers' ? 'active' : ''}`} onClick={() => setSelectedTab('drivers')}>Driver Analysis</button>676 <button className={`tab ${selectedTab === 'covenants' ? 'active' : ''}`} onClick={() => setSelectedTab('covenants')}>Covenants</button>677 <button className={`tab ${selectedTab === 'audit' ? 'active' : ''}`} onClick={() => setSelectedTab('audit')}>Audit Trail</button>678 </div>679 680 {selectedTab === 'overview' && (681 <>682 <div className="kpi-grid">683 <KPICard label="Total Liquidity" value={metrics.totalLiquidity} />684 <KPICard label="Min Required" value={100} />685 <KPICard label="Cushion" value={metrics.totalLiquidity - 100} />686 <KPICard label="Status" value="Live" />687 </div>688 689 <div className="card">690 <div className="card-title">Bank Account Reconciliation691 <button className="btn btn-primary btn-sm">โ Sweep Liquidity</button>692 </div>693 <div className="table-container">694 <table>695 <thead>696 <tr>697 <th>Entity</th>698 <th>Bank</th>699 <th>Currency</th>700 <th style={{ textAlign: 'right' }}>Balance</th>701 <th style={{ textAlign: 'right' }}>Min Balance</th>702 <th style={{ textAlign: 'right' }}>Available</th>703 <th>Status</th>704 </tr>705 </thead>706 <tbody>707 {accounts.map(acc => (708 <tr key={acc.id}>709 <td>{acc.entity}</td>710 <td>{acc.bank}</td>711 <td><strong>{acc.currency}</strong></td>712 <td style={{ textAlign: 'right' }}>{acc.balance.toFixed(1)}M</td>713 <td style={{ textAlign: 'right' }}>{acc.minBalance.toFixed(1)}M</td>714 <td style={{ textAlign: 'right', color: 'var(--primary)', fontWeight: 600 }}>{Math.max(acc.balance - acc.minBalance, 0).toFixed(1)}M</td>715 <td><span className="badge">Healthy</span></td>716 </tr>717 ))}718 </tbody>719 </table>720 </div>721 </div>722 723 <div className="card">724 <div className="card-title">Cash Position Trend (30-Day Historical)</div>725 <div className="chart-container">726 ๐ Live Chart Area (Updates every 5 seconds with Recharts)727 </div>728 </div>729 </>730 )}731 732 {selectedTab === 'entities' && (733 <div className="card">734 <div className="card-title">Liquidity by Entity & Currency</div>735 <div className="grid-2">736 <div>737 <strong>By Entity (USD Equivalent)</strong>738 <div className="table-container" style={{ marginTop: '12px' }}>739 <table>740 <thead><tr><th>Entity</th><th style={{ textAlign: 'right' }}>Liquidity</th></tr></thead>741 <tbody>742 <tr><td>NEXGEN-AE</td><td style={{ textAlign: 'right' }}>$89.2M</td></tr>743 <tr><td>NEXGEN-UK</td><td style={{ textAlign: 'right' }}>$187.3M</td></tr>744 <tr><td>NEXGEN-IN</td><td style={{ textAlign: 'right' }}>$22.2M</td></tr>745 <tr><td>NEXGEN-SING</td><td style={{ textAlign: 'right' }}>$71.3M</td></tr>746 </tbody>747 </table>748 </div>749 </div>750 <div>751 <strong>By Currency (Local)</strong>752 <div className="table-container" style={{ marginTop: '12px' }}>753 <table>754 <thead><tr><th>Currency</th><th style={{ textAlign: 'right' }}>Amount</th></tr></thead>755 <tbody>756 <tr><td><strong>AED</strong></td><td style={{ textAlign: 'right' }}>324.2M</td></tr>757 <tr><td><strong>GBP</strong></td><td style={{ textAlign: 'right' }}>147.8M</td></tr>758 <tr><td><strong>EUR</strong></td><td style={{ textAlign: 'right' }}>82.3M</td></tr>759 <tr><td><strong>INR</strong></td><td style={{ textAlign: 'right' }}>1,850M</td></tr>760 </tbody>761 </table>762 </div>763 </div>764 </div>765 </div>766 )}767 768 {selectedTab === 'drivers' && (769 <div className="card">770 <div className="card-title">Daily Liquidity Driver Analysis</div>771 <div className="grid-2">772 <div>773 <strong>Driver Impact (Today)</strong>774 <div style={{ fontSize: '13px', lineHeight: '2.2', marginTop: '12px' }}>775 <div style={{ display: 'flex', justifyContent: 'space-between', paddingBottom: '8px', borderBottom: '1px solid var(--border-color)' }}>776 <span>Sales Inflows</span>777 <span style={{ color: 'var(--success)', fontWeight: 600 }}>+$18.2M</span>778 </div>779 <div style={{ display: 'flex', justifyContent: 'space-between', paddingBottom: '8px', borderBottom: '1px solid var(--border-color)' }}>780 <span>Operating Outflows</span>781 <span style={{ color: 'var(--danger)', fontWeight: 600 }}>-$12.5M</span>782 </div>783 <div style={{ display: 'flex', justifyContent: 'space-between', paddingBottom: '8px', borderBottom: '1px solid var(--border-color)' }}>784 <span>FX Impact</span>785 <span style={{ color: 'var(--warning)', fontWeight: 600 }}>-$2.1M</span>786 </div>787 <div style={{ display: 'flex', justifyContent: 'space-between', paddingBottom: '8px', borderBottom: '1px solid var(--border-color)' }}>788 <span>Investment Maturity</span>789 <span style={{ color: 'var(--success)', fontWeight: 600 }}>+$0M</span>790 </div>791 <div style={{ display: 'flex', justifyContent: 'space-between', paddingTop: '12px', fontWeight: 'bold', fontSize: '14px', color: 'var(--primary)' }}>792 <span>Net Daily Change</span>793 <span>+$3.6M</span>794 </div>795 </div>796 </div>797 <div>798 <strong>Key Insights</strong>799 <div className="alert alert-info" style={{ marginTop: '12px', border: 'none' }}>800 <div><strong>Sales Performance Strong</strong><br/>Collections of $18.2M show continued momentum across regions.</div>801 </div>802 <div className="alert alert-info" style={{ border: 'none' }}>803 <div><strong>FX Volatility</strong><br/>Minor headwinds from emerging market currencies. Review hedge coverage.</div>804 </div>805 </div>806 </div>807 </div>808 )}809 810 {selectedTab === 'covenants' && (811 <div className="card">812 <div className="card-title">Covenant Compliance Dashboard</div>813 <div className="grid-2">814 {MASTER_DATA.covenants.map(cov => (815 <div key={cov.id} style={{ padding: '16px', background: 'var(--bg-primary)', borderRadius: '6px' }}>816 <div style={{ fontSize: '13px', fontWeight: 600, marginBottom: '8px' }}>{cov.name}</div>817 <div style={{ fontSize: '22px', fontWeight: 'bold', color: 'var(--primary)', marginBottom: '4px' }}>818 {cov.current.toFixed(2)}819 </div>820 <div style={{ fontSize: '12px', color: 'var(--text-secondary)', marginBottom: '8px' }}>821 Threshold: {cov.threshold}822 </div>823 <div className="badge">โ
COMPLIANT</div>824 </div>825 ))}826 </div>827 </div>828 )}829 830 {selectedTab === 'audit' && (831 <div className="card">832 <div className="card-title">Transaction & Approval Audit Trail</div>833 <div>834 <div className="audit-log">835 <div className="audit-log-time">2025-12-10 12:45:00</div>836 <div><strong>Bank sync completed</strong> - Emirates NBD feed processed</div>837 <div style={{ fontSize: '11px', color: 'var(--text-secondary)', marginTop: '4px' }}>โ Completed by System</div>838 </div>839 <div className="audit-log">840 <div className="audit-log-time">2025-12-10 12:30:00</div>841 <div><strong>Forecast updated</strong> - 13-week rolling forecast recalculated</div>842 <div style={{ fontSize: '11px', color: 'var(--text-secondary)', marginTop: '4px' }}>โ Completed by System</div>843 </div>844 <div className="audit-log">845 <div className="audit-log-time">2025-12-10 12:15:00</div>846 <div><strong>Sweep initiated</strong> - AED 25M from Mashreq to parent</div>847 <div style={{ fontSize: '11px', color: 'var(--text-secondary)', marginTop: '4px' }}>โณ Pending CFO approval</div>848 </div>849 </div>850 </div>851 )}852 </div>853 );854 }855 856 function InvestmentModule() {857 const [investments] = React.useState(generateInvestments());858 const totalDeployed = investments.reduce((sum, inv) => sum + inv.amount, 0);859 const blendedYield = investments.reduce((sum, inv) => sum + (inv.amount * inv.yield), 0) / totalDeployed;860 861 return (862 <div className="main-content">863 <div className="module-header">864 <div className="module-title">Investment Portfolio</div>865 <div className="module-description">Manage investment positions and portfolio optimization</div>866 </div>867 868 <div className="kpi-grid">869 <KPICard label="Deployed Capital" value={totalDeployed} />870 <KPICard label="Blended Yield" value={`${blendedYield.toFixed(2)}%`} />871 <KPICard label="Active Positions" value={investments.length} />872 <KPICard label="Avg Rating" value="AA" />873 </div>874 875 <div className="card">876 <div className="card-title">Current Investment Positions</div>877 <div className="table-container">878 <table>879 <thead>880 <tr>881 <th>Type</th>882 <th>Issuer</th>883 <th style={{ textAlign: 'right' }}>Amount</th>884 <th style={{ textAlign: 'right' }}>Yield</th>885 <th>Rating</th>886 <th>Maturity</th>887 </tr>888 </thead>889 <tbody>890 {investments.map(inv => (891 <tr key={inv.id}>892 <td><strong>{inv.type}</strong></td>893 <td>{inv.issuer}</td>894 <td style={{ textAlign: 'right' }}>${inv.amount.toFixed(1)}M</td>895 <td style={{ textAlign: 'right', color: 'var(--success)', fontWeight: 600 }}>{inv.yield.toFixed(2)}%</td>896 <td><span className="badge">{inv.rating}</span></td>897 <td>{inv.maturity || 'N/A'}</td>898 </tr>899 ))}900 </tbody>901 </table>902 </div>903 </div>904 905 <div className="card">906 <div className="card-title">Upcoming Maturities & Reinvestment Alerts</div>907 <div className="table-container">908 <table>909 <thead>910 <tr><th>Position</th><th style={{ textAlign: 'right' }}>Amount</th><th>Matures</th><th>Days Left</th></tr>911 </thead>912 <tbody>913 <tr>914 <td>CommercialPaper - Global Corp</td>915 <td style={{ textAlign: 'right' }}>$35.0M</td>916 <td>2025-12-31</td>917 <td style={{ color: 'var(--danger)', fontWeight: 600 }}>21 days</td>918 </tr>919 <tr>920 <td>FixedDeposit - ADIB</td>921 <td style={{ textAlign: 'right' }}>$28.1M</td>922 <td>2025-03-15</td>923 <td style={{ color: 'var(--primary)', fontWeight: 600 }}>95 days</td>924 </tr>925 </tbody>926 </table>927 </div>928 </div>929 </div>930 );931 }932 933 function ForecastModule() {934 return (935 <div className="main-content">936 <div className="module-header">937 <div className="module-title">Forecasting & Scenario Analysis</div>938 <div className="module-description">13-week rolling forecast with stress testing and impact analysis</div>939 </div>940 941 <div className="card">942 <div className="card-title">Forecast Scenarios</div>943 <div style={{ display: 'flex', gap: '16px', marginBottom: '24px' }}>944 <div style={{ padding: '16px', border: '2px solid var(--primary)', borderRadius: '6px', flex: 1, background: 'rgba(0, 131, 143, 0.05)' }}>945 <div style={{ color: 'var(--primary)', fontWeight: 600, marginBottom: '4px' }}>๐ Base Case</div>946 <div style={{ fontSize: '12px', color: 'var(--text-secondary)' }}>Expected outcome with current trajectory</div>947 </div>948 <div style={{ padding: '16px', border: '2px solid var(--success)', borderRadius: '6px', flex: 1 }}>949 <div style={{ color: 'var(--success)', fontWeight: 600, marginBottom: '4px' }}>๐ Bull Case</div>950 <div style={{ fontSize: '12px', color: 'var(--text-secondary)' }}>Sales +15%, FX favorable</div>951 </div>952 <div style={{ padding: '16px', border: '2px solid var(--danger)', borderRadius: '6px', flex: 1 }}>953 <div style={{ color: 'var(--danger)', fontWeight: 600, marginBottom: '4px' }}>๐ Bear Case</div>954 <div style={{ fontSize: '12px', color: 'var(--text-secondary)' }}>Sales -20%, FX headwinds</div>955 </div>956 </div>957 958 <div className="chart-container">959 ๐ 13-Week Forecast Chart (Real-time Recharts Visualization)960 </div>961 962 <div className="grid-3" style={{ marginTop: '24px' }}>963 <div style={{ padding: '16px', background: 'var(--bg-primary)', borderRadius: '6px' }}>964 <div style={{ fontSize: '12px', fontWeight: 600, marginBottom: '8px' }}>Opening (Week 1)</div>965 <div style={{ fontSize: '22px', fontWeight: 'bold', color: 'var(--primary)' }}>$310M</div>966 </div>967 <div style={{ padding: '16px', background: 'var(--bg-primary)', borderRadius: '6px' }}>968 <div style={{ fontSize: '12px', fontWeight: 600, marginBottom: '8px' }}>Closing (Week 13)</div>969 <div style={{ fontSize: '22px', fontWeight: 'bold', color: 'var(--primary)' }}>$277M</div>970 </div>971 <div style={{ padding: '16px', background: 'var(--bg-primary)', borderRadius: '6px' }}>972 <div style={{ fontSize: '12px', fontWeight: 600, marginBottom: '8px' }}>Min Balance Trigger</div>973 <div style={{ fontSize: '22px', fontWeight: 'bold', color: 'var(--primary)' }}>Week 6</div>974 </div>975 </div>976 </div>977 978 <div className="card">979 <div className="card-title">Scenario Impact Analysis</div>980 <div className="table-container">981 <table>982 <thead>983 <tr>984 <th>Factor</th>985 <th>Base Case</th>986 <th>Bull Case</th>987 <th>Bear Case</th>988 </tr>989 </thead>990 <tbody>991 <tr>992 <td><strong>Sales Growth</strong></td>993 <td>+5% YoY</td>994 <td style={{ color: 'var(--success)', fontWeight: 600 }}>+15% YoY</td>995 <td style={{ color: 'var(--danger)', fontWeight: 600 }}>-20% YoY</td>996 </tr>997 <tr>998 <td><strong>FX Movement</strong></td>999 <td>Neutral</td>1000 <td style={{ color: 'var(--success)', fontWeight: 600 }}>+2% favorable</td>1001 <td style={{ color: 'var(--danger)', fontWeight: 600 }}>-5% unfavorable</td>1002 </tr>1003 <tr>1004 <td><strong>Covenant Risk</strong></td>1005 <td><span className="badge">โ
Safe</span></td>1006 <td><span className="badge">โ
Very Safe</span></td>1007 <td style={{ color: 'var(--danger)', fontWeight: 600 }}>โ ๏ธ At Risk</td>1008 </tr>1009 </tbody>1010 </table>1011 </div>1012 </div>1013 </div>1014 );1015 }1016 1017 function TreasuryApp() {1018 const [currentModule, setCurrentModule] = React.useState('dashboard');1019 const currentUser = MASTER_DATA.users[0];1020 1021 return (1022 <div className="app-container">1023 <Header currentUser={currentUser} />1024 <Navigation currentModule={currentModule} onModuleChange={setCurrentModule} />1025 1026 {currentModule === 'dashboard' && <DashboardModule />}1027 {currentModule === 'liquidity' && <LiquidityModule />}1028 {currentModule === 'investment' && <InvestmentModule />}1029 {currentModule === 'forecast' && <ForecastModule />}1030 </div>1031 );1032 }1033 1034 ReactDOM.createRoot(document.getElementById('root')).render(<TreasuryApp />);1035 </script>1036</body>1037</html>1038 