import React, { useState, useEffect, useRef } from 'react'; import { CContainer, CRow, CCol, CCard, CCardBody, CCardHeader, CFormInput, CButton, CTable, CNavbar, CNavbarBrand, CNav, CNavItem, CForm, CBadge, CModal, CModalHeader, CModalTitle, CModalBody, CModalFooter, CFormSwitch, COffcanvas, COffcanvasHeader, COffcanvasTitle, COffcanvasBody, CCloseButton, CTooltip } from '@coreui/react'; // --- INLINE ICONS --- const IconEye = () => (); const IconEdit = () => (); const IconTrash = () => (); const IconDrag = () => (); function App() { const [userRole, setUserRole] = useState(null); const [theme, setTheme] = useState('light'); // Mobile & Sidebar State const [isMobile, setIsMobile] = useState(window.innerWidth < 768); const [sidebarVisible, setSidebarVisible] = useState(false); const [desktopSidebarVisible, setDesktopSidebarVisible] = useState(true); // System Alert Modal State const [alertModalVisible, setAlertModalVisible] = useState(false); const [alertModalTitle, setAlertModalTitle] = useState(''); const [alertModalMessage, setAlertModalMessage] = useState(''); // Login State const [username, setUsername] = useState(''); const [password, setPassword] = useState(''); // Admin User Management State const [users, setUsers] = useState([]); const [selectedAdminUserId, setSelectedAdminUserId] = useState(null); // Tracks the active user being edited const [newUsername, setNewUsername] = useState(''); const [newPassword, setNewPassword] = useState(''); const [newReportTitle, setNewReportTitle] = useState(''); const [newDesktopUrl, setNewDesktopUrl] = useState(''); const [newMobileUrl, setNewMobileUrl] = useState(''); // Derived active user for the admin dashboard panel const activeAdminUser = users.find(u => u.id === selectedAdminUserId) || null; // Admin Manage Reports State const [reportModalVisible, setReportModalVisible] = useState(false); const [reportModalMode, setReportModalMode] = useState('add'); const [activeUserForModal, setActiveUserForModal] = useState(null); const [activeReportId, setActiveReportId] = useState(null); const [modalReportTitle, setModalReportTitle] = useState(''); const [modalDesktopUrl, setModalDesktopUrl] = useState(''); const [modalMobileUrl, setModalMobileUrl] = useState(''); // Admin Reset Password State const [passwordModalVisible, setPasswordModalVisible] = useState(false); const [newPasswordInput, setNewPasswordInput] = useState(''); // Viewer State const [pages, setPages] = useState([]); const [selectedPage, setSelectedPage] = useState(null); // Force Refresh State & Ref const [refreshKey, setRefreshKey] = useState(0); const [lastRefresh, setLastRefresh] = useState(''); const lastAutoRefreshHour = useRef(null); // Drag and Drop Refs const dragItem = useRef(); const dragOverItem = useRef(); const dragUser = useRef(); useEffect(() => { document.documentElement.setAttribute('data-coreui-theme', theme); }, [theme]); useEffect(() => { const handleResize = () => setIsMobile(window.innerWidth < 768); window.addEventListener('resize', handleResize); return () => window.removeEventListener('resize', handleResize); }, []); // Ensures there is always a selected user in the admin panel if users exist useEffect(() => { if (userRole === 'admin' && users.length > 0) { if (!selectedAdminUserId || !users.find(u => u.id === selectedAdminUserId)) { setSelectedAdminUserId(users[0].id); } } }, [users, userRole, selectedAdminUserId]); useEffect(() => { if (selectedPage && userRole === 'user') { setLastRefresh(new Date().toLocaleTimeString()); setRefreshKey(prev => prev + 1); } }, [selectedPage, userRole]); useEffect(() => { const checkTimeInterval = setInterval(() => { if (!selectedPage || userRole !== 'user') return; const now = new Date(); const currentHour = now.getHours(); const currentMinute = now.getMinutes(); if (currentHour >= 7 && currentHour <= 15 && currentMinute === 5) { if (lastAutoRefreshHour.current !== currentHour) { setRefreshKey(prev => prev + 1); setLastRefresh(`Auto-update: ${now.toLocaleTimeString()}`); lastAutoRefreshHour.current = currentHour; } } }, 30000); return () => clearInterval(checkTimeInterval); }, [selectedPage, userRole]); const showSystemAlert = (title, message) => { setAlertModalTitle(title); setAlertModalMessage(message); setAlertModalVisible(true); }; useEffect(() => { let sessionTimer; if (userRole) { const EIGHT_HOURS = 8 * 60 * 60 * 1000; sessionTimer = setTimeout(() => { handleLogout(); showSystemAlert("Session Expired", "Your 8-hour session has automatically ended. Please log in again to continue viewing reports."); }, EIGHT_HOURS); } return () => clearTimeout(sessionTimer); }, [userRole]); const toggleTheme = () => setTheme(theme === 'light' ? 'dark' : 'light'); const handleManualRefresh = () => { setRefreshKey(prev => prev + 1); setLastRefresh(new Date().toLocaleTimeString()); }; const handleLogin = async (e) => { e.preventDefault(); const res = await fetch('/api/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, password }) }); if (res.ok) { const data = await res.json(); setUserRole(data.role); if (data.role === 'admin') fetchAdminUsers(); if (data.role === 'user') loadUserPages(); } else { showSystemAlert("Login Failed", "Invalid username or password. Please check your credentials and try again."); } }; const handleLogout = async () => { await fetch('/api/logout', { method: 'POST' }); setUserRole(null); setPages([]); setSelectedPage(null); setSelectedAdminUserId(null); }; const fetchAdminUsers = async () => { const res = await fetch('/api/admin/users'); if (res.status === 401 || res.status === 403) return handleLogout(); if (res.ok) { const data = await res.json(); setUsers(data); } }; const handleAddUser = async (e) => { e.preventDefault(); const initialPages = []; if (newReportTitle && newDesktopUrl) { initialPages.push({ id: 'rep_' + Date.now(), title: newReportTitle, desktopUrl: newDesktopUrl, mobileUrl: newMobileUrl }); } const newUser = { username: newUsername, password: newPassword, pages: initialPages }; const res = await fetch('/api/admin/users', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(newUser) }); if (res.status === 401 || res.status === 403) return handleLogout(); if (res.ok) { const createdUser = await res.json(); fetchAdminUsers(); setSelectedAdminUserId(createdUser.id); // Auto-select the newly created user setNewUsername(''); setNewPassword(''); setNewReportTitle(''); setNewDesktopUrl(''); setNewMobileUrl(''); } }; const handleDeleteUser = async (id) => { const res = await fetch(`/api/admin/users/${id}`, { method: 'DELETE' }); if (res.status === 401 || res.status === 403) return handleLogout(); fetchAdminUsers(); // This will auto-select the next available user via the useEffect }; const openReportModal = (mode, user, report = null) => { setReportModalMode(mode); setActiveUserForModal(user); if (mode === 'edit' && report) { setActiveReportId(report.id); setModalReportTitle(report.title); setModalDesktopUrl(report.desktopUrl || report.url || ''); setModalMobileUrl(report.mobileUrl || ''); } else { setActiveReportId(null); setModalReportTitle(''); setModalDesktopUrl(''); setModalMobileUrl(''); } setReportModalVisible(true); }; const handleSaveReport = async () => { try { const currentUser = users.find(u => u.id === activeUserForModal.id); if (!currentUser) return showSystemAlert("Error", "User record not found in active state."); let updatedPages = [...currentUser.pages]; if (reportModalMode === 'add') { updatedPages.push({ id: 'rep_' + Date.now(), title: modalReportTitle, desktopUrl: modalDesktopUrl, mobileUrl: modalMobileUrl }); } else if (reportModalMode === 'edit') { updatedPages = updatedPages.map(p => p.id === activeReportId ? { ...p, title: modalReportTitle, desktopUrl: modalDesktopUrl, mobileUrl: modalMobileUrl } : p ); } const res = await fetch(`/api/admin/users/${currentUser.id}/pages`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ pages: updatedPages }) }); if (res.status === 401 || res.status === 403) return handleLogout(); if (res.ok) { setReportModalVisible(false); fetchAdminUsers(); } else { showSystemAlert("Save Failed", "The server failed to save the report updates."); } } catch (error) { showSystemAlert("Error", "An unexpected error occurred during save."); } }; const handleDeleteReport = async (user, reportId) => { const updatedPages = user.pages.filter(p => p.id !== reportId); const res = await fetch(`/api/admin/users/${user.id}/pages`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ pages: updatedPages }) }); if (res.status === 401 || res.status === 403) return handleLogout(); fetchAdminUsers(); }; const openPasswordModal = (user) => { setActiveUserForModal(user); setNewPasswordInput(''); setPasswordModalVisible(true); }; const handleSavePassword = async () => { const res = await fetch(`/api/admin/users/${activeUserForModal.id}/password`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ password: newPasswordInput }) }); if (res.status === 401 || res.status === 403) return handleLogout(); if (res.ok) { setPasswordModalVisible(false); fetchAdminUsers(); } }; const loadUserPages = async () => { const res = await fetch('/api/user/pages'); if (res.status === 401 || res.status === 403) return handleLogout(); if (res.ok) { const data = await res.json(); setPages(data); if(data.length > 0) setSelectedPage(data[0]); } }; // --- DRAG AND DROP HANDLERS --- const handleDragStart = (e, userId, index) => { dragItem.current = index; dragUser.current = userId; e.dataTransfer.effectAllowed = 'move'; setTimeout(() => e.target.style.opacity = '0.5', 0); }; const handleDragEnter = (e, userId, index) => { if (dragUser.current !== userId) return; dragOverItem.current = index; }; const handleDragEnd = async (e, userId) => { e.target.style.opacity = '1'; if (dragUser.current !== userId || dragItem.current === null || dragOverItem.current === null) return; if (dragItem.current === dragOverItem.current) return; const currentUser = users.find(u => u.id === userId); if (!currentUser) return; const newPages = [...currentUser.pages]; const draggedItemContent = newPages[dragItem.current]; newPages.splice(dragItem.current, 1); newPages.splice(dragOverItem.current, 0, draggedItemContent); // Optimistic UI Update ensures no visual lag setUsers(users.map(u => u.id === userId ? { ...u, pages: newPages } : u)); const res = await fetch(`/api/admin/users/${userId}/pages`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ pages: newPages }) }); if (res.status === 401 || res.status === 403) return handleLogout(); dragItem.current = null; dragOverItem.current = null; dragUser.current = null; }; // --- DYNAMIC OVERLAY STYLES --- const overlayStyleLeft = { position: 'absolute', bottom: 0, left: 0, width: '140px', height: isMobile ? '30px' : '34px', backgroundColor: '#eaeaea', zIndex: 10 }; const overlayStyleRight = { position: 'absolute', bottom: 0, right: 0, width: isMobile ? '30px' : '190px', height: isMobile ? '30px' : '34px', backgroundColor: '#eaeaea', zIndex: 10 }; const getActiveUrl = (page) => { if (!page) return ''; if (isMobile && page.mobileUrl) return page.mobileUrl; return page.desktopUrl || page.url; }; const renderAlertModal = () => ( setAlertModalVisible(false)}> setAlertModalVisible(false)}> {alertModalTitle} {alertModalMessage} setAlertModalVisible(false)}>OK ); if (!userRole) { return ( {renderAlertModal()}

Power BI LOGIN

setUsername(e.target.value)} required /> setPassword(e.target.value)} required /> Log In
); } return (
{renderAlertModal()} {userRole === 'user' && ( isMobile ? setSidebarVisible(true) : setDesktopSidebarVisible(!desktopSidebarVisible)} > )} {userRole === 'admin' ? 'Administration Dashboard' : 'BI Viewer'} Logout {/* --- ADMIN VIEW (REFACTORED TO MASTER-DETAIL LAYOUT) --- */} {userRole === 'admin' && ( {/* LEFT COLUMN: Create User & User List */} Create New User setNewUsername(e.target.value)} required /> setNewPassword(e.target.value)} required />
Optional: Assign initial report
setNewReportTitle(e.target.value)} /> setNewDesktopUrl(e.target.value)} /> setNewMobileUrl(e.target.value)} /> Create User
Managed Users {users.length === 0 &&

No users created yet.

} {users.map(u => ( setSelectedAdminUserId(u.id)} > {u.username} {u.pages.length} {u.pages.length === 1 ? 'Report' : 'Reports'} ))}
{/* RIGHT COLUMN: Active User Details & Previews */} {activeAdminUser ? (
User: {activeAdminUser.username}
openPasswordModal(activeAdminUser)}>Reset Pw handleDeleteUser(activeAdminUser.id)}>Delete User
Current Password: {activeAdminUser.password}
Assigned Reports
{activeAdminUser.pages.length === 0 &&

This user currently has no reports assigned.

} {activeAdminUser.pages.map((p, index) => (
handleDragStart(e, activeAdminUser.id, index)} onDragEnter={(e) => handleDragEnter(e, activeAdminUser.id, index)} onDragEnd={(e) => handleDragEnd(e, activeAdminUser.id)} onDragOver={(e) => e.preventDefault()} style={{ cursor: 'grab', transition: 'opacity 0.2s' }} >
{p.title}
openReportModal('edit', activeAdminUser, p)}> handleDeleteReport(activeAdminUser, p.id)}>
Desktop: {p.desktopUrl || p.url || 'None'} {(p.desktopUrl || p.url) && ( setSelectedPage({ ...p, previewMode: 'desktop' })}> )}
Mobile: {p.mobileUrl || 'None'} {p.mobileUrl && ( setSelectedPage({ ...p, previewMode: 'mobile' })}> )}
))} openReportModal('add', activeAdminUser)}> + Add New Report
) : ( Select a user from the left panel to manage their reports and settings. )} {selectedPage && ( Preview: {selectedPage.title} ({selectedPage.previewMode === 'mobile' ? 'Mobile View' : 'Desktop View'}) setSelectedPage(null)}>Close
)}
setReportModalVisible(false)}> {reportModalMode === 'add' ? `Add Report for ${activeAdminUser?.username}` : `Edit Report`} setModalReportTitle(e.target.value)} /> setModalDesktopUrl(e.target.value)} /> setModalMobileUrl(e.target.value)} /> setReportModalVisible(false)}>Cancel Save setPasswordModalVisible(false)}> Reset Password for {activeUserForModal?.username} setNewPasswordInput(e.target.value)} required /> setPasswordModalVisible(false)}>Cancel Save Password
)} {/* --- USER VIEW --- */} {userRole === 'user' && (
{desktopSidebarVisible && (
{pages.length === 0 &&

No reports assigned.

} {pages.map(page => ( setSelectedPage(page)} > {page.title} ))}
)} setSidebarVisible(false)}> Select Report setSidebarVisible(false)} /> {pages.map(page => ( { setSelectedPage(page); setSidebarVisible(false); }} > {page.title} ))}
{selectedPage ? ( <>
{selectedPage.title}
Last reload: {lastRefresh} ↻ Refresh
) : (
Select a report from the menu to begin viewing.
)}
)}
); } export default App;