import React, { useState, useEffect, useMemo, useRef } from 'react';
import {
Upload, Download, FileSpreadsheet, Lock, User,
Search, CheckCircle2, XCircle, AlertCircle, Save,
FileJson, Shield, ShieldAlert
} from 'lucide-react';
// --- Utility Functions ---
// Custom CSV Parser to handle quotes and commas properly
function parseCSV(text) {
// Strip BOM if present
if (text.charCodeAt(0) === 0xFEFF) text = text.slice(1);
let p = '', row = [''], ret = [row], i = 0, r = 0, s = !0, l;
for (l of text) {
if ('"' === l) {
if (s && l === p) row[i] += l;
s = !s;
} else if (',' === l && s) l = row[++i] = '';
else if ('\n' === l && s) {
if ('\r' === p) row[i] = row[i].slice(0, -1);
row = ret[++r] = [l = '']; i = 0;
} else row[i] += l;
p = l;
}
// Clean up empty last rows
return ret.filter(r => r.length > 1 || r[0].trim() !== '');
}
export default function App() {
// --- State ---
const [authRole, setAuthRole] = useState('none'); // 'none', 'viewer', 'admin'
const [passwordInput, setPasswordInput] = useState('');
const [authError, setAuthError] = useState('');
const [masterData, setMasterData] = useState([]);
const [searchTerm, setSearchTerm] = useState('');
const [filterStatus, setFilterStatus] = useState('All');
const fileInputRef = useRef(null);
const importInputRef = useRef(null);
// --- Authentication ---
const handleLogin = (e) => {
e.preventDefault();
if (passwordInput === 'WC2026!') {
setAuthRole('admin');
setAuthError('');
} else if (passwordInput === 'Viewer2026!') {
setAuthRole('viewer');
setAuthError('');
} else {
setAuthError('Invalid password. Please try again.');
}
};
const handleLogout = () => {
setAuthRole('none');
setPasswordInput('');
setMasterData([]);
};
// --- Data Handling ---
const handleCSVUpload = (e) => {
const file = e.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = (event) => {
const csvText = event.target.result;
const rows = parseCSV(csvText);
if (rows.length < 2) {
alert('Invalid or empty CSV file.');
return;
}
const headers = rows[0].map(h => h.trim());
const deviceNameIdx = headers.indexOf('DeviceName');
if (deviceNameIdx === -1) {
alert('Could not find "DeviceName" column in CSV.');
return;
}
const newData = [];
for (let i = 1; i < rows.length; i++) {
const rowData = rows[i];
const record = {};
headers.forEach((h, index) => {
record[h] = rowData[index] ? rowData[index].trim() : '';
});
// Add manual tracking fields if they don't exist
record.ManualNotes = '';
record.AdminAction = '';
newData.push(record);
}
mergeData(newData);
};
reader.readAsText(file);
e.target.value = null; // Reset input
};
const mergeData = (newData) => {
setMasterData(prevData => {
const dataMap = new Map();
// Load existing into map to preserve manual fields
prevData.forEach(item => {
dataMap.set(item.DeviceName, item);
});
// Merge new data
newData.forEach(item => {
if (dataMap.has(item.DeviceName)) {
const existing = dataMap.get(item.DeviceName);
dataMap.set(item.DeviceName, {
...existing,
...item,
// Explicitly preserve manual fields over CSV blanks
ManualNotes: existing.ManualNotes || '',
AdminAction: existing.AdminAction || ''
});
} else {
dataMap.set(item.DeviceName, item);
}
});
return Array.from(dataMap.values());
});
};
const handleExportDB = () => {
const dataStr = JSON.stringify(masterData, null, 2);
const blob = new Blob([dataStr], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `Intune_MasterDB_${new Date().toISOString().split('T')[0]}.json`;
a.click();
URL.revokeObjectURL(url);
};
const handleImportDB = (e) => {
const file = e.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = (event) => {
try {
const data = JSON.parse(event.target.result);
if (Array.isArray(data)) {
setMasterData(data);
} else {
alert('Invalid JSON format.');
}
} catch (err) {
alert('Error parsing JSON database file.');
}
};
reader.readAsText(file);
e.target.value = null; // Reset input
};
const updateRecord = (deviceName, field, value) => {
setMasterData(prevData =>
prevData.map(item =>
item.DeviceName === deviceName ? { ...item, [field]: value } : item
)
);
};
// --- Computations & Filtering ---
const filteredData = useMemo(() => {
return masterData.filter(item => {
const matchesSearch =
(item.DeviceName || '').toLowerCase().includes(searchTerm.toLowerCase()) ||
(item.UserPrincipalName || '').toLowerCase().includes(searchTerm.toLowerCase());
const status = item.AppInstallState_loc || 'Unknown';
const matchesFilter = filterStatus === 'All' || status === filterStatus;
return matchesSearch && matchesFilter;
});
}, [masterData, searchTerm, filterStatus]);
const stats = useMemo(() => {
const s = { total: masterData.length, installed: 0, failed: 0, pending: 0 };
masterData.forEach(item => {
const state = item.AppInstallState_loc;
if (state === 'Installed') s.installed++;
else if (state === 'Failed') s.failed++;
else if (state === 'Install Pending') s.pending++;
});
return s;
}, [masterData]);
// --- Views ---
if (authRole === 'none') {
return (
Deployment Tracker
Please enter your access password.
GlobalProtect Intune Management Console
);
}
const isAdmin = authRole === 'admin';
return (
{/* Header */}
{/* Actions & Stats Row */}
{/* Action Card */}
{/* Stats Cards */}
Total Devices
{stats.total}
Installed Successfully
{stats.installed}
Installation Failed
{stats.failed}
{/* Toolbar */}
{/* Excel-like Table */}
);
}