marco.asseto.prototype/asset-detail.html

700 lines
38 KiB
HTML
Raw Permalink 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>Asset Detail | AMS</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
<link rel="stylesheet" href="css/styles.css">
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
</head>
<body>
<div class="app-layout">
<!-- SIDEBAR -->
<aside class="sidebar" id="appSidebar"></aside>
<!-- MAIN -->
<div class="main-wrapper">
<header class="topbar">
<div class="topbar-left">
<button onclick="history.back()" class="btn btn-ghost btn-sm" style="margin-right:6px">← Back</button>
<div class="topbar-title" id="assetHeaderTitle">Asset Detail</div>
</div>
<div class="topbar-actions">
<button class="btn btn-secondary btn-sm" onclick="openModal('editModal')">✏️ Edit</button>
<button class="btn btn-secondary btn-sm" onclick="openModal('assignModal')">👤 Assign</button>
<button class="btn btn-secondary btn-sm" onclick="openModal('transferModal')">↔ Transfer</button>
<button class="btn btn-danger btn-sm" onclick="confirmDispose()">🗑️ Dispose</button>
<a href="index.html" class="icon-btn" title="Logout"><i data-lucide="log-out"></i></a>
</div>
</header>
<main class="content">
<!-- Asset Header -->
<div class="card mb-4" id="assetHeader"></div>
<!-- Tabs -->
<div class="tab-container">
<div class="tabs" data-group="detail">
<button class="tab-btn active" data-tab="tab-overview" data-group="detail">📋 Overview</button>
<button class="tab-btn" data-tab="tab-financial" data-group="detail">💰 Financial</button>
<button class="tab-btn" data-tab="tab-assignments" data-group="detail">👤 Assignments</button>
<button class="tab-btn" data-tab="tab-maintenance" data-group="detail">🔧 Maintenance</button>
<button class="tab-btn" data-tab="tab-documents" data-group="detail">📄 Documents</button>
<button class="tab-btn" data-tab="tab-history" data-group="detail">🕐 History</button>
</div>
<!-- Overview Tab -->
<div class="tab-content active" id="tab-overview" data-group="detail">
<div class="grid-2">
<div class="card">
<div class="card-header"><span class="card-title">📋 Asset Information</span></div>
<div class="card-body" id="assetInfoGrid"></div>
</div>
<div class="card">
<div class="card-header"><span class="card-title">📍 Location & Assignment</span></div>
<div class="card-body" id="assetLocationGrid"></div>
</div>
</div>
<div class="grid-2 mt-4">
<div class="card">
<div class="card-header"><span class="card-title">📱 QR Code</span>
<button class="btn btn-secondary btn-sm" onclick="printQR()">🖨️ Print</button></div>
<div class="card-body" style="text-align:center" id="assetQR"></div>
</div>
<div class="card">
<div class="card-header"><span class="card-title">🔧 Custom Fields</span></div>
<div class="card-body" id="assetCustomFields"></div>
</div>
</div>
</div>
<!-- Financial Tab -->
<div class="tab-content" id="tab-financial" data-group="detail">
<div class="grid-2">
<div class="card">
<div class="card-header"><span class="card-title">💰 Depreciation</span></div>
<div class="card-body">
<div id="depreciationInfo"></div>
<canvas id="depChart" height="180"></canvas>
</div>
</div>
<div class="card">
<div class="card-header"><span class="card-title">📊 Value Summary</span></div>
<div class="card-body" id="valueSummary"></div>
</div>
</div>
</div>
<!-- Assignments Tab -->
<div class="tab-content" id="tab-assignments" data-group="detail">
<div class="card">
<div class="card-header"><span class="card-title">👤 Assignment History</span>
<button class="btn btn-primary btn-sm" onclick="openModal('assignModal')">+ New Assignment</button>
</div>
<div class="card-body" id="assignmentHistory"></div>
</div>
</div>
<!-- Maintenance Tab -->
<div class="tab-content" id="tab-maintenance" data-group="detail">
<div class="card">
<div class="card-header"><span class="card-title">🔧 Maintenance Records</span>
<a href="maintenance.html" class="btn btn-secondary btn-sm">+ Raise Ticket</a>
</div>
<div class="card-body" id="maintenanceRecords"></div>
</div>
</div>
<!-- Documents Tab -->
<div class="tab-content" id="tab-documents" data-group="detail">
<div class="card">
<div class="card-header"><span class="card-title">📄 Documents</span>
<button class="btn btn-primary btn-sm" onclick="showToast('Upload','Document upload dialog','info')">📎 Upload</button>
</div>
<div class="card-body" id="assetDocs"></div>
</div>
</div>
<!-- History Tab -->
<div class="tab-content" id="tab-history" data-group="detail">
<div class="card">
<div class="card-header"><span class="card-title">🕐 Audit Trail</span></div>
<div class="card-body" id="auditTrail"></div>
</div>
</div>
</div>
</main>
</div>
</div>
<!-- Edit Modal -->
<div class="modal-overlay" id="editModal">
<div class="modal modal-lg">
<div class="modal-header"><span class="modal-title">Edit Asset</span><button class="modal-close"></button></div>
<div class="modal-body">
<div class="form-row">
<div class="form-group"><label class="form-label">Asset Name <span class="req">*</span></label><input class="form-input" id="editName"></div>
<div class="form-group"><label class="form-label">Serial Number / License Key</label><input class="form-input" id="editSerial"></div>
</div>
<div class="form-row">
<div class="form-group"><label class="form-label">Category</label><select class="form-select" id="editCat"><option>Laptops</option><option>Desktops</option><option>Servers</option><option>Printers</option><option>Networking</option><option>Vehicles</option><option>Furniture</option><option>HVAC</option><option>Software Licenses</option><option>Cloud Subscriptions</option></select></div>
<div class="form-group"><label class="form-label">Status</label><select class="form-select" id="editStatus"><option>Active</option><option>Idle</option><option>Under Maintenance</option><option>Disposed</option></select></div>
</div>
<!-- Digital-only fields inside Edit Modal -->
<div class="form-row" id="editDigitalRow" style="display:none">
<div class="form-group"><label class="form-label">Total Seats</label><input type="number" class="form-input" id="editSeatsTotal"></div>
<div class="form-group"><label class="form-label">Allocated Seats</label><input type="number" class="form-input" id="editSeatsAlloc"></div>
</div>
<div class="form-group"><label class="form-label">Change Reason (for audit trail) <span class="req">*</span></label><textarea class="form-textarea" id="editReason" rows="2" placeholder="Why is this being updated?"></textarea></div>
</div>
<div class="modal-footer">
<button class="btn btn-ghost" onclick="closeModal('editModal')">Cancel</button>
<button class="btn btn-primary" onclick="saveEdit()">Save Changes</button>
</div>
</div>
</div>
<!-- Assign Modal -->
<div class="modal-overlay" id="assignModal">
<div class="modal">
<div class="modal-header"><span class="modal-title">Assign Asset</span><button class="modal-close"></button></div>
<div class="modal-body">
<div class="form-group">
<label class="form-label">Assign Type</label>
<div class="flex gap-4" style="margin-bottom:8px">
<label style="cursor:pointer; font-size:13px"><input type="radio" name="assignType" value="user" checked onchange="toggleAssignType()"> Employee</label>
<label style="cursor:pointer; font-size:13px"><input type="radio" name="assignType" value="project" onchange="toggleAssignType()"> Project</label>
</div>
</div>
<div class="form-group" id="assignUserGroup">
<label class="form-label">Employee <span class="req">*</span></label>
<select class="form-select" id="assignUserSelect">
<option value="">Select Employee…</option>
</select>
</div>
<div class="form-group" id="assignProjectGroup" style="display:none">
<label class="form-label">Project <span class="req">*</span></label>
<select class="form-select" id="assignProjectSelect">
<option value="">Select Project…</option>
</select>
</div>
<div class="form-row">
<div class="form-group"><label class="form-label">From Date</label><input type="date" class="form-input" id="assignFromDate" value="2026-06-04"></div>
<div class="form-group"><label class="form-label">Return By (optional)</label><input type="date" class="form-input" id="assignReturnDate"></div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-ghost" onclick="closeModal('assignModal')">Cancel</button>
<button class="btn btn-primary" onclick="doAssign()">Assign</button>
</div>
</div>
</div>
<!-- Transfer Modal -->
<div class="modal-overlay" id="transferModal">
<div class="modal">
<div class="modal-header"><span class="modal-title">Transfer Asset</span><button class="modal-close"></button></div>
<div class="modal-body">
<div class="form-row">
<div class="form-group"><label class="form-label">To Department</label>
<select class="form-select"><option>IT</option><option>Finance</option><option>HR</option><option>Operations</option><option>Marketing</option><option>Admin</option></select>
</div>
<div class="form-group"><label class="form-label">To Location</label>
<select class="form-select"><option>IT Dept Floor 2</option><option>Finance Floor 1</option><option>Server Room B1</option><option>HR Floor 2</option><option>Marketing Floor 3</option></select>
</div>
</div>
<div class="form-group"><label class="form-label">Reason</label>
<select class="form-select"><option>Department Restructuring</option><option>Employee Transfer</option><option>Better Utilization</option><option>Other</option></select>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-ghost" onclick="closeModal('transferModal')">Cancel</button>
<button class="btn btn-primary" onclick="doTransfer()">Transfer</button>
</div>
</div>
</div>
<div class="modal-overlay" id="confirmModal">
<div class="modal" style="max-width:400px">
<div class="modal-header"><span class="modal-title confirm-title">Confirm</span><button class="modal-close"></button></div>
<div class="modal-body"><p class="confirm-message" style="color:var(--text-secondary)"></p></div>
<div class="modal-footer"><button class="btn btn-ghost" onclick="closeModal('confirmModal')">Cancel</button><button class="btn btn-danger confirm-ok">Confirm</button></div>
</div>
</div>
<div class="toast-container" id="toastContainer"></div>
<script src="https://unpkg.com/lucide@latest"></script>
<script src="js/data.js"></script>
<script src="js/sidebar.js"></script>
<script src="js/app.js"></script>
<script>
const params = new URLSearchParams(window.location.search);
const assetId = params.get('id') || 'AST-2025-001';
let asset = AMS.assets.find(a => a.id === assetId) || AMS.assets[0];
document.addEventListener('DOMContentLoaded', () => {
document.title = `${asset.name} | AMS`;
renderHeader();
renderOverview();
renderFinancial();
renderAssignments();
renderMaintenance();
renderDocuments();
renderHistory();
initTabs();
// Populate Edit Modal fields
document.getElementById('editName').value = asset.name;
document.getElementById('editSerial').value = asset.serial || asset.licenseKey || '';
document.getElementById('editCat').value = asset.cat;
document.getElementById('editStatus').value = asset.status;
if (asset.type === 'digital') {
document.getElementById('editDigitalRow').style.display = '';
document.getElementById('editSeatsTotal').value = asset.seatsTotal || 1;
document.getElementById('editSeatsAlloc').value = asset.seatsAlloc || 0;
}
// Populate Assign modal employee dropdown
const userSelect = document.getElementById('assignUserSelect');
if (userSelect && AMS.users) {
userSelect.innerHTML = '<option value="">Select Employee…</option>';
AMS.users.forEach(u => {
const o = document.createElement('option');
o.value = u.name;
o.textContent = `${u.name} ${u.role} (${u.dept})`;
if (asset.assignee === u.name) o.selected = true;
userSelect.appendChild(o);
});
}
// Populate Assign modal project dropdown
const projSelect = document.getElementById('assignProjectSelect');
if (projSelect && AMS.projects) {
projSelect.innerHTML = '<option value="">Select Project…</option>';
AMS.projects.forEach(p => {
const o = document.createElement('option');
o.value = p.name;
o.textContent = `${p.name} (${p.dept})`;
if (asset.project === p.name) o.selected = true;
projSelect.appendChild(o);
});
}
});
function toggleAssignType() {
const type = document.querySelector('input[name="assignType"]:checked').value;
if (type === 'user') {
document.getElementById('assignUserGroup').style.display = '';
document.getElementById('assignProjectGroup').style.display = 'none';
} else {
document.getElementById('assignUserGroup').style.display = 'none';
document.getElementById('assignProjectGroup').style.display = '';
}
}
function renderHeader() {
document.getElementById('assetHeaderTitle').textContent = asset.name;
const isDigital = asset.type === 'digital';
const depPct = isDigital ? 100 : Math.round((asset.cost - asset.value)/asset.cost*100);
document.getElementById('assetHeader').innerHTML = `
<div class="card-body">
<div class="flex items-center gap-4 flex-wrap">
<div style="width:64px;height:64px;border-radius:16px;background:var(--primary-glow);display:flex;align-items:center;justify-content:center;font-size:30px;border:1px solid var(--border-accent);flex-shrink:0">${asset.icon || '📦'}</div>
<div style="flex:1;min-width:0">
<div style="font-size:20px;font-weight:800;margin-bottom:4px">${escapeHtml(asset.name)}</div>
<div style="display:flex;gap:10px;flex-wrap:wrap;align-items:center">
<span class="badge badge-neutral" style="font-size:11px">${escapeHtml(asset.id)}</span>
<span class="badge ${statusBadge(asset.status)}"><span class="badge-dot-ind" style="background:${statusDot(asset.status)}"></span>${asset.status}</span>
<span class="badge badge-neutral" style="font-size:11px">${escapeHtml(asset.cat)}</span>
<span style="font-size:12px;color:var(--text-muted)">${isDigital ? 'Software License' : escapeHtml(asset.serial)}</span>
</div>
</div>
<div class="flex gap-5 flex-wrap">
<div style="text-align:right">
<div style="font-size:10px;color:var(--text-muted);text-transform:uppercase;letter-spacing:.5px">${isDigital ? 'Cost (Annual)' : 'Purchase Cost'}</div>
<div style="font-size:18px;font-weight:800">${fmt(asset.cost)}</div>
</div>
${isDigital ? `
<div style="text-align:right">
<div style="font-size:10px;color:var(--text-muted);text-transform:uppercase;letter-spacing:.5px">Allocated Seats</div>
<div style="font-size:18px;font-weight:800;color:var(--primary-light)">${asset.seatsAlloc || 0} / ${asset.seatsTotal || 1}</div>
</div>
` : `
<div style="text-align:right">
<div style="font-size:10px;color:var(--text-muted);text-transform:uppercase;letter-spacing:.5px">Net Book Value</div>
<div style="font-size:18px;font-weight:800;color:${depPct>60?'var(--warning)':'var(--success)'}">${fmt(asset.value)}</div>
</div>
<div style="text-align:right">
<div style="font-size:10px;color:var(--text-muted);text-transform:uppercase;letter-spacing:.5px">Depreciated</div>
<div style="font-size:18px;font-weight:800;color:var(--danger)">${depPct}%</div>
</div>
`}
</div>
</div>
<div style="margin-top:16px;background:var(--bg-surface);border-radius:var(--radius-md);overflow:hidden;height:6px">
<div style="height:100%;width:${isDigital ? (100 * (asset.seatsAlloc || 0)/(asset.seatsTotal || 1)) : (100-depPct)}%;background:linear-gradient(90deg,var(--primary),var(--cyan));transition:width .6s ease;border-radius:var(--radius-md)"></div>
</div>
<div style="display:flex;justify-content:space-between;font-size:11px;color:var(--text-muted);margin-top:5px">
<span>${isDigital ? `Seat Utilization: ${Math.round((asset.seatsAlloc||0)/(asset.seatsTotal||1)*100)}%` : `Net Value: ${fmt(asset.value)}`}</span>
<span>${isDigital ? `Billing Cycle: Annual Renewal` : `Fully Depreciated by: ~${new Date(new Date(asset.purchase).getFullYear() + Math.ceil(asset.cost/asset.value),0,1).getFullYear()}`}</span>
<span>Purchased: ${fmtDate(asset.purchase)}</span>
</div>
</div>`;
}
function renderOverview() {
const isDigital = asset.type === 'digital';
document.getElementById('assetInfoGrid').innerHTML = `
<div class="info-grid">
<div class="info-item"><div class="info-label">Asset ID</div><div class="info-value">${escapeHtml(asset.id)}</div></div>
<div class="info-item"><div class="info-label">${isDigital ? 'Subscription Type' : 'Serial Number'}</div><div class="info-value">${isDigital ? 'Digital Subscription' : escapeHtml(asset.serial)}</div></div>
<div class="info-item"><div class="info-label">Category</div><div class="info-value">${escapeHtml(asset.cat)}</div></div>
<div class="info-item"><div class="info-label">Status</div><div class="info-value"><span class="badge ${statusBadge(asset.status)}">${asset.status}</span></div></div>
<div class="info-item"><div class="info-label">Vendor / Supplier</div><div class="info-value">${escapeHtml(asset.vendor)}</div></div>
<div class="info-item"><div class="info-label">Purchase Date</div><div class="info-value">${fmtDate(asset.purchase)}</div></div>
<div class="info-item"><div class="info-label">${isDigital ? 'Renewal Date' : 'Warranty Expiry'}</div><div class="info-value">${fmtDate(asset.warranty)}</div></div>
<div class="info-item"><div class="info-label">Depreciation Method</div><div class="info-value">${isDigital ? 'N/A' : `${asset.depM} @ ${asset.depR}% p.a.`}</div></div>
</div>`;
if (isDigital) {
document.getElementById('assetLocationGrid').innerHTML = `
<div class="info-grid">
<div class="info-item" style="grid-column:span 2"><div class="info-label">Deployment Environment</div><div class="info-value">☁️ ${escapeHtml(asset.loc || 'Cloud hosted')}</div></div>
<div class="info-item"><div class="info-label">Assigned Project</div><div class="info-value"><span class="badge badge-primary">${escapeHtml(asset.project || 'Unassigned')}</span></div></div>
<div class="info-item"><div class="info-label">License Owner</div><div class="info-value">${escapeHtml(asset.assignee || 'IT Team')}</div></div>
</div>
<hr class="divider">
<div style="font-size:12px;color:var(--text-muted);margin-bottom:8px">License Status</div>
<div style="padding:12px;background:var(--bg-surface);border-radius:var(--radius-md);border:1px solid var(--border)">
<div style="font-weight:600;font-size:13px;margin-bottom:4px">Key Details</div>
<code style="display:block;padding:6px;background:var(--bg-elevated);border-radius:4px;font-size:12px;color:var(--primary-light);margin-bottom:8px">${asset.licenseKey || 'N/A'}</code>
<div style="font-size:12px;color:var(--text-secondary)">Total Seats: <strong>${asset.seatsTotal || 1}</strong> &nbsp;·&nbsp; Allocated: <strong>${asset.seatsAlloc || 0}</strong></div>
</div>`;
} else {
document.getElementById('assetLocationGrid').innerHTML = `
<div class="info-grid">
<div class="info-item" style="grid-column:span 2"><div class="info-label">Current Location</div><div class="info-value">🏢 ${asset.loc}</div></div>
<div class="info-item"><div class="info-label">Department</div><div class="info-value">${asset.dept}</div></div>
<div class="info-item"><div class="info-label">Assigned To</div><div class="info-value">${asset.assignee}</div></div>
</div>
<hr class="divider">
<div style="font-size:12px;color:var(--text-muted);margin-bottom:8px">Custody Chain</div>
<div class="timeline">
<div class="timeline-item">
<div class="tl-icon-wrap"><div class="tl-icon" style="background:var(--success-bg);color:var(--success)">👤</div><div class="tl-line"></div></div>
<div class="tl-content"><div class="tl-title">${asset.assignee} (Current)</div><div class="tl-desc">${asset.dept} · ${asset.loc}</div><div class="tl-time">From ${fmtDate(asset.purchase)}</div></div>
</div>
<div class="timeline-item">
<div class="tl-icon-wrap"><div class="tl-icon" style="background:var(--bg-elevated);color:var(--text-muted)">🏪</div></div>
<div class="tl-content"><div class="tl-title">Warehouse (Initial Stock)</div><div class="tl-desc">Goods Receipt Note created</div><div class="tl-time">${fmtDate(asset.purchase)}</div></div>
</div>
</div>`;
}
// QR Code
const cells = generateQRPattern(asset.id);
document.getElementById('assetQR').innerHTML = `
<div class="qr-box" style="margin:0 auto">
<div style="display:grid;grid-template-columns:repeat(7,11px);grid-template-rows:repeat(7,11px);gap:2px;padding:8px;background:#fff">
${cells.map(c=>`<div style="background:${c?'#000':'#fff'};border-radius:1px"></div>`).join('')}
</div>
<div style="font-size:9px;color:#333;font-weight:700;font-family:monospace">${asset.id}</div>
<div style="font-size:8px;color:#555;max-width:100px">${asset.name.substring(0,24)}</div>
</div>
<div style="margin-top:12px;font-size:12px;color:var(--text-muted)">Scan to view asset details</div>`;
// Custom fields
let fieldsHtml = '';
if (isDigital) {
fieldsHtml = `
<div class="info-item"><div class="info-label">Platform Type</div><div class="info-value">SaaS Cloud</div></div>
<div class="info-item"><div class="info-label">Billing Cycle</div><div class="info-value">${asset.billingCycle || 'Annual'}</div></div>
<div class="info-item"><div class="info-label">Associated Project</div><div class="info-value">${asset.project || 'Unassigned'}</div></div>
<div class="info-item"><div class="info-label">Access Provider</div><div class="info-value">${asset.vendor}</div></div>
`;
} else {
const fieldsByCategory = {
'Laptops': [['Processor','Intel Core i7 13th Gen'],['RAM','16 GB DDR5'],['Storage','512 GB NVMe SSD'],['OS','Windows 11 Pro'],['Screen Size','14 inch FHD']],
'Servers': [['CPU','2× Xeon Gold 5218'],['RAM','128 GB ECC'],['Storage','4× 1.8 TB SAS'],['RAID','RAID 10'],['OS','Ubuntu Server 22.04']],
'Vehicles': [['Registration No.',asset.serial],['Fuel Type','Petrol / Electric'],['Engine CC','1498 CC'],['Insurance Expiry','2026-01-15'],['Next Service','50,000 KM']],
'HVAC': [['Capacity','1.5 Ton'],['Type','Inverter Split'],['Refrigerant','R-32'],['Star Rating','5 Star'],['Installation Date',fmtDate(asset.purchase)]],
'Printers': [['Print Speed','40 ppm'],['Print Technology','Laser'],['Paper Sizes','A4, A5, Letter'],['Connectivity','USB, Network, Wi-Fi'],['Monthly Duty Cycle','80,000 pages']]
};
const fields = fieldsByCategory[asset.cat] || [['Brand',asset.vendor],['Part Number','N/A'],['Model Year','2024'],['Color','Black / Silver']];
fieldsHtml = fields.map(([k,v])=>`<div class="info-item"><div class="info-label">${k}</div><div class="info-value">${v}</div></div>`).join('');
}
document.getElementById('assetCustomFields').innerHTML = `<div class="info-grid">${fieldsHtml}</div>`;
}
function renderFinancial() {
const isDigital = asset.type === 'digital';
if (isDigital) {
document.getElementById('tab-financial').innerHTML = `
<div class="card">
<div class="card-header"><span class="card-title">💰 Software Subscription Cost Breakdown</span></div>
<div class="card-body">
<div class="info-grid mb-4">
<div class="info-item"><div class="info-label">Subscription Cost</div><div class="info-value" style="font-size:18px;font-weight:800">${fmt(asset.cost)} / year</div></div>
<div class="info-item"><div class="info-label">Total Seats Purchased</div><div class="info-value">${asset.seatsTotal || 1}</div></div>
<div class="info-item"><div class="info-label">Allocated Seats</div><div class="info-value">${asset.seatsAlloc || 0}</div></div>
<div class="info-item"><div class="info-label">Cost per Seat (avg)</div><div class="info-value">${fmt(Math.round(asset.cost / (asset.seatsTotal || 1)))} / year</div></div>
</div>
<hr class="divider">
<div style="font-size:12.5px;color:var(--text-secondary)">
<strong style="color:var(--text-primary)">V1 Note:</strong> Software subscriptions are expensed as operational costs (OPEX) and are 100% written off annually. Depreciation methods (SLM/WDV) do not apply to SaaS licenses.
</div>
</div>
</div>`;
return;
}
const depPct = Math.round((asset.cost - asset.value)/asset.cost*100);
const years = Math.max(1, Math.floor((new Date() - new Date(asset.purchase))/(365.25*24*3600*1000)));
const annualDep = asset.depM === 'SLM' ? Math.round(asset.cost * asset.depR/100) : Math.round((asset.cost - asset.value) / Math.max(1,years));
document.getElementById('depreciationInfo').innerHTML = `
<div class="dep-bar-wrap" style="margin-bottom:16px">
<div class="dep-nums" style="display:flex;justify-content:space-between;margin-bottom:6px">
<span>Net Book Value: <strong>${fmt(asset.value)}</strong></span>
<span>Total Dep.: <strong style="color:var(--danger)">${fmt(asset.cost - asset.value)}</strong></span>
</div>
<div class="progress-wrap" style="background:var(--bg-surface);border-radius:4px;height:8px;overflow:hidden"><div class="progress-fill" style="width:${100-depPct}%;height:100%;background:var(--success)"></div></div>
<div class="dep-nums" style="margin-top:6px;margin-bottom:0;display:flex;justify-content:space-between">
<span style="font-size:11px">${100-depPct}% remaining value</span>
<span style="font-size:11px">${depPct}% depreciated</span>
</div>
</div>
<div class="info-grid mb-4">
<div class="info-item"><div class="info-label">Method</div><div class="info-value">${asset.depM} (${asset.depM==='SLM'?'Straight Line':'Written Down Value'})</div></div>
<div class="info-item"><div class="info-label">Rate</div><div class="info-value">${asset.depR}% per annum</div></div>
<div class="info-item"><div class="info-label">Annual Depreciation</div><div class="info-value" style="color:var(--danger)">${fmt(annualDep)}</div></div>
<div class="info-item"><div class="info-label">Asset Age</div><div class="info-value">${years} year${years!==1?'s':''}</div></div>
</div>`;
// Depreciation chart
const purchaseYear = new Date(asset.purchase).getFullYear();
const labels=[], values=[];
let val = asset.cost;
for(let i=0;i<=5;i++){
labels.push(purchaseYear+i);
values.push(Math.max(0, Math.round(val)));
if(asset.depM==='SLM') val -= asset.cost*asset.depR/100;
else val *= (1-asset.depR/100);
}
new Chart(document.getElementById('depChart'),{
type:'line',
data:{ labels, datasets:[{label:'Book Value',data:values,borderColor:'#6366F1',backgroundColor:'rgba(99,102,241,.1)',fill:true,tension:.3,pointRadius:4,borderWidth:2}] },
options:{responsive:true,maintainAspectRatio:false,plugins:{legend:{display:false}},
scales:{x:{grid:{color:'rgba(255,255,255,.04)'},ticks:{color:'#4B5563',font:{family:'Inter',size:11}}},
y:{grid:{color:'rgba(255,255,255,.04)'},ticks:{color:'#4B5563',font:{family:'Inter',size:11},callback:v=>'₹'+(v/1000).toFixed(0)+'K'}}}}
});
document.getElementById('valueSummary').innerHTML = `
<div class="info-grid">
<div class="info-item"><div class="info-label">Purchase Cost</div><div class="info-value" style="font-size:18px;font-weight:800">${fmt(asset.cost)}</div></div>
<div class="info-item"><div class="info-label">Current Book Value</div><div class="info-value" style="font-size:18px;font-weight:800;color:var(--success)">${fmt(asset.value)}</div></div>
<div class="info-item"><div class="info-label">Total Depreciation</div><div class="info-value" style="color:var(--danger)">${fmt(asset.cost-asset.value)}</div></div>
<div class="info-item"><div class="info-label">Residual Value</div><div class="info-value">${fmt(Math.round(asset.cost*0.05))}</div></div>
</div>
<hr class="divider">
<div class="section-hdr">Year-wise Depreciation</div>
<table class="data-table" style="font-size:12px">
<thead><tr><th>Year</th><th>Opening Value</th><th>Depreciation</th><th>Closing Value</th></tr></thead>
<tbody>
${(()=>{
let v=asset.cost, rows=''; const py=new Date(asset.purchase).getFullYear();
for(let i=0;i<Math.min(5,Math.ceil(100/asset.depR));i++){
const dep = asset.depM==='SLM' ? asset.cost*asset.depR/100 : v*asset.depR/100;
const close = Math.max(0,v-dep);
rows+=`<tr><td>${py+i}</td><td>${fmt(Math.round(v))}</td><td style="color:var(--danger)">-${fmt(Math.round(dep))}</td><td>${fmt(Math.round(close))}</td></tr>`;
v=close;
}
return rows;
})()}
</tbody>
</table>`;
}
function renderAssignments() {
const isProject = asset.project && asset.project !== 'N/A' && asset.project !== 'Unassigned / No Project';
document.getElementById('assignmentHistory').innerHTML = `
<div class="timeline">
<div class="timeline-item">
<div class="tl-icon-wrap"><div class="tl-icon" style="background:var(--success-bg);color:var(--success)">✅</div><div class="tl-line"></div></div>
<div class="tl-content">
<div class="tl-title">${isProject ? `Project: ${asset.project}` : `Employee: ${asset.assignee}`} (Current)</div>
<div class="tl-desc">${asset.dept} Department · ${asset.loc}</div>
<div class="tl-time">Since ${fmtDate(asset.purchase)} · Saved in records</div>
</div>
</div>
<div class="timeline-item">
<div class="tl-icon-wrap"><div class="tl-icon" style="background:var(--bg-elevated);color:var(--text-muted)">🏪</div></div>
<div class="tl-content"><div class="tl-title">Warehouse (Initial)</div><div class="tl-desc">Asset received via GRN • PO-2024-038</div><div class="tl-time">${fmtDate(asset.purchase)}</div></div>
</div>
</div>`;
}
function renderMaintenance() {
const rel = AMS.tickets.filter(t => t.asset === asset.id);
if (!rel.length) {
document.getElementById('maintenanceRecords').innerHTML = `<div class="empty-state"><div class="empty-icon">🔧</div><div class="empty-title">No maintenance records</div><div class="empty-text">No tickets raised for this asset</div><a href="maintenance.html" class="btn btn-primary btn-sm">Raise Ticket</a></div>`;
return;
}
document.getElementById('maintenanceRecords').innerHTML = `
<div class="timeline">
${rel.map(t=>`
<div class="timeline-item">
<div class="tl-icon-wrap"><div class="tl-icon" style="background:var(--${statusBadge(t.status).includes('danger')?'danger':'info'}-bg);color:var(--${statusBadge(t.status).includes('danger')?'danger':'info'})">🔧</div><div class="tl-line"></div></div>
<div class="tl-content">
<div class="tl-title">${t.title||t.name} <span class="badge ${statusBadge(t.status)}" style="margin-left:6px">${t.status}</span></div>
<div class="tl-desc">${t.category} · Assigned to: ${t.assignedTo}</div>
<div class="tl-time">Created: ${fmtDate(t.created)} · Priority: <span class="badge ${statusBadge(t.priority)}">${t.priority}</span></div>
</div>
</div>`).join('')}
</div>`;
}
function renderDocuments() {
const docs = [
{ name:'Purchase Invoice', type:'PDF', size:'240 KB', date:'2024-01-15', icon:'📄' },
{ name:'Delivery Challan', type:'PDF', size:'85 KB', date:'2024-01-16', icon:'📋' },
{ name:'Warranty Card', type:'PDF', size:'120 KB', date:'2024-01-15', icon:'🛡️' }
];
document.getElementById('assetDocs').innerHTML = docs.map(d=>`
<div class="flex items-center gap-3 mb-3" style="padding:12px;background:var(--bg-surface);border-radius:var(--radius-md);border:1px solid var(--border)">
<div style="font-size:22px">${d.icon}</div>
<div style="flex:1"><div style="font-weight:600;font-size:13px">${d.name}</div><div style="font-size:11px;color:var(--text-muted)">${d.type} · ${d.size} · Uploaded ${fmtDate(d.date)}</div></div>
<button class="btn btn-ghost btn-sm" onclick="showToast('Download','Downloading ${d.name}…','info')">📥</button>
<button class="btn btn-ghost btn-sm" onclick="showToast('Delete','File deleted','success')">🗑️</button>
</div>`).join('');
}
function renderHistory() {
const events = [
{ icon:'📦', bg:'var(--primary-glow)', color:'var(--primary-light)', title:'Asset Created', desc:`Imported via GRN · Vendor: ${asset.vendor}`, time:fmtDate(asset.purchase) },
{ icon:'📱', bg:'var(--info-bg)', color:'var(--info)', title:'QR Code Generated', desc:'System assigned unique ID: '+asset.id, time:fmtDate(asset.purchase) }
];
if (asset.project && asset.project !== 'N/A' && asset.project !== 'Unassigned / No Project') {
events.push({ icon:'👤', bg:'var(--success-bg)', color:'var(--success)', title:'Assigned to Project', desc:`Project: ${asset.project}`, time:'Just now' });
} else {
events.push({ icon:'👤', bg:'var(--success-bg)', color:'var(--success)', title:'Assigned to '+asset.assignee, desc:`Dept: ${asset.dept} · Location: ${asset.loc}`, time:'Just now' });
}
document.getElementById('auditTrail').innerHTML = `
<div class="timeline">
${events.map(e=>`
<div class="timeline-item">
<div class="tl-icon-wrap"><div class="tl-icon" style="background:${e.bg};color:${e.color}">${e.icon}</div><div class="tl-line"></div></div>
<div class="tl-content"><div class="tl-title">${e.title}</div><div class="tl-desc">${e.desc}</div><div class="tl-time">By ${AMS.currentUser.name} · ${e.time}</div></div>
</div>`).join('')}
</div>`;
}
function saveEdit() {
const target = AMS.assets.find(a => a.id === asset.id);
if (!target) return;
target.name = document.getElementById('editName').value;
target.cat = document.getElementById('editCat').value;
target.status = document.getElementById('editStatus').value;
if (asset.type === 'digital') {
target.licenseKey = document.getElementById('editSerial').value;
target.seatsTotal = parseInt(document.getElementById('editSeatsTotal').value) || 1;
target.seatsAlloc = parseInt(document.getElementById('editSeatsAlloc').value) || 0;
} else {
target.serial = document.getElementById('editSerial').value;
}
// Track activity feed
AMS.activityFeed.unshift({
user: AMS.currentUser.name,
av: AMS.currentUser.avatar,
color: '#3B82F6',
action: 'updated asset',
target: target.name,
detail: `(${target.id}) — Reason: ${document.getElementById('editReason').value || 'Details correction'}`,
time: 'Just now'
});
AMS.save();
closeModal('editModal');
showToast('Asset Updated', 'Changes saved successfully', 'success');
setTimeout(() => window.location.reload(), 800);
}
function doAssign() {
const target = AMS.assets.find(a => a.id === asset.id);
if (!target) return;
const assignType = document.querySelector('input[name="assignType"]:checked').value;
if (assignType === 'user') {
const user = document.getElementById('assignUserSelect').value;
if (!user) { showToast('Error', 'Please select an employee', 'error'); return; }
target.assignee = user;
target.project = 'Unassigned / No Project';
} else {
const proj = document.getElementById('assignProjectSelect').value;
if (!proj) { showToast('Error', 'Please select a project', 'error'); return; }
target.project = proj;
target.assignee = 'Shared (Project Asset)';
}
// Add audit trace
AMS.activityFeed.unshift({
user: AMS.currentUser.name,
av: AMS.currentUser.avatar,
color: '#10B981',
action: 're-assigned asset',
target: target.name,
detail: `to ${assignType === 'user' ? target.assignee : target.project}`,
time: 'Just now'
});
AMS.save();
closeModal('assignModal');
showToast('Asset Assigned', `Assigned successfully`, 'success');
setTimeout(() => window.location.reload(), 800);
}
function doTransfer() {
closeModal('transferModal');
showToast('Transfer Request', 'Approval request sent to Department Head', 'info');
}
function confirmDispose() {
confirmAction('Dispose Asset', `Mark "${asset.name}" as disposed? This action is permanent and will write off this asset.`, () => {
const target = AMS.assets.find(a => a.id === asset.id);
if (target) {
target.status = 'Disposed';
// Update statistics
AMS.stats.active = AMS.assets.filter(a => a.status === 'Active').length;
AMS.stats.maintenance = AMS.assets.filter(a => a.status === 'Under Maintenance').length;
AMS.stats.idle = AMS.assets.filter(a => a.status === 'Idle').length;
AMS.stats.disposed = AMS.assets.filter(a => a.status === 'Disposed').length;
AMS.activityFeed.unshift({
user: AMS.currentUser.name,
av: AMS.currentUser.avatar,
color: '#EF4444',
action: 'disposed asset',
target: target.name,
detail: `(${target.id})`,
time: 'Just now'
});
AMS.save();
showToast('Asset Disposed', 'Asset status set to Disposed', 'success');
setTimeout(() => window.location.href = 'assets.html', 1200);
}
});
}
function printQR() { showToast('Print', 'QR label sent to printer', 'info'); }
</script>
</body>
</html>