marco.asseto.prototype/settings.html

337 lines
21 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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>Settings | 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">
<aside class="sidebar" id="appSidebar"></aside>
<div class="main-wrapper">
<header class="topbar">
<div class="topbar-left"><div class="topbar-title">System Settings</div></div>
<div class="topbar-actions">
<button class="btn btn-primary btn-sm" id="saveSettingsBtn" onclick="saveSettings()">💾 Save All Settings</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:220px 1fr;gap:20px;align-items:start">
<!-- Settings Sidebar -->
<div class="card p-4">
<div style="font-size:11.5px;font-weight:700;color:var(--text-muted);text-transform:uppercase;letter-spacing:.6px;margin-bottom:12px">Settings</div>
<nav id="settingsNav"></nav>
</div>
<!-- Settings Content -->
<div id="settingsContent"></div>
</div>
</main>
</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 sections = [
{ id:'general', icon:'🏢', label:'Organization' },
{ id:'appearance', icon:'🎨', label:'Appearance' },
{ id:'depreciation',icon:'💰', label:'Depreciation' },
{ id:'notifications',icon:'🔔',label:'Notifications' },
{ id:'email', icon:'📧', label:'Email / SMTP' },
{ id:'backup', icon:'💾', label:'Backup & Export' },
{ id:'security', icon:'🔐', label:'Security & 2FA' },
{ id:'integrations',icon:'🔗', label:'Integrations' }
];
const settingsHTML = {
general: `
<div class="card">
<div class="card-header"><span class="card-title">🏢 Organization Settings</span></div>
<div class="card-body">
<div class="form-row">
<div class="form-group"><label class="form-label">Company Name <span class="req">*</span></label><input class="form-input" id="setCompanyName" value="${AMS ? AMS.company.name : 'Acme Corporation Pvt. Ltd.'}"></div>
<div class="form-group"><label class="form-label">Company Logo</label><div class="flex items-center gap-3"><div style="width:48px;height:48px;border-radius:var(--radius-md);background:var(--primary-glow);display:flex;align-items:center;justify-content:center;font-size:22px">📦</div><button class="btn btn-secondary btn-sm" onclick="showToast('Upload','Logo upload dialog','info')">Change Logo</button></div></div>
</div>
<div class="form-row">
<div class="form-group"><label class="form-label">Currency</label><select class="form-select" id="setCurrency"><option selected>INR (₹)</option><option>USD ($)</option><option>EUR (€)</option><option>GBP (£)</option></select></div>
<div class="form-group"><label class="form-label">Financial Year</label><select class="form-select"><option selected>April March</option><option>January December</option><option>July June</option></select></div>
</div>
<div class="form-row">
<div class="form-group"><label class="form-label">Date Format</label><select class="form-select"><option selected>DD-MMM-YYYY</option><option>DD/MM/YYYY</option><option>MM/DD/YYYY</option><option>YYYY-MM-DD</option></select></div>
<div class="form-group"><label class="form-label">Timezone</label><select class="form-select"><option selected>Asia/Kolkata (IST +5:30)</option><option>UTC</option><option>America/New_York</option></select></div>
</div>
<div class="form-group"><label class="form-label">Registered Address</label><textarea class="form-textarea" id="setAddress" rows="2">${AMS ? AMS.company.address : ''}</textarea></div>
<div class="form-group"><label class="form-label">GST Number</label><input class="form-input" id="setGst" value="${AMS ? AMS.company.gst : ''}"></div>
<div class="form-group"><label class="form-label">Asset ID Prefix</label><input class="form-input" value="AST" placeholder="e.g. AST, ACME, ITL"><div class="form-hint">IDs will be generated as: <code style="color:var(--primary-light)">AST-2025-001</code></div></div>
</div>
</div>`,
appearance: `
<div class="card">
<div class="card-header"><span class="card-title">🎨 Appearance</span></div>
<div class="card-body">
<div class="form-group">
<label class="form-label">Theme</label>
<div class="flex gap-3 mt-2">
<label class="theme-opt" data-theme-opt="light" onclick="setTheme('light')"><div class="theme-swatch light"></div><span>Light (Default)</span></label>
<label class="theme-opt" data-theme-opt="dark" onclick="setTheme('dark')"><div class="theme-swatch dark"></div><span>Dark</span></label>
</div>
</div>
<div class="form-group mt-4">
<label class="form-label">Accent Color</label>
<div class="flex gap-3 mt-2 flex-wrap">
${['#6366F1','#06B6D4','#10B981','#F59E0B','#EF4444','#A855F7'].map((c,i)=>`
<button onclick="setAccent('${c}')" style="width:36px;height:36px;border-radius:50%;background:${c};border:${i===0?'3px solid #fff':'2px solid transparent'};cursor:pointer;transition:var(--t)" title="${c}"></button>`).join('')}
</div>
</div>
<div class="form-group mt-4">
<label class="form-label">Sidebar Style</label>
<select class="form-select"><option>Compact (Default)</option><option>Wide</option><option>Collapsed</option></select>
</div>
<div class="form-group">
<label class="form-label">Table Density</label>
<select class="form-select"><option>Comfortable (Default)</option><option>Compact</option><option>Spacious</option></select>
</div>
</div>
</div>`,
depreciation: `
<div class="card">
<div class="card-header"><span class="card-title">💰 Depreciation Defaults</span></div>
<div class="card-body">
<div class="alert alert-info mb-4">
<div class="alert-icon"></div>
<div><div class="alert-title">These are default values applied when creating new assets</div><div class="alert-text">Each asset can override these per category settings.</div></div>
</div>
<div class="form-group"><label class="form-label">Default Depreciation Method</label>
<select class="form-select"><option selected>SLM Straight Line Method (as per Companies Act)</option><option>WDV Written Down Value</option></select>
</div>
<hr class="divider">
<div class="section-hdr">Category-wise Default Rates</div>
<table class="data-table" style="font-size:12.5px">
<thead><tr><th>Category</th><th>Default Method</th><th>Rate (% p.a.)</th><th>Useful Life (Years)</th></tr></thead>
<tbody>
${AMS.categories.map(c=>`<tr data-cat="${c.id}">
<td>${c.icon} ${c.name}</td>
<td><select class="form-select cat-depM" style="padding:4px 8px;font-size:11px"><option ${c.depM==='SLM'?'selected':''}>SLM</option><option ${c.depM==='WDV'?'selected':''}>WDV</option></select></td>
<td><input type="number" class="form-input cat-depR" value="${c.depR}" style="width:70px;padding:4px 8px">%</td>
<td><input type="number" class="form-input cat-life" value="${c.life}" style="width:70px;padding:4px 8px"> yr</td>
</tr>`).join('')}
</tbody>
</table>
</div>
</div>`,
notifications: `
<div class="card">
<div class="card-header"><span class="card-title">🔔 Notification Preferences</span></div>
<div class="card-body">
<div class="section-hdr">Warranty Alerts</div>
${notifRow('Warranty expiry alert',true,'Send email 90 / 60 / 30 days before expiry')}
${notifRow('Warranty expired',true,'Immediate alert when warranty expires')}
<hr class="divider">
<div class="section-hdr">Maintenance Alerts</div>
${notifRow('PM due reminder',true,'7 days before scheduled PM')}
${notifRow('PM overdue',true,'Daily reminders for overdue PMs')}
${notifRow('Ticket assigned to me',true,'When a ticket is assigned to you')}
${notifRow('Ticket status change',false,'When status changes on your tickets')}
<hr class="divider">
<div class="section-hdr">Procurement Alerts</div>
${notifRow('PR requires my approval',true,'When a PR is sent to you for approval')}
${notifRow('PR approved / rejected',true,'When your PR is actioned')}
${notifRow('PO delivery due',false,'3 days before expected delivery date')}
<hr class="divider">
<div class="section-hdr">System Alerts</div>
${notifRow('Low stock threshold reached',true,'When any category falls below minimum')}
${notifRow('AMC expiry reminder',true,'30 days before AMC contract expires')}
${notifRow('Audit schedule reminder',false,'Quarterly audit schedule reminders')}
</div>
</div>`,
email: `
<div class="card">
<div class="card-header"><span class="card-title">📧 Email / SMTP Configuration</span></div>
<div class="card-body">
<div class="form-row">
<div class="form-group"><label class="form-label">SMTP Host</label><input class="form-input" value="smtp.acmecorp.com"></div>
<div class="form-group"><label class="form-label">SMTP Port</label><input class="form-input" value="587"></div>
</div>
<div class="form-row">
<div class="form-group"><label class="form-label">Username</label><input class="form-input" value="ams@acmecorp.com"></div>
<div class="form-group"><label class="form-label">Password</label><input type="password" class="form-input" value="•••••••••••••••"></div>
</div>
<div class="form-row">
<div class="form-group"><label class="form-label">Sender Name</label><input class="form-input" value="AMS Acme Corporation"></div>
<div class="form-group"><label class="form-label">Encryption</label><select class="form-select"><option selected>STARTTLS</option><option>SSL/TLS</option><option>None</option></select></div>
</div>
<div class="form-row">
<div class="form-group"><label class="form-label">Test Recipient</label><input type="email" class="form-input" placeholder="Send test email to…"></div>
<div class="form-group" style="display:flex;align-items:flex-end"><button class="btn btn-secondary w-full" onclick="testEmail()">📧 Send Test Email</button></div>
</div>
</div>
</div>`,
backup: `
<div class="card">
<div class="card-header"><span class="card-title">💾 Backup & Data Export</span></div>
<div class="card-body">
<div class="section-hdr">Automated Backup</div>
<div class="form-group"><label class="form-label">Backup Frequency</label><select class="form-select"><option selected>Daily (2:00 AM IST)</option><option>Weekly</option><option>Monthly</option><option>Disabled</option></select></div>
<div class="form-group"><label class="form-label">Backup Location</label><select class="form-select"><option selected>AWS S3 ap-south-1</option><option>Google Cloud Storage</option><option>Local Server</option><option>SFTP</option></select></div>
<div class="form-group"><label class="form-label">Retention Period</label><select class="form-select"><option>30 days</option><option selected>90 days</option><option>1 year</option></select></div>
<hr class="divider">
<div class="section-hdr">Manual Export</div>
<div class="flex gap-3 flex-wrap">
<button class="btn btn-secondary" onclick="showToast('Export','Exporting full asset database to JSON…','info')">📤 Export Database (JSON)</button>
<button class="btn btn-secondary" onclick="showToast('Export','Exporting asset register to CSV…','info')">📊 Export Asset Register (CSV)</button>
<button class="btn btn-secondary" onclick="showToast('Export','Generating audit report PDF…','info')">📄 Export Audit Report (PDF)</button>
</div>
<hr class="divider">
<div class="section-hdr">Import</div>
<div class="alert alert-warning mb-3"><div class="alert-icon">⚠️</div><div><div class="alert-title">Bulk import may overwrite existing records</div><div class="alert-text">Always take a backup before bulk importing data.</div></div></div>
<div class="flex gap-3">
<label class="btn btn-secondary" for="importFile">📥 Import Assets (CSV)</label>
<input type="file" id="importFile" accept=".csv" style="display:none" onchange="handleImport()">
<button class="btn btn-ghost btn-sm" onclick="downloadTemplate()">📋 Download Template</button>
</div>
</div>
</div>`,
security: `
<div class="card">
<div class="card-header"><span class="card-title">🔐 Security Settings</span></div>
<div class="card-body">
<div class="section-hdr">Two-Factor Authentication</div>
<div class="flex items-center justify-between mb-4 p-4 bg-elevated rounded-md border">
<div><div style="font-weight:600">Enforce 2FA for all users</div><div style="font-size:12.5px;color:var(--text-muted)">All users will be required to set up 2FA on next login</div></div>
<label class="toggle"><input type="checkbox" checked><span class="toggle-slider"></span></label>
</div>
<div class="flex items-center justify-between mb-4 p-4 bg-elevated rounded-md border">
<div><div style="font-weight:600">2FA for Admin roles only</div><div style="font-size:12.5px;color:var(--text-muted)">Only Asset Managers and Super Admins require 2FA</div></div>
<label class="toggle"><input type="checkbox"><span class="toggle-slider"></span></label>
</div>
<hr class="divider">
<div class="section-hdr">Session Policy</div>
<div class="form-row">
<div class="form-group"><label class="form-label">Session Timeout</label><select class="form-select"><option>30 minutes</option><option selected>1 hour</option><option>4 hours</option><option>8 hours</option><option>No timeout</option></select></div>
<div class="form-group"><label class="form-label">Max Concurrent Sessions</label><select class="form-select"><option>1</option><option selected>3</option><option>5</option><option>Unlimited</option></select></div>
</div>
<div class="form-group"><label class="form-label">IP Whitelist (optional)</label><textarea class="form-textarea" rows="2" placeholder="Enter allowed IP ranges, one per line. e.g. 192.168.1.0/24"></textarea></div>
<hr class="divider">
<div class="section-hdr">Password Policy</div>
<div class="form-row">
<div class="form-group"><label class="form-label">Minimum Length</label><input type="number" class="form-input" value="10" min="8"></div>
<div class="form-group"><label class="form-label">Expire After</label><select class="form-select"><option>Never</option><option selected>90 days</option><option>180 days</option><option>1 year</option></select></div>
</div>
</div>
</div>`,
integrations: `
<div class="card">
<div class="card-header"><span class="card-title">🔗 Integrations</span></div>
<div class="card-body">
${integrationCard('Microsoft Active Directory / Azure AD','🔷','SSO via Microsoft OAuth 2.0. Sync users from AD groups.','Connected','Connected · 10 users synced')}
${integrationCard('Tally ERP / Zoho Books','📊','Auto-sync asset depreciation and financial data to accounting.','Connect','Not Connected')}
${integrationCard('JIRA / ServiceNow','🎫','Create and sync support tickets with your ITSM tool.','Connect','Not Connected')}
${integrationCard('Slack / Microsoft Teams','💬','Send alerts, notifications, and approvals to Slack/Teams channels.','Connect','Not Connected')}
${integrationCard('ERP System (SAP / Oracle)','🏭','Bi-directional sync with enterprise ERP for procurement data.','Connect','Not Connected')}
${integrationCard('Webhooks (Custom)','⚡','Send real-time events to your own systems via HTTP webhooks.','Configure','1 webhook active')}
</div>
</div>`
};
function notifRow(label, def, desc) {
return `<div class="flex items-center gap-3 mb-4" style="padding:12px;background:var(--bg-surface);border-radius:var(--radius-md);border:1px solid var(--border)">
<label class="toggle"><input type="checkbox" ${def?'checked':''}><span class="toggle-slider"></span></label>
<div style="flex:1"><div style="font-weight:600;font-size:13px">${label}</div><div style="font-size:11.5px;color:var(--text-muted)">${desc}</div></div>
</div>`;
}
function integrationCard(name, icon, desc, btnLabel, status) {
const connected = status.toLowerCase().includes('connected') || status.includes('active');
return `<div class="flex items-center gap-4 mb-4 p-4" style="background:var(--bg-surface);border-radius:var(--radius-md);border:1px solid var(--border)">
<div style="width:42px;height:42px;border-radius:10px;background:var(--bg-elevated);display:flex;align-items:center;justify-content:center;font-size:22px;flex-shrink:0">${icon}</div>
<div style="flex:1">
<div style="font-weight:700;font-size:13.5px">${name}</div>
<div style="font-size:12px;color:var(--text-muted);margin-bottom:4px">${desc}</div>
<div style="font-size:11px;color:${connected?'var(--success)':'var(--text-muted)'}">${status}</div>
</div>
<button class="btn ${connected?'btn-ghost':'btn-secondary'} btn-sm" onclick="showToast('Integration','${name} integration dialog opening…','info')">${btnLabel}</button>
</div>`;
}
let activeSect = 'general';
document.addEventListener('DOMContentLoaded', () => {
renderSettingsNav();
loadSection('general');
AMS.categories.forEach(c => {/* pre-load */});
});
function renderSettingsNav() {
document.getElementById('settingsNav').innerHTML = sections.map(s=>`
<div class="settings-nav-item ${s.id===activeSect?'active':''}" id="snav-${s.id}" onclick="loadSection('${s.id}')">
<span style="font-size:15px">${s.icon}</span>
<span>${s.label}</span>
</div>`).join('');
}
function loadSection(id) {
activeSect = id;
document.querySelectorAll('.settings-nav-item').forEach(el=>el.classList.remove('active'));
const el=document.getElementById('snav-'+id);
if(el)el.classList.add('active');
document.getElementById('settingsContent').innerHTML = settingsHTML[id] || `<div class="card"><div class="card-body">${id} settings</div></div>`;
if (typeof updateThemeUI === 'function') updateThemeUI();
}
function saveSettings() {
if (window.AMS) {
// Persist General (organization) settings if that section is rendered
const nameEl = document.getElementById('setCompanyName');
if (nameEl) {
AMS.company.name = nameEl.value.trim() || AMS.company.name;
const addr = document.getElementById('setAddress');
const gst = document.getElementById('setGst');
if (addr) AMS.company.address = addr.value.trim();
if (gst) AMS.company.gst = gst.value.trim();
const cur = document.getElementById('setCurrency');
if (cur) {
const map = { 'INR (₹)':['₹','INR'], 'USD ($)':['$','USD'], 'EUR (€)':['€','EUR'], 'GBP (£)':['£','GBP'] };
const [sym, code] = map[cur.value] || ['₹','INR'];
AMS.company.currency = sym; AMS.company.currencyCode = code;
}
}
// Persist Depreciation category defaults if that section is rendered
document.querySelectorAll('tr[data-cat]').forEach(tr => {
const cat = AMS.categories.find(c => c.id === tr.dataset.cat);
if (!cat) return;
const depM = tr.querySelector('.cat-depM');
const depR = tr.querySelector('.cat-depR');
const life = tr.querySelector('.cat-life');
if (depM) cat.depM = depM.value;
if (depR) cat.depR = parseInt(depR.value, 10) || cat.depR;
if (life) cat.life = parseInt(life.value, 10) || cat.life;
});
AMS.save();
}
document.getElementById('saveSettingsBtn').textContent = '✅ Saved!';
showToast('Settings Saved','All configuration changes have been applied','success');
setTimeout(()=>{ document.getElementById('saveSettingsBtn').textContent = '💾 Save All Settings'; },2500);
}
function testEmail() { showToast('Test Email Sent','Check your inbox for the test email','success'); }
function handleImport() { showToast('Import Started','Validating CSV file…','info'); }
function downloadTemplate() { showToast('Template Downloaded','CSV import template downloaded','success'); }
function setAccent(color) { showToast('Theme Updated',`Accent color changed to ${color}`,'success'); }
</script>
</body>
</html>