Medical Inventory Portal

* {
margin: 0;
padding: 0;
box-sizing: border-box;
}

body {
font-family: ‘Segoe UI’, Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
color: #333;
}

.container {
max-width: 1400px;
margin: 0 auto;
padding: 20px;
}

.header {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(10px);
border-radius: 20px;
padding: 30px;
margin-bottom: 30px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
text-align: center;
}

.header h1 {
color: #2c3e50;
font-size: 2.5rem;
margin-bottom: 10px;
font-weight: 700;
}

.header p {
color: #7f8c8d;
font-size: 1.1rem;
}

.nav-tabs {
display: flex;
background: rgba(255, 255, 255, 0.9);
border-radius: 15px;
padding: 5px;
margin-bottom: 30px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
overflow-x: auto;
}

.nav-tab {
flex: 1;
padding: 15px 20px;
background: transparent;
border: none;
border-radius: 10px;
cursor: pointer;
font-weight: 600;
color: #666;
transition: all 0.3s ease;
white-space: nowrap;
min-width: 120px;
}

.nav-tab.active {
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
}

.tab-content {
display: none;
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(10px);
border-radius: 20px;
padding: 30px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
}

.tab-content.active {
display: block;
}

.dashboard-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
margin-bottom: 30px;
}

.dashboard-card {
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
color: white;
padding: 25px;
border-radius: 15px;
box-shadow: 0 6px 25px rgba(0, 0, 0, 0.15);
text-align: center;
transition: transform 0.3s ease;
}

.dashboard-card:hover {
transform: translateY(-5px);
}

.dashboard-card h3 {
font-size: 1.2rem;
margin-bottom: 10px;
opacity: 0.9;
}

.dashboard-card .number {
font-size: 2.5rem;
font-weight: 700;
margin-bottom: 5px;
}

.dashboard-card.warning {
background: linear-gradient(135deg, #ff9a9e 0%, #fecfef 100%);
}

.dashboard-card.success {
background: linear-gradient(135deg, #a8edea 0%, #fed6e3 100%);
}

.dashboard-card.info {
background: linear-gradient(135deg, #ffecd2 0%, #fcb69f 100%);
}

.search-bar {
width: 100%;
padding: 15px 20px;
border: 2px solid #e0e6ed;
border-radius: 12px;
font-size: 1rem;
margin-bottom: 20px;
transition: border-color 0.3s ease;
}

.search-bar:focus {
outline: none;
border-color: #667eea;
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}

.filter-group {
display: flex;
gap: 15px;
margin-bottom: 20px;
flex-wrap: wrap;
}

.filter-select {
padding: 10px 15px;
border: 2px solid #e0e6ed;
border-radius: 8px;
background: white;
cursor: pointer;
min-width: 150px;
}

.items-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
gap: 20px;
margin-top: 20px;
}

.item-card {
background: white;
border-radius: 12px;
padding: 20px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
border-left: 4px solid #667eea;
transition: all 0.3s ease;
}

.item-card:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
}

.item-card.low-stock {
border-left-color: #e74c3c;
}

.item-card.out-of-stock {
border-left-color: #c0392b;
opacity: 0.8;
}

.item-card h4 {
color: #2c3e50;
margin-bottom: 10px;
font-size: 1.1rem;
}

.item-details {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 10px;
font-size: 0.9rem;
color: #666;
}

.status-badge {
display: inline-block;
padding: 4px 12px;
border-radius: 20px;
font-size: 0.8rem;
font-weight: 600;
margin-top: 10px;
}

.status-good {
background: #d5f4e6;
color: #27ae60;
}

.status-low {
background: #fef9e7;
color: #f39c12;
}

.status-critical {
background: #fadbd8;
color: #e74c3c;
}

.form-section {
background: #f8f9fa;
padding: 25px;
border-radius: 12px;
margin-bottom: 20px;
}

.form-section h3 {
color: #2c3e50;
margin-bottom: 20px;
padding-bottom: 10px;
border-bottom: 2px solid #ecf0f1;
}

.form-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
}

.form-group {
display: flex;
flex-direction: column;
}

.form-group label {
margin-bottom: 5px;
font-weight: 600;
color: #555;
}

.form-group input,
.form-group select,
.form-group textarea {
padding: 12px;
border: 2px solid #e0e6ed;
border-radius: 8px;
font-size: 1rem;
transition: border-color 0.3s ease;
}

.form-group input:focus,
.form-group select:focus,
.form-group textarea:focus {
outline: none;
border-color: #667eea;
}

.btn {
padding: 12px 25px;
border: none;
border-radius: 8px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
font-size: 1rem;
}

.btn-primary {
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
}

.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(102, 126, 234, 0.4);
}

.btn-secondary {
background: #6c757d;
color: white;
}

.btn-danger {
background: #e74c3c;
color: white;
}

.maintenance-item {
background: white;
padding: 20px;
border-radius: 12px;
margin-bottom: 15px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
border-left: 4px solid #f39c12;
}

.maintenance-item.overdue {
border-left-color: #e74c3c;
}

.maintenance-item.upcoming {
border-left-color: #3498db;
}

.vendor-card {
background: white;
padding: 20px;
border-radius: 12px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
margin-bottom: 15px;
}

.alert {
padding: 15px 20px;
border-radius: 8px;
margin-bottom: 20px;
font-weight: 500;
}

.alert-warning {
background: #fff3cd;
color: #856404;
border-left: 4px solid #ffc107;
}

.alert-danger {
background: #f8d7da;
color: #721c24;
border-left: 4px solid #dc3545;
}

@media (max-width: 768px) {
.container {
padding: 10px;
}

.dashboard-grid {
grid-template-columns: 1fr;
}

.items-grid {
grid-template-columns: 1fr;
}

.nav-tabs {
flex-direction: column;
}

.filter-group {
flex-direction: column;
}
}

🏥 Medical Inventory Portal

Comprehensive Equipment & Supply Management System

Total Equipment

24

Active machines

Supply Items

156

In inventory

Low Stock Items

8

Need reordering

Upcoming Service

3

Due this month

⚠️ Attention: 3 items are critically low on stock and need immediate reordering.

🚨 Critical Alerts

All Equipment Types
MRI Scanners
CT Scanners
Ultrasound
X-Ray Machines
Mammography

All Locations
Radiology
Emergency
Surgery
ICU

All Status
Active
Under Maintenance
Inactive

All Categories
Contrast Media
Personal Protective Equipment
Disposables
Medications
Medical Tools

All Stock Levels
Good Stock
Low Stock
Critical/Out

🛠️ Maintenance Schedule

🏢 Vendor Directory

➕ Add New Equipment

Equipment Name

Type

Select Type

Model

Serial Number

Location

Select Location

Status

Select Status

Purchase Date

Vendor

Add Equipment

📦 Add New Supply Item

Item Name

Category

Select Category

Current Stock

Minimum Level

Unit of Measure

Location

Vendor

Expiry Date

Add Supply Item

⚙️ System Administration

Manage dropdown options for locations, equipment types, supply categories, and vendors.

🔧 Equipment Types

Add Type

📍 Locations

Add Location

📦 Supply Categories

Add Category

🏢 Vendors Management

Add New Vendor

Vendor Name

Contact Person

Phone Number

Email Address

Specialties (comma-separated)

Add Vendor

Current Vendors

📊 Equipment Status Options

Add Status

💾 Data Management

📥 Export All Data
🗑️ Clear All Data
🔄 Reset to Defaults

📤 Import Data

Import from JSON Backup

📁 Import JSON

Import a complete backup file exported from this system

Import from CSV Files

🔧 Equipment CSV

📊 Import Equipment
📋 Download Template

Required columns: Name, Type, Model, Serial, Location, Status, Vendor, Purchase Date

📦 Supplies CSV

📊 Import Supplies
📋 Download Template

Required columns: Name, Category, Current Stock, Min Level, Unit, Location, Vendor, Expiry Date

🏢 Vendors CSV

📊 Import Vendors
📋 Download Template

Required columns: Name, Contact, Phone, Email, Specialties

Import Options

📝 Append (Add to existing data)

🔄 Replace (Clear existing data first)

Note: Export will download a JSON file with all your data. Clear All Data will remove everything permanently.

🔧 Equipment Management

All Equipment

🔍 Search

📦 Supply Management

All Categories

🔍 Search

/*
* AUTHENTICATION & SECURITY IMPLEMENTATION
*
* Current Approach (Demo/Development):
* – Client-side authentication with in-memory session storage
* – Hardcoded user credentials for demonstration
* – Role-based permissions (admin, staff, viewer)
* – Session expires when browser closes/refreshes
*
* Production Recommendations:
* – Backend authentication server (Node.js, Python, etc.)
* – Secure password hashing (bcrypt, scrypt)
* – JWT tokens or secure session management
* – HTTPS only for all communications
* – Database for user management
* – Two-factor authentication (2FA)
* – Password complexity requirements
* – Account lockout after failed attempts
* – Audit logging for all administrative actions
*
* Easy Migration Path:
* 1. Replace login() function to call backend API
* 2. Store JWT token securely
* 3. Add token to all API requests
* 4. Validate permissions on backend
* 5. Add proper session management
*/

// Authentication system
let currentUser = null;
let isAuthenticated = false;

// User credentials (in production, this would be handled by backend)
const users = {
‘admin’: {
password: ‘admin123’,
role: ‘admin’,
name: ‘Administrator’,
permissions: [‘view’, ‘add’, ‘edit’, ‘delete’, ‘admin’]
},
‘staff’: {
password: ‘staff123’,
role: ‘staff’,
name: ‘Staff Member’,
permissions: [‘view’, ‘add’, ‘edit’]
},
‘viewer’: {
password: ‘viewer123’,
role: ‘viewer’,
name: ‘Viewer’,
permissions: [‘view’]
}
};

// Sample data
let equipmentTypes = [“MRI”, “CT”, “Ultrasound”, “X-Ray”, “Mammography”, “Nuclear Medicine”, “PET Scan”];
let locations = [“Radiology”, “Emergency”, “Surgery”, “ICU”, “Cardiology”, “Neurology”, “Oncology”];
let supplyCategories = [“Contrast”, “PPE”, “Disposables”, “Medications”, “Tools”, “Linens”, “Cleaning Supplies”];
let equipmentStatuses = [“Active”, “Maintenance”, “Inactive”, “Decommissioned”];

let machines = [
{
id: 1,
name: “Siemens MAGNETOM Vida”,
type: “MRI”,
model: “MAGNETOM Vida 3T”,
serial: “SN12345”,
location: “Radiology”,
status: “Active”,
purchaseDate: “2022-03-15”,
vendor: “Siemens Healthcare”,
lastService: “2024-06-15”,
nextService: “2024-07-20” // This is overdue to show in critical alerts
},
{
id: 2,
name: “GE Revolution CT”,
type: “CT”,
model: “Revolution CT”,
serial: “GE98765”,
location: “Emergency”,
status: “Active”,
purchaseDate: “2021-08-20”,
vendor: “GE Healthcare”,
lastService: “2024-05-10”,
nextService: “2025-05-10”
},
{
id: 3,
name: “Philips EPIQ Elite”,
type: “Ultrasound”,
model: “EPIQ Elite”,
serial: “PH54321”,
location: “Radiology”,
status: “Maintenance”,
purchaseDate: “2023-01-10”,
vendor: “Philips Healthcare”,
lastService: “2024-07-01”,
nextService: “2025-01-01”
}
];

let supplies = [
{
id: 1,
name: “Gadolinium Contrast”,
category: “Contrast”,
currentStock: 0,
minLevel: 50,
unit: “vials”,
location: “Radiology Storage”,
vendor: “Bayer HealthCare”,
expiryDate: “2025-12-31”
},
{
id: 2,
name: “Surgical Gloves – Large”,
category: “PPE”,
currentStock: 25,
minLevel: 100,
unit: “boxes”,
location: “Supply Room A”,
vendor: “Ansell Healthcare”,
expiryDate: “2026-03-15”
},
{
id: 3,
name: “Disposable Syringes 10ml”,
category: “Disposables”,
currentStock: 500,
minLevel: 200,
unit: “pieces”,
location: “Supply Room B”,
vendor: “BD Medical”,
expiryDate: “2027-01-20”
},
{
id: 4,
name: “Iodine Contrast Media”,
category: “Contrast”,
currentStock: 15,
minLevel: 25,
unit: “bottles”,
location: “Radiology Storage”,
vendor: “GE Healthcare”,
expiryDate: “2025-09-30”
}
];

let vendors = [
{
name: “Siemens Healthcare”,
contact: “John Smith”,
phone: “1-800-SIEMENS”,
email: “service@siemens-healthineers.com”,
specialties: [“MRI”, “CT”, “X-Ray”]
},
{
name: “GE Healthcare”,
contact: “Sarah Johnson”,
phone: “1-800-GE-CARE”,
email: “support@gehealthcare.com”,
specialties: [“CT”, “MRI”, “Ultrasound”]
},
{
name: “Philips Healthcare”,
contact: “Mike Wilson”,
phone: “1-800-PHILIPS”,
email: “service@philips.com”,
specialties: [“Ultrasound”, “MRI”, “Monitoring”]
}
];

// Tab switching with authentication check
function showTab(tabName) {
// Check if tab requires authentication
if ((tabName === ‘add-item’ || tabName === ‘admin’) && !isAuthenticated) {
showLoginModal();
return;
}

// Check permissions for admin tab
if (tabName === ‘admin’ && !hasPermission(‘admin’)) {
alert(‘Access denied. Admin privileges required.’);
return;
}

// Check permissions for add-item tab
if (tabName === ‘add-item’ && !hasPermission(‘add’)) {
alert(‘Access denied. Add items permission required.’);
return;
}

const tabs = document.querySelectorAll(‘.tab-content’);
const navTabs = document.querySelectorAll(‘.nav-tab’);

tabs.forEach(tab => tab.classList.remove(‘active’));
navTabs.forEach(nav => nav.classList.remove(‘active’));

document.getElementById(tabName).classList.add(‘active’);
event.target.classList.add(‘active’);

if (tabName === ‘machines’) loadMachines();
if (tabName === ‘supplies’) loadSupplies();
if (tabName === ‘maintenance’) loadMaintenance();
if (tabName === ‘vendors’) loadVendors();
if (tabName === ‘admin’) loadAdmin();
if (tabName === ‘dashboard’) updateDashboard(); // Refresh dashboard including critical alerts
}

// Authentication functions
function showLoginModal() {
document.getElementById(‘login-modal’).style.display = ‘flex’;
document.getElementById(‘username’).focus();
}

function closeLoginModal() {
document.getElementById(‘login-modal’).style.display = ‘none’;
document.getElementById(‘login-form’).reset();
document.getElementById(‘login-error’).style.display = ‘none’;
}

function login(username, password) {
const user = users[username];

if (user && user.password === password) {
currentUser = {
username: username,
…user
};
isAuthenticated = true;

updateUIForAuthentication();
closeLoginModal();

// Show success message
alert(`Welcome, ${user.name}! You are now logged in.`);

return true;
} else {
showLoginError(‘Invalid username or password’);
return false;
}
}

function logout() {
if (confirm(‘Are you sure you want to logout?’)) {
currentUser = null;
isAuthenticated = false;
updateUIForAuthentication();

// Redirect to dashboard if on protected page
showTab(‘dashboard’);
document.querySelector(‘[onclick=”showTab(\’dashboard\’)”]’).classList.add(‘active’);

alert(‘You have been logged out successfully.’);
}
}

function hasPermission(permission) {
return isAuthenticated && currentUser && currentUser.permissions.includes(permission);
}

function updateUIForAuthentication() {
const userInfo = document.getElementById(‘user-info’);
const welcomeMessage = document.getElementById(‘welcome-message’);
const loginTab = document.getElementById(‘login-tab’);
const addItemsTab = document.getElementById(‘add-items-tab’);
const adminTab = document.getElementById(‘admin-tab’);

if (isAuthenticated) {
// Show user info
userInfo.style.display = ‘block’;
welcomeMessage.textContent = `${currentUser.name} (${currentUser.role})`;

// Hide login tab
loginTab.style.display = ‘none’;

// Show tabs based on permissions
if (hasPermission(‘add’)) {
addItemsTab.style.display = ‘block’;
}

if (hasPermission(‘admin’)) {
adminTab.style.display = ‘block’;
}
} else {
// Hide user info
userInfo.style.display = ‘none’;

// Show login tab
loginTab.style.display = ‘block’;

// Hide protected tabs
addItemsTab.style.display = ‘none’;
adminTab.style.display = ‘none’;
}
}

function showLoginError(message) {
const errorDiv = document.getElementById(‘login-error’);
errorDiv.textContent = message;
errorDiv.style.display = ‘block’;
}

// Tab switching (updated)
function showTab(tabName) {
const tabs = document.querySelectorAll(‘.tab-content’);
const navTabs = document.querySelectorAll(‘.nav-tab’);

tabs.forEach(tab => tab.classList.remove(‘active’));
navTabs.forEach(nav => nav.classList.remove(‘active’));

document.getElementById(tabName).classList.add(‘active’);
event.target.classList.add(‘active’);

if (tabName === ‘machines’) loadMachines();
if (tabName === ‘supplies’) loadSupplies();
if (tabName === ‘maintenance’) loadMaintenance();
if (tabName === ‘vendors’) loadVendors();
if (tabName === ‘admin’) loadAdmin();
if (tabName === ‘dashboard’) updateDashboard(); // Refresh dashboard including critical alerts
}

// Load machines
function loadMachines() {
const grid = document.getElementById(‘machines-grid’);
grid.innerHTML = ”;

machines.forEach(machine => {
const card = document.createElement(‘div’);
card.className = ‘item-card’;
if (machine.status === ‘Maintenance’) card.classList.add(‘low-stock’);

card.innerHTML = `

${machine.name}

Type: ${machine.type}
Model: ${machine.model}
Serial: ${machine.serial}
Location: ${machine.location}
Status: ${machine.status}
Vendor: ${machine.vendor}
Next Service: ${machine.nextService}

${machine.status.toUpperCase()}
`;
grid.appendChild(card);
});
}

function loadAdminEquipment() {
const searchTerm = document.getElementById(‘equipment-search-admin’).value.toLowerCase();
const typeFilter = document.getElementById(‘equipment-filter-admin’).value;

const filtered = machines.filter(machine => {
const matchesSearch = machine.name.toLowerCase().includes(searchTerm) ||
machine.model.toLowerCase().includes(searchTerm) ||
machine.serial.toLowerCase().includes(searchTerm) ||
machine.location.toLowerCase().includes(searchTerm);
const matchesType = !typeFilter || machine.type === typeFilter;
return matchesSearch && matchesType;
});

const list = document.getElementById(‘admin-equipment-list’);
list.innerHTML = ”;

if (filtered.length === 0) {
list.innerHTML = ‘

No equipment found matching your criteria.

‘;
return;
}

filtered.forEach((machine, originalIndex) => {
const actualIndex = machines.findIndex(m => m.id === machine.id);
const card = document.createElement(‘div’);
card.className = ‘item-card’;
card.style.position = ‘relative’;
card.style.marginBottom = ’15px’;

card.innerHTML = `

${machine.name}

Type: ${machine.type}
Model: ${machine.model}
Serial: ${machine.serial}
Location: ${machine.location}
Status: ${machine.status}
Vendor: ${machine.vendor}

${hasPermission(‘edit’) ? `✏️ Edit` : ”}
${hasPermission(‘delete’) ? `🗑️ Delete` : ”}

`;
list.appendChild(card);
});
}

function loadAdminSupplies() {
const searchTerm = document.getElementById(‘supply-search-admin’).value.toLowerCase();
const categoryFilter = document.getElementById(‘supply-filter-admin’).value;

const filtered = supplies.filter(supply => {
const matchesSearch = supply.name.toLowerCase().includes(searchTerm) ||
supply.location.toLowerCase().includes(searchTerm) ||
supply.vendor.toLowerCase().includes(searchTerm);
const matchesCategory = !categoryFilter || supply.category === categoryFilter;
return matchesSearch && matchesCategory;
});

const list = document.getElementById(‘admin-supply-list’);
list.innerHTML = ”;

if (filtered.length === 0) {
list.innerHTML = ‘

No supplies found matching your criteria.

‘;
return;
}

filtered.forEach((supply) => {
const actualIndex = supplies.findIndex(s => s.id === supply.id);
const card = document.createElement(‘div’);
card.className = ‘item-card’;
card.style.position = ‘relative’;
card.style.marginBottom = ’15px’;

let stockStatus = ‘Good Stock’;
let statusClass = ‘status-good’;

if (supply.currentStock === 0) {
stockStatus = ‘OUT OF STOCK’;
statusClass = ‘status-critical’;
} else if (supply.currentStock <= supply.minLevel) {
stockStatus = 'Low Stock';
statusClass = 'status-low';
}

card.innerHTML = `

${supply.name}

Category: ${supply.category}
Stock: ${supply.currentStock} ${supply.unit}
Min Level: ${supply.minLevel} ${supply.unit}
Location: ${supply.location}
Vendor: ${supply.vendor}
Expires: ${supply.expiryDate}

${stockStatus}

${hasPermission(‘edit’) ? `✏️ Edit` : ”}
${hasPermission(‘delete’) ? `🗑️ Delete` : ”}

`;
list.appendChild(card);
});
}

function removeEquipment(index) {
const equipment = machines[index];
if (confirm(`Are you sure you want to delete “${equipment.name}”?\n\nThis action cannot be undone.`)) {
machines.splice(index, 1);
loadAdminEquipment();
updateDashboard();
alert(‘Equipment deleted successfully.’);
}
}

function removeSupply(index) {
const supply = supplies[index];
if (confirm(`Are you sure you want to delete “${supply.name}”?\n\nThis action cannot be undone.`)) {
supplies.splice(index, 1);
loadAdminSupplies();
updateDashboard();
alert(‘Supply item deleted successfully.’);
}
}

function removeEquipment(index) {
const equipment = machines[index];
if (confirm(`Are you sure you want to delete “${equipment.name}”?\n\nThis action cannot be undone.`)) {
machines.splice(index, 1);
loadAdminEquipment();
updateDashboard();
alert(‘Equipment deleted successfully.’);
}
}

function removeSupply(index) {
const supply = supplies[index];
if (confirm(`Are you sure you want to delete “${supply.name}”?\n\nThis action cannot be undone.`)) {
supplies.splice(index, 1);
loadAdminSupplies();
updateDashboard();
alert(‘Supply item deleted successfully.’);
}
}

function editEquipment(index) {
const equipment = machines[index];

// Create modal-style edit form
const modal = document.createElement(‘div’);
modal.style.cssText = `
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
`;

const form = document.createElement(‘div’);
form.style.cssText = `
background: white;
padding: 30px;
border-radius: 15px;
max-width: 500px;
width: 90%;
max-height: 80vh;
overflow-y: auto;
`;

form.innerHTML = `

Edit Equipment

Equipment Name

Type

${equipmentTypes.map(type => `${type}`).join(”)}

Model

Serial Number

Location

${locations.map(location => `${location}`).join(”)}

Status

${equipmentStatuses.map(status => `${status}`).join(”)}

Vendor

Purchase Date

Cancel
Save Changes

`;

modal.appendChild(form);
document.body.appendChild(modal);

// Handle form submission
document.getElementById(‘edit-equipment-form’).addEventListener(‘submit’, function(e) {
e.preventDefault();
const formData = new FormData(e.target);

machines[index] = {
…equipment,
name: formData.get(‘name’),
type: formData.get(‘type’),
model: formData.get(‘model’),
serial: formData.get(‘serial’),
location: formData.get(‘location’),
status: formData.get(‘status’),
vendor: formData.get(‘vendor’),
purchaseDate: formData.get(‘purchaseDate’)
};

document.body.removeChild(modal);
loadAdminEquipment();
updateDashboard(); // This will also update critical alerts
alert(‘Equipment updated successfully!’);
});

// Close modal when clicking outside
modal.addEventListener(‘click’, function(e) {
if (e.target === modal) {
document.body.removeChild(modal);
}
});
}

function editSupply(index) {
if (!hasPermission(‘edit’)) {
alert(‘Access denied. Edit permission required.’);
return;
}

const supply = supplies[index];

// Create modal-style edit form
const modal = document.createElement(‘div’);
modal.style.cssText = `
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
`;

const form = document.createElement(‘div’);
form.style.cssText = `
background: white;
padding: 30px;
border-radius: 15px;
max-width: 500px;
width: 90%;
max-height: 80vh;
overflow-y: auto;
`;

form.innerHTML = `

Edit Supply Item

Item Name

Category

${supplyCategories.map(category => `${category}`).join(”)}

Current Stock

Minimum Level

Unit of Measure

Location

Vendor

Expiry Date

Cancel
Save Changes

`;

modal.appendChild(form);
document.body.appendChild(modal);

// Handle form submission
document.getElementById(‘edit-supply-form’).addEventListener(‘submit’, function(e) {
e.preventDefault();
const formData = new FormData(e.target);

supplies[index] = {
…supply,
name: formData.get(‘name’),
category: formData.get(‘category’),
currentStock: parseInt(formData.get(‘currentStock’)),
minLevel: parseInt(formData.get(‘minLevel’)),
unit: formData.get(‘unit’),
location: formData.get(‘location’),
vendor: formData.get(‘vendor’),
expiryDate: formData.get(‘expiryDate’)
};

document.body.removeChild(modal);
loadAdminSupplies();
updateDashboard(); // This will also update critical alerts
alert(‘Supply item updated successfully!’);
});

// Close modal when clicking outside
modal.addEventListener(‘click’, function(e) {
if (e.target === modal) {
document.body.removeChild(modal);
}
});
}

function closeEditModal() {
const modals = document.querySelectorAll(‘div[style*=”position: fixed”]’);
modals.forEach(modal => {
if (modal.style.background.includes(‘rgba(0,0,0,0.5)’)) {
document.body.removeChild(modal);
}
});
}

// Make functions globally accessible
window.removeEquipment = removeEquipment;
window.removeSupply = removeSupply;
window.editEquipment = editEquipment;
window.editSupply = editSupply;
window.closeEditModal = closeEditModal;
window.removeVendor = removeVendor;
window.addEquipmentType = addEquipmentType;
window.addLocation = addLocation;
window.addCategory = addCategory;
window.addStatus = addStatus;
window.exportData = exportData;
window.clearAllData = clearAllData;
window.resetToDefaults = resetToDefaults;
window.importJSONData = importJSONData;
window.importEquipmentCSV = importEquipmentCSV;
window.importSuppliesCSV = importSuppliesCSV;
window.importVendorsCSV = importVendorsCSV;
window.downloadEquipmentTemplate = downloadEquipmentTemplate;
window.downloadSuppliesTemplate = downloadSuppliesTemplate;
window.downloadVendorsTemplate = downloadVendorsTemplate;
window.loadAdminEquipment = loadAdminEquipment;
window.loadAdminSupplies = loadAdminSupplies;
window.showTab = showTab;
window.updateCriticalAlerts = updateCriticalAlerts;
window.showLoginModal = showLoginModal;
window.closeLoginModal = closeLoginModal;
window.login = login;
window.logout = logout;

// Load supplies
function loadSupplies() {
const grid = document.getElementById(‘supplies-grid’);
grid.innerHTML = ”;

supplies.forEach(supply => {
const card = document.createElement(‘div’);
card.className = ‘item-card’;

if (supply.currentStock === 0) {
card.classList.add(‘out-of-stock’);
} else if (supply.currentStock <= supply.minLevel) {
card.classList.add('low-stock');
}

let stockStatus = 'Good Stock';
let statusClass = 'status-good';

if (supply.currentStock === 0) {
stockStatus = 'OUT OF STOCK';
statusClass = 'status-critical';
} else if (supply.currentStock <= supply.minLevel) {
stockStatus = 'Low Stock';
statusClass = 'status-low';
}

card.innerHTML = `

${supply.name}

Category: ${supply.category}
Stock: ${supply.currentStock} ${supply.unit}
Min Level: ${supply.minLevel} ${supply.unit}
Location: ${supply.location}
Vendor: ${supply.vendor}
Expires: ${supply.expiryDate}

${stockStatus}
`;
grid.appendChild(card);
});
}

// Load maintenance
function loadMaintenance() {
const list = document.getElementById(‘maintenance-list’);
list.innerHTML = ”;

machines.forEach(machine => {
const item = document.createElement(‘div’);
const nextService = new Date(machine.nextService);
const today = new Date();
const daysUntilService = Math.ceil((nextService – today) / (1000 * 60 * 60 * 24));

let statusClass = ‘maintenance-item’;
let statusText = ‘Scheduled’;

if (daysUntilService < 0) {
statusClass += ' overdue';
statusText = `OVERDUE (${Math.abs(daysUntilService)} days)`;
} else if (daysUntilService <= 30) {
statusClass += ' upcoming';
statusText = `Due in ${daysUntilService} days`;
} else {
statusText = `Due in ${daysUntilService} days`;
}

item.className = statusClass;
item.innerHTML = `

${machine.name} – ${machine.location}

Type: ${machine.type} | Model: ${machine.model}

Last Service: ${machine.lastService} | Next Service: ${machine.nextService}

Status: ${statusText} | Vendor: ${machine.vendor}

`;
list.appendChild(item);
});
}

// Load vendors
function loadVendors() {
const list = document.getElementById(‘vendors-list’);
list.innerHTML = ”;

vendors.forEach(vendor => {
const card = document.createElement(‘div’);
card.className = ‘vendor-card’;

card.innerHTML = `

${vendor.name}

Contact: ${vendor.contact}

Phone: ${vendor.phone}

Email: ${vendor.email}

Specialties: ${vendor.specialties.join(‘, ‘)}

`;
list.appendChild(card);
});
}

// Update dashboard counters
function updateDashboard() {
document.getElementById(‘total-machines’).textContent = machines.length;
document.getElementById(‘total-supplies’).textContent = supplies.length;

const lowStockItems = supplies.filter(s => s.currentStock 0);
const outOfStockItems = supplies.filter(s => s.currentStock === 0);
document.getElementById(‘low-stock-count’).textContent = lowStockItems.length + outOfStockItems.length;

const today = new Date();
const upcomingService = machines.filter(m => {
if (!m.nextService) return false;
const nextService = new Date(m.nextService);
const daysUntil = Math.ceil((nextService – today) / (1000 * 60 * 60 * 24));
return daysUntil = 0;
});
document.getElementById(‘upcoming-service’).textContent = upcomingService.length;

// Update critical alerts
updateCriticalAlerts();
}

// Update critical alerts dynamically
function updateCriticalAlerts() {
const alertsContainer = document.getElementById(‘critical-alerts’);
alertsContainer.innerHTML = ”;

const today = new Date();
let hasAlerts = false;

// Check for overdue maintenance
machines.forEach(machine => {
if (machine.nextService) {
const nextService = new Date(machine.nextService);
const daysOverdue = Math.ceil((today – nextService) / (1000 * 60 * 60 * 24));

if (daysOverdue > 0) {
hasAlerts = true;
const alertDiv = document.createElement(‘div’);
alertDiv.className = ‘maintenance-item overdue’;
alertDiv.innerHTML = `

${machine.name} – ${machine.location}

Overdue Service: Service was due ${daysOverdue} day${daysOverdue > 1 ? ‘s’ : ”} ago

Type: ${machine.type} | Vendor: ${machine.vendor}

`;
alertsContainer.appendChild(alertDiv);
}
}
});

// Check for upcoming maintenance (within 7 days)
machines.forEach(machine => {
if (machine.nextService) {
const nextService = new Date(machine.nextService);
const daysUntil = Math.ceil((nextService – today) / (1000 * 60 * 60 * 24));

if (daysUntil > 0 && daysUntil <= 7) {
hasAlerts = true;
const alertDiv = document.createElement('div');
alertDiv.className = 'maintenance-item upcoming';
alertDiv.innerHTML = `

${machine.name} – ${machine.location}

Upcoming Service: Due in ${daysUntil} day${daysUntil > 1 ? ‘s’ : ”}

Type: ${machine.type} | Vendor: ${machine.vendor}

`;
alertsContainer.appendChild(alertDiv);
}
}
});

// Check for out of stock items
supplies.forEach(supply => {
if (supply.currentStock === 0) {
hasAlerts = true;
const alertDiv = document.createElement(‘div’);
alertDiv.className = ‘item-card out-of-stock’;
alertDiv.innerHTML = `

${supply.name}

Stock: ${supply.currentStock} ${supply.unit}
Min Level: ${supply.minLevel} ${supply.unit}
Location: ${supply.location}
Category: ${supply.category}

OUT OF STOCK
`;
alertsContainer.appendChild(alertDiv);
}
});

// Check for critically low stock (at or below minimum level)
supplies.forEach(supply => {
if (supply.currentStock > 0 && supply.currentStock <= supply.minLevel) {
hasAlerts = true;
const alertDiv = document.createElement('div');
alertDiv.className = 'item-card low-stock';
alertDiv.innerHTML = `

${supply.name}

Stock: ${supply.currentStock} ${supply.unit}
Min Level: ${supply.minLevel} ${supply.unit}
Location: ${supply.location}
Category: ${supply.category}

CRITICALLY LOW
`;
alertsContainer.appendChild(alertDiv);
}
});

// Check for equipment under maintenance
machines.forEach(machine => {
if (machine.status === ‘Maintenance’) {
hasAlerts = true;
const alertDiv = document.createElement(‘div’);
alertDiv.className = ‘maintenance-item’;
alertDiv.innerHTML = `

${machine.name} – ${machine.location}

Status: Currently under maintenance

Type: ${machine.type} | Vendor: ${machine.vendor}

`;
alertsContainer.appendChild(alertDiv);
}
});

// Check for expired supplies (if expiry date is set)
const thirtyDaysFromNow = new Date();
thirtyDaysFromNow.setDate(today.getDate() + 30);

supplies.forEach(supply => {
if (supply.expiryDate) {
const expiryDate = new Date(supply.expiryDate);
if (expiryDate <= today) {
hasAlerts = true;
const alertDiv = document.createElement('div');
alertDiv.className = 'item-card out-of-stock';
alertDiv.innerHTML = `

${supply.name}

Stock: ${supply.currentStock} ${supply.unit}
Expired: ${supply.expiryDate}
Location: ${supply.location}
Category: ${supply.category}

EXPIRED
`;
alertsContainer.appendChild(alertDiv);
} else if (expiryDate <= thirtyDaysFromNow) {
hasAlerts = true;
const daysToExpiry = Math.ceil((expiryDate – today) / (1000 * 60 * 60 * 24));
const alertDiv = document.createElement('div');
alertDiv.className = 'item-card low-stock';
alertDiv.innerHTML = `

${supply.name}

Stock: ${supply.currentStock} ${supply.unit}
Expires in: ${daysToExpiry} day${daysToExpiry > 1 ? ‘s’ : ”}
Location: ${supply.location}
Category: ${supply.category}

EXPIRING SOON
`;
alertsContainer.appendChild(alertDiv);
}
}
});

// If no alerts, show a positive message
if (!hasAlerts) {
const alertDiv = document.createElement(‘div’);
alertDiv.style.cssText = `
text-align: center;
padding: 30px;
background: linear-gradient(135deg, #d5f4e6, #a8edea);
border-radius: 12px;
color: #27ae60;
`;
alertDiv.innerHTML = `

✅ All Systems Normal

No critical alerts at this time. All equipment is functioning properly and supplies are adequately stocked.

`;
alertsContainer.appendChild(alertDiv);
}
}

// Search functionality
function setupSearch() {
// Machine search
document.getElementById(‘machine-search’).addEventListener(‘input’, function(e) {
filterMachines();
});

// Supply search
document.getElementById(‘supply-search’).addEventListener(‘input’, function(e) {
filterSupplies();
});

// Machine filters
document.getElementById(‘machine-type-filter’).addEventListener(‘change’, filterMachines);
document.getElementById(‘machine-location-filter’).addEventListener(‘change’, filterMachines);
document.getElementById(‘machine-status-filter’).addEventListener(‘change’, filterMachines);

// Supply filters
document.getElementById(‘supply-category-filter’).addEventListener(‘change’, filterSupplies);
document.getElementById(‘supply-stock-filter’).addEventListener(‘change’, filterSupplies);
}

function filterMachines() {
const searchTerm = document.getElementById(‘machine-search’).value.toLowerCase();
const typeFilter = document.getElementById(‘machine-type-filter’).value;
const locationFilter = document.getElementById(‘machine-location-filter’).value;
const statusFilter = document.getElementById(‘machine-status-filter’).value;

const filtered = machines.filter(machine => {
const matchesSearch = machine.name.toLowerCase().includes(searchTerm) ||
machine.model.toLowerCase().includes(searchTerm) ||
machine.serial.toLowerCase().includes(searchTerm);
const matchesType = !typeFilter || machine.type === typeFilter;
const matchesLocation = !locationFilter || machine.location === locationFilter;
const matchesStatus = !statusFilter || machine.status === statusFilter;

return matchesSearch && matchesType && matchesLocation && matchesStatus;
});

displayFilteredMachines(filtered);
}

function filterSupplies() {
const searchTerm = document.getElementById(‘supply-search’).value.toLowerCase();
const categoryFilter = document.getElementById(‘supply-category-filter’).value;
const stockFilter = document.getElementById(‘supply-stock-filter’).value;

const filtered = supplies.filter(supply => {
const matchesSearch = supply.name.toLowerCase().includes(searchTerm) ||
supply.category.toLowerCase().includes(searchTerm) ||
supply.vendor.toLowerCase().includes(searchTerm);
const matchesCategory = !categoryFilter || supply.category === categoryFilter;

let matchesStock = true;
if (stockFilter === ‘Good’) {
matchesStock = supply.currentStock > supply.minLevel;
} else if (stockFilter === ‘Low’) {
matchesStock = supply.currentStock 0;
} else if (stockFilter === ‘Critical’) {
matchesStock = supply.currentStock === 0;
}

return matchesSearch && matchesCategory && matchesStock;
});

displayFilteredSupplies(filtered);
}

function displayFilteredMachines(filteredMachines) {
const grid = document.getElementById(‘machines-grid’);
grid.innerHTML = ”;

filteredMachines.forEach(machine => {
const card = document.createElement(‘div’);
card.className = ‘item-card’;
if (machine.status === ‘Maintenance’) card.classList.add(‘low-stock’);

card.innerHTML = `

${machine.name}

Type: ${machine.type}
Model: ${machine.model}
Serial: ${machine.serial}
Location: ${machine.location}
Status: ${machine.status}
Vendor: ${machine.vendor}
Next Service: ${machine.nextService}

${machine.status.toUpperCase()}
`;
grid.appendChild(card);
});
}

function displayFilteredSupplies(filteredSupplies) {
const grid = document.getElementById(‘supplies-grid’);
grid.innerHTML = ”;

filteredSupplies.forEach(supply => {
const card = document.createElement(‘div’);
card.className = ‘item-card’;

if (supply.currentStock === 0) {
card.classList.add(‘out-of-stock’);
} else if (supply.currentStock <= supply.minLevel) {
card.classList.add('low-stock');
}

let stockStatus = 'Good Stock';
let statusClass = 'status-good';

if (supply.currentStock === 0) {
stockStatus = 'OUT OF STOCK';
statusClass = 'status-critical';
} else if (supply.currentStock <= supply.minLevel) {
stockStatus = 'Low Stock';
statusClass = 'status-low';
}

card.innerHTML = `

${supply.name}

Category: ${supply.category}
Stock: ${supply.currentStock} ${supply.unit}
Min Level: ${supply.minLevel} ${supply.unit}
Location: ${supply.location}
Vendor: ${supply.vendor}
Expires: ${supply.expiryDate}

${stockStatus}
`;
grid.appendChild(card);
});
}

// Admin functions
function loadAdmin() {
updateDropdownManagement();
loadAdminVendors();
loadAdminEquipment();
loadAdminSupplies();
updateAdminFilters();
}

function updateAdminFilters() {
// Update equipment filter
const equipmentFilter = document.getElementById(‘equipment-filter-admin’);
equipmentFilter.innerHTML = ‘All Equipment’;
equipmentTypes.forEach(type => {
const option = document.createElement(‘option’);
option.value = type;
option.textContent = type;
equipmentFilter.appendChild(option);
});

// Update supply filter
const supplyFilter = document.getElementById(‘supply-filter-admin’);
supplyFilter.innerHTML = ‘All Categories’;
supplyCategories.forEach(category => {
const option = document.createElement(‘option’);
option.value = category;
option.textContent = category;
supplyFilter.appendChild(option);
});
}

function updateDropdownManagement() {
updateEquipmentTypesList();
updateLocationsList();
updateCategoriesList();
updateStatusList();
updateAllDropdowns();
}

function updateEquipmentTypesList() {
const list = document.getElementById(‘equipment-types-list’);
list.innerHTML = ”;
equipmentTypes.forEach((type, index) => {
const tag = createRemovableTag(type, () => removeEquipmentType(index));
list.appendChild(tag);
});
}

function updateLocationsList() {
const list = document.getElementById(‘locations-list’);
list.innerHTML = ”;
locations.forEach((location, index) => {
const tag = createRemovableTag(location, () => removeLocation(index));
list.appendChild(tag);
});
}

function updateCategoriesList() {
const list = document.getElementById(‘categories-list’);
list.innerHTML = ”;
supplyCategories.forEach((category, index) => {
const tag = createRemovableTag(category, () => removeCategory(index));
list.appendChild(tag);
});
}

function updateStatusList() {
const list = document.getElementById(‘status-list’);
list.innerHTML = ”;
equipmentStatuses.forEach((status, index) => {
const tag = createRemovableTag(status, () => removeStatus(index));
list.appendChild(tag);
});
}

function createRemovableTag(text, onRemove) {
const tag = document.createElement(‘div’);
tag.style.cssText = `
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
padding: 8px 12px;
border-radius: 20px;
display: flex;
align-items: center;
gap: 8px;
font-size: 0.9rem;
`;

const textSpan = document.createElement(‘span’);
textSpan.textContent = text;

const removeBtn = document.createElement(‘button’);
removeBtn.innerHTML = ‘×’;
removeBtn.style.cssText = `
background: rgba(255,255,255,0.3);
border: none;
color: white;
border-radius: 50%;
width: 20px;
height: 20px;
font-size: 14px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
`;
removeBtn.onclick = onRemove;

tag.appendChild(textSpan);
tag.appendChild(removeBtn);
return tag;
}

function addEquipmentType() {
const input = document.getElementById(‘new-equipment-type’);
const value = input.value.trim();
if (value && !equipmentTypes.includes(value)) {
equipmentTypes.push(value);
input.value = ”;
updateEquipmentTypesList();
updateAllDropdowns();
}
}

function removeEquipmentType(index) {
equipmentTypes.splice(index, 1);
updateEquipmentTypesList();
updateAllDropdowns();
}

function addLocation() {
const input = document.getElementById(‘new-location’);
const value = input.value.trim();
if (value && !locations.includes(value)) {
locations.push(value);
input.value = ”;
updateLocationsList();
updateAllDropdowns();
}
}

function removeLocation(index) {
locations.splice(index, 1);
updateLocationsList();
updateAllDropdowns();
}

function addCategory() {
const input = document.getElementById(‘new-category’);
const value = input.value.trim();
if (value && !supplyCategories.includes(value)) {
supplyCategories.push(value);
input.value = ”;
updateCategoriesList();
updateAllDropdowns();
}
}

function removeCategory(index) {
supplyCategories.splice(index, 1);
updateCategoriesList();
updateAllDropdowns();
}

function addStatus() {
const input = document.getElementById(‘new-status’);
const value = input.value.trim();
if (value && !equipmentStatuses.includes(value)) {
equipmentStatuses.push(value);
input.value = ”;
updateStatusList();
updateAllDropdowns();
}
}

function removeStatus(index) {
equipmentStatuses.splice(index, 1);
updateStatusList();
updateAllDropdowns();
}

function updateAllDropdowns() {
// Update equipment type dropdowns
updateDropdownOptions(‘machine-type-filter’, equipmentTypes);
updateDropdownOptions(‘add-machine-type’, equipmentTypes);

// Update location dropdowns
updateDropdownOptions(‘machine-location-filter’, locations);
updateDropdownOptions(‘add-machine-location’, locations);

// Update category dropdowns
updateDropdownOptions(‘supply-category-filter’, supplyCategories);
updateDropdownOptions(‘add-supply-category’, supplyCategories);

// Update status dropdowns
updateDropdownOptions(‘add-machine-status’, equipmentStatuses);
}

function updateDropdownOptions(elementId, options) {
const dropdown = document.getElementById(elementId);
if (!dropdown) return;

// Store current value
const currentValue = dropdown.value;

// Clear existing options except first one (which is usually “Select…” or “All…”)
const firstOption = dropdown.firstElementChild;
dropdown.innerHTML = ”;
if (firstOption) {
dropdown.appendChild(firstOption);
}

// Add new options
options.forEach(option => {
const optionElement = document.createElement(‘option’);
optionElement.value = option;
optionElement.textContent = option;
dropdown.appendChild(optionElement);
});

// Restore value if it still exists
if (options.includes(currentValue)) {
dropdown.value = currentValue;
}
}

function loadAdminVendors() {
const list = document.getElementById(‘admin-vendors-list’);
list.innerHTML = ”;

vendors.forEach((vendor, index) => {
const card = document.createElement(‘div’);
card.className = ‘vendor-card’;
card.style.position = ‘relative’;

card.innerHTML = `
×

${vendor.name}

Contact: ${vendor.contact}

Phone: ${vendor.phone}

Email: ${vendor.email}

Specialties: ${vendor.specialties.join(‘, ‘)}

`;
list.appendChild(card);
});
}

function removeVendor(index) {
if (confirm(‘Are you sure you want to remove this vendor?’)) {
vendors.splice(index, 1);
loadAdminVendors();
}
}

function exportData() {
const data = {
machines: machines,
supplies: supplies,
vendors: vendors,
equipmentTypes: equipmentTypes,
locations: locations,
supplyCategories: supplyCategories,
equipmentStatuses: equipmentStatuses,
exportDate: new Date().toISOString()
};

const blob = new Blob([JSON.stringify(data, null, 2)], { type: ‘application/json’ });
const url = URL.createObjectURL(blob);
const a = document.createElement(‘a’);
a.href = url;
a.download = `medical-inventory-backup-${new Date().toISOString().split(‘T’)[0]}.json`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}

function clearAllData() {
if (confirm(‘⚠️ This will permanently delete ALL data including equipment, supplies, vendors, and custom settings. Are you absolutely sure?’)) {
if (confirm(‘🚨 FINAL WARNING: This action cannot be undone. All your inventory data will be lost forever!’)) {
machines.length = 0;
supplies.length = 0;
vendors.length = 0;
resetToDefaults();
updateDashboard();
alert(‘All data has been cleared.’);
}
}
}

function resetToDefaults() {
equipmentTypes.length = 0;
equipmentTypes.push(“MRI”, “CT”, “Ultrasound”, “X-Ray”, “Mammography”, “Nuclear Medicine”, “PET Scan”);

locations.length = 0;
locations.push(“Radiology”, “Emergency”, “Surgery”, “ICU”, “Cardiology”, “Neurology”, “Oncology”);

supplyCategories.length = 0;
supplyCategories.push(“Contrast”, “PPE”, “Disposables”, “Medications”, “Tools”, “Linens”, “Cleaning Supplies”);

equipmentStatuses.length = 0;
equipmentStatuses.push(“Active”, “Maintenance”, “Inactive”, “Decommissioned”);

updateDropdownManagement();
alert(‘Settings have been reset to defaults.’);
}

// Import functionality
function importJSONData() {
const fileInput = document.getElementById(‘json-import’);
const file = fileInput.files[0];

if (!file) {
alert(‘Please select a JSON file to import.’);
return;
}

const reader = new FileReader();
reader.onload = function(e) {
try {
const data = JSON.parse(e.target.result);
const importMode = document.querySelector(‘input[name=”importMode”]:checked’).value;

if (importMode === ‘replace’) {
if (!confirm(‘ This will REPLACE ALL existing data. Are you sure?’)) {
return;
}
machines.length = 0;
supplies.length = 0;
vendors.length = 0;
}

let importedCounts = {
machines: 0,
supplies: 0,
vendors: 0,
settings: false
};

// Import machines
if (data.machines && Array.isArray(data.machines)) {
data.machines.forEach(machine => {
machine.id = machines.length + 1;
machines.push(machine);
importedCounts.machines++;
});
}

// Import supplies
if (data.supplies && Array.isArray(data.supplies)) {
data.supplies.forEach(supply => {
supply.id = supplies.length + 1;
supplies.push(supply);
importedCounts.supplies++;
});
}

// Import vendors
if (data.vendors && Array.isArray(data.vendors)) {
data.vendors.forEach(vendor => {
vendors.push(vendor);
importedCounts.vendors++;
});
}

// Import settings
if (data.equipmentTypes) {
equipmentTypes.length = 0;
equipmentTypes.push(…data.equipmentTypes);
importedCounts.settings = true;
}
if (data.locations) {
locations.length = 0;
locations.push(…data.locations);
importedCounts.settings = true;
}
if (data.supplyCategories) {
supplyCategories.length = 0;
supplyCategories.push(…data.supplyCategories);
importedCounts.settings = true;
}
if (data.equipmentStatuses) {
equipmentStatuses.length = 0;
equipmentStatuses.push(…data.equipmentStatuses);
importedCounts.settings = true;
}

showImportResults(‘JSON Import Successful!’,
`Imported: ${importedCounts.machines} equipment, ${importedCounts.supplies} supplies, ${importedCounts.vendors} vendors` +
(importedCounts.settings ? ‘, and system settings’ : ”), ‘success’);

updateDashboard();
updateDropdownManagement();
loadAdminEquipment();
loadAdminSupplies();
loadAdminVendors();

} catch (error) {
showImportResults(‘Import Failed’, ‘Invalid JSON file format. Please check your file.’, ‘error’);
}
};
reader.readAsText(file);
}

function importEquipmentCSV() {
const fileInput = document.getElementById(‘equipment-csv’);
importCSVFile(fileInput, ‘equipment’);
}

function importSuppliesCSV() {
const fileInput = document.getElementById(‘supplies-csv’);
importCSVFile(fileInput, ‘supplies’);
}

function importVendorsCSV() {
const fileInput = document.getElementById(‘vendors-csv’);
importCSVFile(fileInput, ‘vendors’);
}

function importCSVFile(fileInput, type) {
const file = fileInput.files[0];

if (!file) {
alert(`Please select a ${type} CSV file to import.`);
return;
}

const reader = new FileReader();
reader.onload = function(e) {
try {
const csv = e.target.result;
const lines = csv.split(‘\n’).filter(line => line.trim());

if (lines.length h.trim().replace(/”/g, ”));
const importMode = document.querySelector(‘input[name=”importMode”]:checked’).value;

let imported = 0;
let errors = [];

if (importMode === ‘replace’) {
if (type === ‘equipment’) machines.length = 0;
else if (type === ‘supplies’) supplies.length = 0;
else if (type === ‘vendors’) vendors.length = 0;
}

for (let i = 1; i {
if (values[index] !== undefined) {
item[header.toLowerCase().replace(/\s+/g, ”)] = values[index].trim();
}
});

if (type === ‘equipment’) {
const machine = {
id: machines.length + 1,
name: item.name || ”,
type: item.type || ”,
model: item.model || ”,
serial: item.serial || ”,
location: item.location || ”,
status: item.status || ‘Active’,
vendor: item.vendor || ”,
purchaseDate: item.purchasedate || ”,
lastService: ”,
nextService: ”
};

if (machine.name && machine.type) {
machines.push(machine);
imported++;
} else {
errors.push(`Row ${i + 1}: Missing required fields (Name, Type)`);
}
} else if (type === ‘supplies’) {
const supply = {
id: supplies.length + 1,
name: item.name || ”,
category: item.category || ”,
currentStock: parseInt(item.currentstock) || 0,
minLevel: parseInt(item.minlevel) || 0,
unit: item.unit || ”,
location: item.location || ”,
vendor: item.vendor || ”,
expiryDate: item.expirydate || ”
};

if (supply.name && supply.category) {
supplies.push(supply);
imported++;
} else {
errors.push(`Row ${i + 1}: Missing required fields (Name, Category)`);
}
} else if (type === ‘vendors’) {
const vendor = {
name: item.name || ”,
contact: item.contact || ”,
phone: item.phone || ”,
email: item.email || ”,
specialties: (item.specialties || ”).split(‘,’).map(s => s.trim()).filter(s => s)
};

if (vendor.name && vendor.contact) {
vendors.push(vendor);
imported++;
} else {
errors.push(`Row ${i + 1}: Missing required fields (Name, Contact)`);
}
}
} catch (error) {
errors.push(`Row ${i + 1}: ${error.message}`);
}
}

let message = `Successfully imported ${imported} ${type}`;
if (errors.length > 0) {
message += `\n${errors.length} errors:\n${errors.slice(0, 5).join(‘\n’)}`;
if (errors.length > 5) message += `\n… and ${errors.length – 5} more errors`;
}

showImportResults(‘CSV Import Complete’, message, errors.length > 0 ? ‘warning’ : ‘success’);

updateDashboard();
if (type === ‘equipment’) loadAdminEquipment();
else if (type === ‘supplies’) loadAdminSupplies();
else if (type === ‘vendors’) loadAdminVendors();

} catch (error) {
showImportResults(‘Import Failed’, ‘Error reading CSV file. Please check the file format.’, ‘error’);
}
};
reader.readAsText(file);
}

function parseCSVLine(line) {
const result = [];
let current = ”;
let inQuotes = false;

for (let i = 0; i item.replace(/”/g, ”));
}

function showImportResults(title, message, type) {
const resultsDiv = document.getElementById(‘import-results’);
resultsDiv.style.display = ‘block’;

let bgColor = ‘#d4edda’;
let textColor = ‘#155724’;
let borderColor = ‘#c3e6cb’;

if (type === ‘error’) {
bgColor = ‘#f8d7da’;
textColor = ‘#721c24’;
borderColor = ‘#f5c6cb’;
} else if (type === ‘warning’) {
bgColor = ‘#fff3cd’;
textColor = ‘#856404’;
borderColor = ‘#ffeaa7’;
}

resultsDiv.style.backgroundColor = bgColor;
resultsDiv.style.color = textColor;
resultsDiv.style.border = `1px solid ${borderColor}`;

resultsDiv.innerHTML = `

${title}
${message}

`;

setTimeout(() => {
resultsDiv.style.display = ‘none’;
}, 10000);
}

function downloadEquipmentTemplate() {
const csvContent = ‘Name,Type,Model,Serial,Location,Status,Vendor,Purchase Date\n’ +
‘”Siemens MRI Scanner”,”MRI”,”MAGNETOM Vida 3T”,”SN12345″,”Radiology”,”Active”,”Siemens Healthcare”,”2022-03-15″\n’ +
‘”GE CT Scanner”,”CT”,”Revolution CT”,”GE98765″,”Emergency”,”Active”,”GE Healthcare”,”2021-08-20″‘;
downloadCSV(‘equipment-template.csv’, csvContent);
}

function downloadSuppliesTemplate() {
const csvContent = ‘Name,Category,Current Stock,Min Level,Unit,Location,Vendor,Expiry Date\n’ +
‘”Gadolinium Contrast”,”Contrast”,”50″,”25″,”vials”,”Radiology Storage”,”Bayer HealthCare”,”2025-12-31″\n’ +
‘”Surgical Gloves – Large”,”PPE”,”100″,”50″,”boxes”,”Supply Room A”,”Ansell Healthcare”,”2026-03-15″‘;
downloadCSV(‘supplies-template.csv’, csvContent);
}

function downloadVendorsTemplate() {
const csvContent = ‘Name,Contact,Phone,Email,Specialties\n’ +
‘”Siemens Healthcare”,”John Smith”,”1-800-SIEMENS”,”service@siemens-healthineers.com”,”MRI,CT,X-Ray”\n’ +
‘”GE Healthcare”,”Sarah Johnson”,”1-800-GE-CARE”,”support@gehealthcare.com”,”CT,MRI,Ultrasound”‘;
downloadCSV(‘vendors-template.csv’, csvContent);
}

function downloadCSV(filename, content) {
const blob = new Blob([content], { type: ‘text/csv’ });
const url = URL.createObjectURL(blob);
const a = document.createElement(‘a’);
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}

// Form submissions
function setupForms() {
document.getElementById(‘add-machine-form’).addEventListener(‘submit’, function(e) {
e.preventDefault();
const formData = new FormData(e.target);
const newMachine = {
id: machines.length + 1,
name: formData.get(‘name’),
type: formData.get(‘type’),
model: formData.get(‘model’),
serial: formData.get(‘serial’),
location: formData.get(‘location’),
status: formData.get(‘status’),
purchaseDate: formData.get(‘purchaseDate’),
vendor: formData.get(‘vendor’),
lastService: ”,
nextService: ”
};

machines.push(newMachine);
e.target.reset();
updateDashboard();
alert(‘Equipment added successfully!’);
});

document.getElementById(‘add-supply-form’).addEventListener(‘submit’, function(e) {
e.preventDefault();
const formData = new FormData(e.target);
const newSupply = {
id: supplies.length + 1,
name: formData.get(‘name’),
category: formData.get(‘category’),
currentStock: parseInt(formData.get(‘currentStock’)),
minLevel: parseInt(formData.get(‘minLevel’)),
unit: formData.get(‘unit’),
location: formData.get(‘location’),
vendor: formData.get(‘vendor’),
expiryDate: formData.get(‘expiryDate’)
};

supplies.push(newSupply);
e.target.reset();
updateDashboard();
alert(‘Supply item added successfully!’);
});

// Add vendor form
document.getElementById(‘add-vendor-form’).addEventListener(‘submit’, function(e) {
e.preventDefault();
const formData = new FormData(e.target);
const specialties = formData.get(‘specialties’).split(‘,’).map(s => s.trim()).filter(s => s);

const newVendor = {
name: formData.get(‘vendorName’),
contact: formData.get(‘contactPerson’),
phone: formData.get(‘phoneNumber’),
email: formData.get(’emailAddress’),
specialties: specialties
};

vendors.push(newVendor);
e.target.reset();
loadAdminVendors();
alert(‘Vendor added successfully!’);
});
}

// Initialize the application
document.addEventListener(‘DOMContentLoaded’, function() {
// Initialize authentication UI
updateUIForAuthentication();

// Initialize dropdowns first
updateAllDropdowns();

updateDashboard();
setupSearch();
setupForms();

// Load initial data for first tab
loadMachines();

// Setup admin search functionality
document.getElementById(‘equipment-search-admin’).addEventListener(‘input’, loadAdminEquipment);
document.getElementById(‘equipment-filter-admin’).addEventListener(‘change’, loadAdminEquipment);
document.getElementById(‘supply-search-admin’).addEventListener(‘input’, loadAdminSupplies);
document.getElementById(‘supply-filter-admin’).addEventListener(‘change’, loadAdminSupplies);

// Setup login form
document.getElementById(‘login-form’).addEventListener(‘submit’, function(e) {
e.preventDefault();
const username = document.getElementById(‘username’).value;
const password = document.getElementById(‘password’).value;
login(username, password);
});

// Close login modal when clicking outside
document.getElementById(‘login-modal’).addEventListener(‘click’, function(e) {
if (e.target === this) {
closeLoginModal();
}
});
});