589 lines
29 KiB
HTML
589 lines
29 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||
<title>Add New Asset | 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">
|
||
</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">
|
||
<a href="assets.html" class="btn btn-ghost btn-sm" style="margin-right:6px">← Back to Assets</a>
|
||
<div class="topbar-title">Add New Asset</div>
|
||
</div>
|
||
<div class="topbar-actions">
|
||
<button class="btn btn-secondary btn-sm" onclick="saveDraft()">💾 Save Draft</button>
|
||
<a href="index.html" class="icon-btn" title="Logout"><i data-lucide="log-out"></i></a>
|
||
</div>
|
||
</header>
|
||
|
||
<main class="content">
|
||
<div style="display:grid;grid-template-columns:240px 1fr;gap:20px;align-items:start">
|
||
<!-- Step Sidebar -->
|
||
<div class="card p-5" id="stepsSidebar">
|
||
<div style="font-size:12px;font-weight:700;color:var(--text-muted);text-transform:uppercase;letter-spacing:.6px;margin-bottom:14px">Creation Steps</div>
|
||
<div id="stepNav"></div>
|
||
<hr class="divider">
|
||
<div style="font-size:11.5px;color:var(--text-muted)">
|
||
<div class="mb-2">💡 <strong style="color:var(--text-secondary)">Auto-generated:</strong></div>
|
||
<div style="margin-bottom:4px">• Asset ID: <code style="color:var(--primary-light)" id="previewId">AST-2025-021</code></div>
|
||
<div>• QR code on save</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Form Area -->
|
||
<div id="formArea">
|
||
<!-- Step 1 -->
|
||
<div class="card" id="step1" data-step="1">
|
||
<div class="card-header"><span class="card-title">📋 Step 1: Basic Information</span></div>
|
||
<div class="card-body">
|
||
<div class="form-row">
|
||
<div class="form-group">
|
||
<label class="form-label">Asset Type <span class="req">*</span></label>
|
||
<select class="form-select" id="assetType" onchange="handleTypeChange()">
|
||
<option value="physical">Physical Asset (Hardware, Furniture, Vehicle, etc.)</option>
|
||
<option value="digital">Digital Asset (Software License, Cloud Subscription)</option>
|
||
<option value="other">Other Asset (Lease, Agreement, Patent, etc.)</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label class="form-label">Asset Name <span class="req">*</span></label>
|
||
<input type="text" class="form-input" id="assetName" placeholder="e.g. Dell Latitude 5540 Laptop" oninput="updatePreview()">
|
||
</div>
|
||
</div>
|
||
<div class="form-row">
|
||
<div class="form-group">
|
||
<label class="form-label">Category <span class="req">*</span></label>
|
||
<select class="form-select" id="assetCategory" onchange="renderCustomFields()">
|
||
<option value="">Select category…</option>
|
||
<option>Laptops</option><option>Desktops</option><option>Servers</option>
|
||
<option>Printers</option><option>Networking</option><option>Mobile Devices</option>
|
||
<option>AV Equipment</option><option>Displays</option><option>Furniture</option>
|
||
<option>Vehicles</option><option>HVAC</option><option>Power Equipment</option><option>Storage</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label class="form-label">Status <span class="req">*</span></label>
|
||
<select class="form-select" id="assetStatus">
|
||
<option>Active</option><option>Idle</option><option>Under Maintenance</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Physical Hardware Fields -->
|
||
<div class="form-row" id="physicalFieldsRow">
|
||
<div class="form-group">
|
||
<label class="form-label">Serial Number</label>
|
||
<input type="text" class="form-input" id="serialNo" placeholder="Manufacturer serial number">
|
||
</div>
|
||
<div class="form-group">
|
||
<label class="form-label">Model / Part Number</label>
|
||
<input type="text" class="form-input" id="modelNo" placeholder="Model identifier">
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Digital Software Fields -->
|
||
<div class="form-row" id="digitalFieldsRow" style="display:none">
|
||
<div class="form-group" id="licenseKeyGroup">
|
||
<label class="form-label">License Key / Subscription ID</label>
|
||
<input type="text" class="form-input" id="licenseKey" placeholder="e.g. MS365-ABCD-1234">
|
||
</div>
|
||
<div class="form-group" id="seatsGroup">
|
||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px">
|
||
<div>
|
||
<label class="form-label">Total Seats</label>
|
||
<input type="number" class="form-input" id="seatsTotal" value="1" min="1">
|
||
</div>
|
||
<div>
|
||
<label class="form-label">Allocated Seats</label>
|
||
<input type="number" class="form-input" id="seatsAlloc" value="0" min="0">
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-row">
|
||
<div class="form-group" id="brandGroup">
|
||
<label class="form-label">Brand / Manufacturer</label>
|
||
<input type="text" class="form-input" id="brand" placeholder="e.g. Dell, HP, Apple">
|
||
</div>
|
||
<div class="form-group">
|
||
<label class="form-label">Description</label>
|
||
<input type="text" class="form-input" id="description" placeholder="Optional description or notes…">
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Custom Fields -->
|
||
<div id="customFieldsSection" style="display:none">
|
||
<hr class="divider">
|
||
<div class="section-hdr">Category-specific Fields</div>
|
||
<div id="customFieldsGrid" class="form-row"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Step 2 -->
|
||
<div class="card mt-4" id="step2" data-step="2">
|
||
<div class="card-header"><span class="card-title">💰 Step 2: Purchase & Financial Details</span></div>
|
||
<div class="card-body">
|
||
<div class="form-row">
|
||
<div class="form-group">
|
||
<label class="form-label">Vendor / Supplier <span class="req">*</span></label>
|
||
<select class="form-select" id="assetVendor">
|
||
<option value="">Select vendor…</option>
|
||
<option>Dell India Pvt. Ltd.</option><option>HP India Pvt. Ltd.</option>
|
||
<option>Cisco Systems India</option><option>Apple India</option>
|
||
<option>Lenovo India</option><option>Daikin India</option>
|
||
<option>Samsung India</option><option>Godrej Interio</option>
|
||
<option value="new">+ Add New Vendor</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label class="form-label">Purchase Date <span class="req">*</span></label>
|
||
<input type="date" class="form-input" id="purchaseDate" value="2025-05-28">
|
||
</div>
|
||
</div>
|
||
<div class="form-row">
|
||
<div class="form-group">
|
||
<label class="form-label">Purchase Cost (₹) <span class="req">*</span></label>
|
||
<div class="input-group">
|
||
<span class="input-prefix">₹</span>
|
||
<input type="number" class="form-input" id="purchaseCost" placeholder="0.00" oninput="calcDepreciation()" style="border-radius:0 var(--radius-md) var(--radius-md) 0;border-left:none">
|
||
</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label class="form-label">Invoice / PO Reference</label>
|
||
<input type="text" class="form-input" id="invoiceRef" placeholder="INV-2025-XXXX or PO-XXXX">
|
||
</div>
|
||
</div>
|
||
<div class="form-row">
|
||
<div class="form-group">
|
||
<label class="form-label">Warranty Expiry</label>
|
||
<input type="date" class="form-input" id="warrantyDate">
|
||
</div>
|
||
<div class="form-group">
|
||
<label class="form-label">Warranty Type</label>
|
||
<select class="form-select"><option>On-site</option><option>Carry-in</option><option>Comprehensive AMC</option><option>No Warranty</option></select>
|
||
</div>
|
||
</div>
|
||
<hr class="divider">
|
||
<div class="section-hdr">Depreciation Configuration</div>
|
||
<div class="form-row-3">
|
||
<div class="form-group">
|
||
<label class="form-label">Method <span class="req">*</span></label>
|
||
<select class="form-select" id="depMethod" onchange="calcDepreciation()">
|
||
<option value="SLM">SLM – Straight Line</option>
|
||
<option value="WDV">WDV – Written Down Value</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label class="form-label">Rate (% p.a.) <span class="req">*</span></label>
|
||
<input type="number" class="form-input" id="depRate" value="20" min="1" max="100" oninput="calcDepreciation()">
|
||
</div>
|
||
<div class="form-group">
|
||
<label class="form-label">Residual Value (₹)</label>
|
||
<input type="number" class="form-input" id="residualValue" placeholder="0">
|
||
</div>
|
||
</div>
|
||
<div id="depPreview" style="display:none;margin-top:8px;padding:14px;background:var(--bg-surface);border-radius:var(--radius-md);border:1px solid var(--border)">
|
||
<div style="font-size:12px;font-weight:700;color:var(--text-muted);text-transform:uppercase;letter-spacing:.5px;margin-bottom:10px">Depreciation Preview</div>
|
||
<div id="depPreviewContent"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Step 3 -->
|
||
<div class="card mt-4" id="step3" data-step="3">
|
||
<div class="card-header"><span class="card-title">📍 Step 3: Location & Assignment</span></div>
|
||
<div class="card-body">
|
||
<div class="form-row">
|
||
<div class="form-group">
|
||
<label class="form-label">Department <span class="req">*</span></label>
|
||
<select class="form-select" id="assetDept">
|
||
<option value="">Select department…</option>
|
||
<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">Location <span class="req">*</span></label>
|
||
<select class="form-select" id="assetLoc">
|
||
<option>IT Dept – Floor 2</option><option>Finance – Floor 1</option>
|
||
<option>HR – Floor 2</option><option>Server Room – B1</option>
|
||
<option>Marketing – Floor 3</option><option>Admin – Floor 1</option>
|
||
<option>Warehouse – Whitefield</option><option>Parking – B1</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
<div class="form-row">
|
||
<div class="form-group" id="assigneeGroup">
|
||
<label class="form-label">Assign To (Employee)</label>
|
||
<select class="form-select" id="assetAssignee">
|
||
<option value="">Unassigned (Pool Asset)</option>
|
||
<option>Priya Kumar – IT</option><option>Rahul Mehta – Finance</option>
|
||
<option>Anita Singh – HR</option><option>Vikram Reddy – Operations</option>
|
||
<option>Sneha Patel – Marketing</option><option>Deepak Joshi – Admin</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group" id="projectGroup" style="display:none">
|
||
<label class="form-label">Associated Project</label>
|
||
<select class="form-select" id="assetProject">
|
||
<option value="">Unassigned / No Project</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label class="form-label">Assignment Date</label>
|
||
<input type="date" class="form-input" value="2026-06-04">
|
||
</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label class="form-label">Cost Center</label>
|
||
<select class="form-select">
|
||
<option>CC-IT-001 (IT Infrastructure)</option><option>CC-FIN-002 (Finance Ops)</option>
|
||
<option>CC-HR-003 (Human Resources)</option><option>CC-OPS-004 (Operations)</option>
|
||
<option>CC-MKT-005 (Marketing)</option>
|
||
</select>
|
||
</div>
|
||
<hr class="divider">
|
||
<div class="section-hdr">Additional Options</div>
|
||
<div class="flex gap-4 flex-wrap">
|
||
<label class="flex items-center gap-2" style="cursor:pointer;font-size:13px">
|
||
<input type="checkbox" checked> Generate QR code on save
|
||
</label>
|
||
<label class="flex items-center gap-2" style="cursor:pointer;font-size:13px">
|
||
<input type="checkbox" checked> Send acknowledgment email to assignee
|
||
</label>
|
||
<label class="flex items-center gap-2" style="cursor:pointer;font-size:13px">
|
||
<input type="checkbox"> Schedule first PM after 3 months
|
||
</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Submit Row -->
|
||
<div class="card mt-4">
|
||
<div class="card-body" style="display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:12px">
|
||
<div>
|
||
<div style="font-size:13px;font-weight:600">Ready to save?</div>
|
||
<div style="font-size:12px;color:var(--text-muted)">Asset will be created and QR code will be generated automatically.</div>
|
||
</div>
|
||
<div class="flex gap-3">
|
||
<button class="btn btn-secondary" onclick="saveDraft()">💾 Save as Draft</button>
|
||
<button class="btn btn-primary btn-lg" onclick="submitAsset()">✅ Create Asset</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div><!-- /formArea -->
|
||
</div>
|
||
</main>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Success Modal -->
|
||
<div class="modal-overlay" id="successModal">
|
||
<div class="modal" style="max-width:420px">
|
||
<div class="modal-body" style="text-align:center;padding:36px 28px">
|
||
<div style="font-size:52px;margin-bottom:16px">🎉</div>
|
||
<div style="font-size:20px;font-weight:800;margin-bottom:8px">Asset Created!</div>
|
||
<div style="font-size:13px;color:var(--text-muted);margin-bottom:6px">Asset ID: <code id="newAssetId" style="color:var(--primary-light);font-size:14px"></code></div>
|
||
<div style="font-size:12.5px;color:var(--text-muted);margin-bottom:24px">QR code generated. Assignee acknowledgment email sent.</div>
|
||
<div class="flex gap-3" style="justify-content:center">
|
||
<a href="assets.html" class="btn btn-secondary">← Asset List</a>
|
||
<button class="btn btn-primary" onclick="viewNew()">View Asset →</button>
|
||
</div>
|
||
</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 steps = [
|
||
{ num:1, label:'Basic Info', sub:'Name, category, serial' },
|
||
{ num:2, label:'Purchase & Finance', sub:'Cost, depreciation' },
|
||
{ num:3, label:'Location & Assign', sub:'Department, assignee' }
|
||
];
|
||
|
||
const customFieldDefs = {
|
||
'Laptops': [['Processor','text','e.g. Intel Core i7'],['RAM','text','e.g. 16 GB'],['Storage','text','e.g. 512 GB SSD'],['OS','text','e.g. Windows 11 Pro'],['Screen Size','text','e.g. 14 inch']],
|
||
'Desktops': [['Processor','text','e.g. Core i5'],['RAM','text','e.g. 8 GB'],['Storage','text','e.g. 1 TB HDD'],['OS','text','e.g. Windows 11']],
|
||
'Servers': [['CPU','text','e.g. Xeon Gold'],['RAM','text','e.g. 64 GB ECC'],['Storage','text','e.g. 2× 1.8 TB SAS'],['RAID','text','e.g. RAID 10'],['OS','text','e.g. Ubuntu Server']],
|
||
'Vehicles': [['Registration No.','text','e.g. MH12AB1234'],['Fuel Type','select','Petrol|Diesel|Electric|CNG'],['Engine CC','number','1498'],['Insurance Expiry','date',''],['Seating Capacity','number','5']],
|
||
'HVAC': [['Capacity','text','e.g. 1.5 Ton'],['Type','select','Split|Window|Cassette|Ducted'],['Refrigerant','text','e.g. R-32'],['Star Rating','number','5']],
|
||
'Printers': [['Print Speed (ppm)','number','40'],['Technology','select','Laser|Inkjet|Dot Matrix'],['Paper Sizes','text','A4, A5, Letter'],['Monthly Duty Cycle','text','e.g. 80,000 pages']],
|
||
'Networking': [['Port Count','number','24'],['Speed','text','e.g. 1 Gbps'],['Managed','select','Yes|No'],['PoE','select','Yes|No']],
|
||
'Mobile Devices': [['OS','select','iOS|Android|Windows'],['Storage','text','256 GB'],['IMEI','text','']],
|
||
'Displays': [['Screen Size','text','43 inch'],['Resolution','text','4K UHD'],['Panel Type','select','IPS|VA|OLED|TN']],
|
||
'Furniture': [['Material','text','e.g. Engineered Wood'],['Color','text','Black'],['Load Capacity','text','e.g. 120 kg']]
|
||
};
|
||
|
||
document.addEventListener('DOMContentLoaded', () => {
|
||
renderStepNav();
|
||
|
||
// Populate projects select dynamically from AMS
|
||
const projSel = document.getElementById('assetProject');
|
||
if (projSel && window.AMS && AMS.projects) {
|
||
AMS.projects.forEach(p => {
|
||
const o = document.createElement('option');
|
||
o.value = p.name;
|
||
o.textContent = `${p.name} (${p.dept})`;
|
||
projSel.appendChild(o);
|
||
});
|
||
}
|
||
|
||
// Populate assignee select dynamically from AMS.users
|
||
const assignSel = document.getElementById('assetAssignee');
|
||
if (assignSel && window.AMS && AMS.users) {
|
||
assignSel.innerHTML = '<option value="">Unassigned (Pool Asset)</option>';
|
||
AMS.users.forEach(u => {
|
||
const o = document.createElement('option');
|
||
o.value = u.name;
|
||
o.textContent = `${u.name} – ${u.role} (${u.dept})`;
|
||
assignSel.appendChild(o);
|
||
});
|
||
}
|
||
});
|
||
|
||
function renderStepNav() {
|
||
document.getElementById('stepNav').innerHTML = steps.map(s => `
|
||
<div class="step-nav-item ${s.num===1?'active':''}" id="stepNavItem-${s.num}" onclick="scrollToStep(${s.num})">
|
||
<div class="step-num" id="stepNum-${s.num}">${s.num}</div>
|
||
<div><div class="step-nav-label">${s.label}</div><div class="step-nav-sub">${s.sub}</div></div>
|
||
</div>`).join('');
|
||
}
|
||
|
||
function scrollToStep(n) {
|
||
const el = document.getElementById(`step${n}`);
|
||
if (el) el.scrollIntoView({behavior:'smooth',block:'start'});
|
||
}
|
||
|
||
function handleTypeChange() {
|
||
const type = document.getElementById('assetType').value;
|
||
const catSel = document.getElementById('assetCategory');
|
||
|
||
// Dynamic categories based on asset type
|
||
let catsHtml = '';
|
||
if (type === 'physical') {
|
||
catsHtml = `
|
||
<option value="">Select category…</option>
|
||
<option>Laptops</option><option>Desktops</option><option>Servers</option>
|
||
<option>Printers</option><option>Networking</option><option>Mobile Devices</option>
|
||
<option>AV Equipment</option><option>Displays</option><option>Furniture</option>
|
||
<option>Vehicles</option><option>HVAC</option><option>Power Equipment</option><option>Storage</option>
|
||
`;
|
||
document.getElementById('physicalFieldsRow').style.display = '';
|
||
document.getElementById('digitalFieldsRow').style.display = 'none';
|
||
document.getElementById('assigneeGroup').style.display = '';
|
||
document.getElementById('projectGroup').style.display = 'none';
|
||
document.getElementById('assetLoc').closest('.form-group').style.display = '';
|
||
} else if (type === 'digital') {
|
||
catsHtml = `
|
||
<option value="">Select category…</option>
|
||
<option>Software Licenses</option><option>Cloud Subscriptions</option>
|
||
`;
|
||
document.getElementById('physicalFieldsRow').style.display = 'none';
|
||
document.getElementById('digitalFieldsRow').style.display = '';
|
||
document.getElementById('assigneeGroup').style.display = 'none';
|
||
document.getElementById('projectGroup').style.display = '';
|
||
document.getElementById('assetLoc').closest('.form-group').style.display = 'none';
|
||
} else {
|
||
catsHtml = `
|
||
<option value="">Select category…</option>
|
||
<option>Service Agreements</option><option>Leases</option><option>Patents/IP</option>
|
||
`;
|
||
document.getElementById('physicalFieldsRow').style.display = 'none';
|
||
document.getElementById('digitalFieldsRow').style.display = 'none';
|
||
document.getElementById('assigneeGroup').style.display = '';
|
||
document.getElementById('projectGroup').style.display = '';
|
||
document.getElementById('assetLoc').closest('.form-group').style.display = 'none';
|
||
}
|
||
catSel.innerHTML = catsHtml;
|
||
renderCustomFields();
|
||
}
|
||
|
||
function renderCustomFields() {
|
||
const cat = document.getElementById('assetCategory').value;
|
||
const section = document.getElementById('customFieldsSection');
|
||
const grid = document.getElementById('customFieldsGrid');
|
||
const fields = customFieldDefs[cat];
|
||
if (!fields) { section.style.display='none'; return; }
|
||
section.style.display = '';
|
||
grid.innerHTML = fields.map(([label,type,ph])=>`
|
||
<div class="form-group">
|
||
<label class="form-label">${label}</label>
|
||
${type==='select'
|
||
? `<select class="form-select">${ph.split('|').map(o=>`<option>${o}</option>`).join('')}</select>`
|
||
: `<input type="${type}" class="form-input" placeholder="${ph||''}">`
|
||
}
|
||
</div>`).join('');
|
||
}
|
||
|
||
function nextAssetId() {
|
||
// Derive from the highest existing sequence number so IDs never collide
|
||
const maxNum = AMS.assets.reduce((m, a) => {
|
||
const n = parseInt(String(a.id).split('-').pop(), 10);
|
||
return isNaN(n) ? m : Math.max(m, n);
|
||
}, 0);
|
||
return `AST-2025-${String(maxNum + 1).padStart(3, '0')}`;
|
||
}
|
||
|
||
function updatePreview() {
|
||
const n = document.getElementById('assetName').value;
|
||
if(n && window.AMS) {
|
||
document.getElementById('previewId').textContent = nextAssetId();
|
||
}
|
||
}
|
||
|
||
function calcDepreciation() {
|
||
const cost = parseFloat(document.getElementById('purchaseCost').value) || 0;
|
||
const rate = parseFloat(document.getElementById('depRate').value) || 20;
|
||
const method = document.getElementById('depMethod').value;
|
||
const prev = document.getElementById('depPreview');
|
||
const cont = document.getElementById('depPreviewContent');
|
||
if (!cost) { prev.style.display='none'; return; }
|
||
prev.style.display = '';
|
||
let rows='',val=cost;
|
||
for(let i=1;i<=4;i++){
|
||
const dep = method==='SLM' ? cost*rate/100 : val*rate/100;
|
||
const close = Math.max(0,val-dep);
|
||
rows+=`<div class="flex justify-between" style="font-size:12px;padding:5px 0;border-bottom:1px solid var(--border)">
|
||
<span style="color:var(--text-muted)">Year ${i}</span>
|
||
<span style="color:var(--danger)">-${fmt(Math.round(dep))}</span>
|
||
<span style="font-weight:600">${fmt(Math.round(close))}</span>
|
||
</div>`;
|
||
val=close;
|
||
}
|
||
cont.innerHTML = `<div class="flex justify-between mb-2" style="font-size:11px;color:var(--text-muted);text-transform:uppercase;letter-spacing:.5px"><span>Year</span><span>Depreciation</span><span>Closing Value</span></div>${rows}`;
|
||
}
|
||
|
||
function saveDraft() {
|
||
const name = document.getElementById('assetName').value || 'Unnamed Asset';
|
||
showToast('Draft Saved',`"${name}" saved as draft`,'info');
|
||
}
|
||
|
||
function submitAsset() {
|
||
const name = document.getElementById('assetName').value.trim();
|
||
const type = document.getElementById('assetType').value;
|
||
const cat = document.getElementById('assetCategory').value;
|
||
const cost = parseFloat(document.getElementById('purchaseCost').value);
|
||
const vendor = document.getElementById('assetVendor').value;
|
||
const pdate = document.getElementById('purchaseDate').value;
|
||
const dept = document.getElementById('assetDept').value;
|
||
const depRraw = document.getElementById('depRate').value;
|
||
const depR = parseFloat(depRraw);
|
||
|
||
const fail = (msg, id) => { showToast('Validation Error', msg, 'error'); const el = document.getElementById(id); if (el) el.focus(); };
|
||
|
||
// Step 1
|
||
if (!name) { fail('Please enter the asset name','assetName'); return; }
|
||
if (!cat) { fail('Please select a category','assetCategory'); return; }
|
||
// Step 2 — financials
|
||
if (isNaN(cost) || cost <= 0) { fail('Please enter a valid purchase cost greater than 0','purchaseCost'); return; }
|
||
if (!vendor || vendor === 'new') { fail('Please select a vendor / supplier','assetVendor'); return; }
|
||
if (!pdate) { fail('Please select the purchase date','purchaseDate'); return; }
|
||
if (isNaN(depR) || depR < 1 || depR > 100) { fail('Depreciation rate must be between 1 and 100','depRate'); return; }
|
||
// Step 3 — location & assignment
|
||
if (!dept) { fail('Please select a department','assetDept'); return; }
|
||
// Digital seat integrity
|
||
if (type === 'digital') {
|
||
const tot = parseInt(document.getElementById('seatsTotal').value, 10);
|
||
const alloc = parseInt(document.getElementById('seatsAlloc').value, 10);
|
||
if (isNaN(tot) || tot < 1) { fail('Total seats must be at least 1','seatsTotal'); return; }
|
||
if (isNaN(alloc) || alloc < 0) { fail('Allocated seats cannot be negative','seatsAlloc'); return; }
|
||
if (alloc > tot) { fail('Allocated seats cannot exceed total seats','seatsAlloc'); return; }
|
||
}
|
||
|
||
// Generate ID
|
||
const nextId = nextAssetId();
|
||
|
||
// Build new asset record
|
||
const newAsset = {
|
||
id: nextId,
|
||
name: name,
|
||
cat: cat,
|
||
type: type,
|
||
status: document.getElementById('assetStatus').value || 'Active',
|
||
dept: document.getElementById('assetDept').value || 'IT',
|
||
purchase: document.getElementById('purchaseDate').value || new Date().toISOString().split('T')[0],
|
||
cost: cost,
|
||
value: cost,
|
||
vendor: document.getElementById('assetVendor').value || 'N/A',
|
||
warranty: document.getElementById('warrantyDate').value || 'N/A',
|
||
depM: document.getElementById('depMethod').value || 'SLM',
|
||
depR: parseFloat(document.getElementById('depRate').value) || 20,
|
||
icon: type === 'digital' ? (cat.includes('Subscription') ? '☁️' : '🔑') : (cat === 'Vehicles' ? '🚗' : '💻')
|
||
};
|
||
|
||
if (type === 'physical') {
|
||
newAsset.serial = document.getElementById('serialNo').value || 'N/A';
|
||
newAsset.loc = document.getElementById('assetLoc').value || 'IT Dept – Floor 2';
|
||
newAsset.assignee = document.getElementById('assetAssignee').value || 'Unassigned';
|
||
} else if (type === 'digital') {
|
||
newAsset.serial = 'Digital-License';
|
||
newAsset.loc = 'Cloud Environment';
|
||
newAsset.assignee = 'IT Team';
|
||
newAsset.licenseKey = document.getElementById('licenseKey').value || 'N/A';
|
||
newAsset.seatsTotal = parseInt(document.getElementById('seatsTotal').value) || 1;
|
||
newAsset.seatsAlloc = parseInt(document.getElementById('seatsAlloc').value) || 0;
|
||
newAsset.project = document.getElementById('assetProject').value || 'Unassigned / No Project';
|
||
} else {
|
||
newAsset.serial = 'N/A';
|
||
newAsset.loc = 'Corporate HQ';
|
||
newAsset.assignee = document.getElementById('assetAssignee').value || 'Unassigned';
|
||
newAsset.project = document.getElementById('assetProject').value || 'Unassigned / No Project';
|
||
}
|
||
|
||
// Save to datastore
|
||
AMS.assets.push(newAsset);
|
||
|
||
// Track activity
|
||
AMS.activityFeed.unshift({
|
||
user: AMS.currentUser.name,
|
||
av: AMS.currentUser.avatar,
|
||
color: '#6366F1',
|
||
action: 'created asset',
|
||
target: newAsset.name,
|
||
detail: `(${newAsset.id})`,
|
||
time: 'Just now'
|
||
});
|
||
|
||
// Adjust stats
|
||
AMS.stats.total++;
|
||
if (newAsset.status === 'Active') AMS.stats.active++;
|
||
else if (newAsset.status === 'Under Maintenance') AMS.stats.maintenance++;
|
||
else if (newAsset.status === 'Idle') AMS.stats.idle++;
|
||
AMS.stats.totalValue += cost;
|
||
AMS.stats.netValue += cost;
|
||
|
||
AMS.save();
|
||
|
||
// Show Success Modal
|
||
document.querySelector('#successModal .modal').innerHTML = `
|
||
<div style="text-align:center;padding:36px 28px">
|
||
<div style="font-size:52px;margin-bottom:16px">🎉</div>
|
||
<div style="font-size:20px;font-weight:800;margin-bottom:8px">Asset Created!</div>
|
||
<div style="font-size:13px;color:var(--text-muted);margin-bottom:6px">Asset ID: <code style="color:var(--primary-light);font-size:14px">${nextId}</code></div>
|
||
<div style="font-size:12px;color:var(--text-muted);margin-bottom:6px"><strong style="color:var(--text-secondary)">${name}</strong> — ${cat}</div>
|
||
<div style="font-size:12.5px;color:var(--text-muted);margin-bottom:24px">QR code generated. Assignee acknowledgment email sent.</div>
|
||
<div class="flex gap-3" style="justify-content:center">
|
||
<a href="assets.html" class="btn btn-secondary">← Asset List</a>
|
||
<a href="asset-detail.html?id=${nextId}" class="btn btn-primary">View Asset →</a>
|
||
</div>
|
||
</div>`;
|
||
openModal('successModal');
|
||
}
|
||
</script>
|
||
</body>
|
||
</html>
|