Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Data Visualization AI</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> | |
| <script src="https://unpkg.com/feather-icons"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script> | |
| <link href="https://unpkg.com/aos@2.3.1/dist/aos.css" rel="stylesheet"> | |
| <script src="https://unpkg.com/aos@2.3.1/dist/aos.js"></script> | |
| <style> | |
| .dropzone { | |
| border: 2px dashed #3b82f6; | |
| border-radius: 0.5rem; | |
| transition: all 0.3s ease; | |
| } | |
| .dropzone:hover { | |
| background-color: #eff6ff; | |
| } | |
| .dropzone.active { | |
| border-color: #10b981; | |
| background-color: #ecfdf5; | |
| } | |
| .chart-container { | |
| transition: all 0.3s ease; | |
| } | |
| .chart-container:hover { | |
| transform: translateY(-5px); | |
| box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1); | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-gray-50 min-h-screen flex flex-col"> | |
| <header id="header" class="bg-white shadow-sm"> | |
| <div class="container mx-auto px-4 py-4 flex justify-between items-center"> | |
| <div id="branding" class="flex items-center space-x-2"> | |
| <img id="companyLogo" src="https://huggingface.co/spaces/Cg16/cg-data-analytics/resolve/main/images/syf3.png" alt="Company Logo" class="h-10 w-10 rounded-full"> | |
| <h1 id="reportHeader" class="text-xl font-bold text-gray-800">Data Visualization Dashboard</h1> | |
| </div> | |
| <div id="headerControls" class="hidden space-x-4"> | |
| <div id="editControls" class="flex space-x-4"> | |
| <button id="uploadLogoBtn" class="text-blue-600 hover:text-blue-800 flex items-center"> | |
| <i data-feather="image" class="mr-1"></i> Upload Logo | |
| </button> | |
| <button id="editHeaderBtn" class="text-blue-600 hover:text-blue-800 flex items-center"> | |
| <i data-feather="edit" class="mr-1"></i> Edit Header | |
| </button> | |
| </div> | |
| <button id="doneEditingBtn" class="bg-green-500 hover:bg-green-600 text-white px-3 py-1 rounded-md text-sm hidden"> | |
| <i data-feather="check" class="mr-1"></i> Done | |
| </button> | |
| <button id="shareReportBtn" class="text-blue-600 hover:text-blue-800 flex items-center"> | |
| <i data-feather="share-2" class="mr-1"></i> Share Report | |
| </button> | |
| </div> | |
| </div> | |
| </header> | |
| <main class="flex-grow container mx-auto px-4 py-8"> | |
| <section class="mb-12" data-aos="fade-up"> | |
| <div class="text-center mb-8"> | |
| <h2 class="text-3xl font-bold text-gray-800 mb-2">AI-Powered Data Visualization</h2> | |
| <p class="text-gray-600 max-w-2xl mx-auto">Upload your Excel, CSV files or paste a file URL to generate dynamic visualizations with AI analysis</p> | |
| </div> | |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-6"> | |
| <div class="dropzone p-8 text-center cursor-pointer" id="dropzone"> | |
| <div class="flex flex-col items-center justify-center h-full"> | |
| <i data-feather="upload" class="w-12 h-12 text-blue-500 mb-4"></i> | |
| <h3 class="text-lg font-medium text-gray-700 mb-2">Drag & Drop Files Here</h3> | |
| <p class="text-gray-500 mb-4">or</p> | |
| <label for="fileInput" class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-md cursor-pointer transition"> | |
| Select Files | |
| </label> | |
| <input type="file" id="fileInput" class="hidden" accept=".csv, .xlsx, .xls"> | |
| </div> | |
| </div> | |
| <div class="bg-white p-6 rounded-lg shadow-sm border border-gray-200"> | |
| <h3 class="text-lg font-medium text-gray-700 mb-4">Or paste a file URL</h3> | |
| <div class="flex space-x-2"> | |
| <input type="url" id="fileUrl" placeholder="https://example.com/data.csv" class="flex-grow px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"> | |
| <button id="fetchUrlBtn" class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-md transition"> | |
| <i data-feather="download" class="w-4 h-4"></i> | |
| </button> | |
| </div> | |
| <div class="mt-4"> | |
| <p class="text-sm text-gray-500">Supported formats: CSV, Excel (.xlsx, .xls)</p> | |
| </div> | |
| </div> | |
| </div> | |
| </section> | |
| <section id="visualizationSection" class="hidden" data-aos="fade-up"> | |
| <div class="flex justify-between items-center mb-6"> | |
| <h2 class="text-2xl font-bold text-gray-800">AI-Generated Visualizations</h2> | |
| <div id="chartControls" class="hidden space-x-2"> | |
| <button id="editChartTitlesBtn" class="text-blue-600 hover:text-blue-800 flex items-center"> | |
| <i data-feather="edit-2" class="mr-1"></i> Edit Titles | |
| </button> | |
| </div> | |
| </div> | |
| <div id="chartContainer" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"> | |
| <!-- Charts will be dynamically inserted here --> | |
| </div> | |
| <div id="aiInsights" class="mt-12 bg-white p-6 rounded-lg shadow-sm border border-gray-200"> | |
| <h3 class="text-xl font-medium text-gray-700 mb-4 flex items-center"> | |
| <i data-feather="zap" class="text-yellow-500 mr-2"></i> AI Analysis | |
| </h3> | |
| <div id="insightsContent" class="text-gray-600"> | |
| <!-- AI insights will be dynamically inserted here --> | |
| </div> | |
| </div> | |
| </section> | |
| </main> | |
| <footer class="bg-gray-100 py-6"> | |
| <div class="container mx-auto px-4 text-center"> | |
| <p class="text-gray-600"> | |
| <a href="#" id="footerLink" class="hover:text-blue-600 transition">Created by CG. All rights reserved</a><br> | |
| <span class="text-xs text-gray-500">For internal use only. Uses company security policies.</span> | |
| </p> | |
| </div> | |
| </footer> | |
| <!-- Modals --> | |
| <div id="pinModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden z-50"> | |
| <div class="bg-white p-6 rounded-lg shadow-xl max-w-sm w-full"> | |
| <h3 class="text-xl font-bold text-gray-800 mb-4">Enter Credentials</h3> | |
| <input type="password" id="pinInput" placeholder="Enter PIN" class="w-full px-4 py-2 border border-gray-300 rounded-md mb-2 focus:outline-none focus:ring-2 focus:ring-blue-500"> | |
| <input type="text" id="usernameInput" placeholder="Enter Username (except Super Admin)" class="w-full px-4 py-2 border border-gray-300 rounded-md mb-4 focus:outline-none focus:ring-2 focus:ring-blue-500 hidden"> | |
| <div class="flex justify-end space-x-3"> | |
| <button id="cancelPinBtn" class="px-4 py-2 border border-gray-300 rounded-md hover:bg-gray-100">Cancel</button> | |
| <button id="submitPinBtn" class="px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600">Submit</button> | |
| </div> | |
| </div> | |
| </div> | |
| <div id="logoModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden z-50"> | |
| <div class="bg-white p-6 rounded-lg shadow-xl max-w-sm w-full"> | |
| <h3 class="text-xl font-bold text-gray-800 mb-4">Upload Company Logo</h3> | |
| <input type="file" id="logoUpload" accept="image/*" class="w-full mb-4"> | |
| <div class="flex justify-end space-x-3"> | |
| <button id="cancelLogoBtn" class="px-4 py-2 border border-gray-300 rounded-md hover:bg-gray-100">Cancel</button> | |
| <button id="saveLogoBtn" class="px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600">Save</button> | |
| </div> | |
| </div> | |
| </div> | |
| <div id="headerModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden z-50"> | |
| <div class="bg-white p-6 rounded-lg shadow-xl max-w-sm w-full"> | |
| <h3 class="text-xl font-bold text-gray-800 mb-4">Edit Report Header</h3> | |
| <input type="text" id="headerInput" placeholder="Enter new header" class="w-full px-4 py-2 border border-gray-300 rounded-md mb-4 focus:outline-none focus:ring-2 focus:ring-blue-500"> | |
| <div class="flex justify-end space-x-3"> | |
| <button id="cancelHeaderBtn" class="px-4 py-2 border border-gray-300 rounded-md hover:bg-gray-100">Cancel</button> | |
| <button id="saveHeaderBtn" class="px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600">Save</button> | |
| </div> | |
| </div> | |
| </div> | |
| <div id="doneBtnContainer" class="text-center mt-8 hidden"> | |
| <button id="doneBtn" class="bg-green-500 hover:bg-green-600 text-white px-6 py-3 rounded-md transition flex items-center mx-auto"> | |
| <i data-feather="check-circle" class="mr-2"></i> Done | |
| </button> | |
| </div> | |
| <div id="shareModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden z-50"> | |
| <div class="bg-white p-6 rounded-lg shadow-xl max-w-md w-full"> | |
| <h3 class="text-xl font-bold text-gray-800 mb-4">Share Report</h3> | |
| <p class="text-gray-600 mb-4">Share this link for view-only access:</p> | |
| <div class="flex items-center mb-4"> | |
| <input type="text" id="shareLink" readonly class="flex-grow px-4 py-2 border border-gray-300 rounded-l-md focus:outline-none"> | |
| <button id="copyLinkBtn" class="bg-blue-500 text-white px-4 py-2 rounded-r-md hover:bg-blue-600"> | |
| <i data-feather="copy"></i> | |
| </button> | |
| </div> | |
| <div class="flex justify-end"> | |
| <button id="closeShareBtn" class="px-4 py-2 bg-gray-500 text-white rounded-md hover:bg-gray-600">Close</button> | |
| </div> | |
| </div> | |
| </div> | |
| <div id="chartTitleModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden z-50"> | |
| <div class="bg-white p-6 rounded-lg shadow-xl max-w-sm w-full"> | |
| <h3 class="text-xl font-bold text-gray-800 mb-4">Edit Chart Title</h3> | |
| <input type="text" id="chartTitleInput" placeholder="Enter new title" class="w-full px-4 py-2 border border-gray-300 rounded-md mb-4 focus:outline-none focus:ring-2 focus:ring-blue-500"> | |
| <div class="flex justify-end space-x-3"> | |
| <button id="cancelTitleBtn" class="px-4 py-2 border border-gray-300 rounded-md hover:bg-gray-100">Cancel</button> | |
| <button id="saveTitleBtn" class="px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600">Save</button> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| // User management modal | |
| const userManagementModal = ` | |
| <div id="userManagementModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden z-50"> | |
| <div class="bg-white p-6 rounded-lg shadow-xl max-w-md w-full"> | |
| <h3 class="text-xl font-bold text-gray-800 mb-4">User Management</h3> | |
| <div class="mb-4 max-h-60 overflow-y-auto"> | |
| <table class="w-full text-sm"> | |
| <thead> | |
| <tr class="border-b"> | |
| <th class="text-left py-2">Username</th> | |
| <th class="text-left py-2">PIN</th> | |
| <th class="text-left py-2">Actions</th> | |
| </tr> | |
| </thead> | |
| <tbody id="userList"> | |
| <!-- Users will be populated here --> | |
| </tbody> | |
| </table> | |
| </div> | |
| <div class="flex space-x-2 mb-4"> | |
| <input type="text" id="newUsername" placeholder="New Username" class="flex-1 px-3 py-2 border rounded"> | |
| <input type="text" id="newPin" placeholder="New PIN" class="w-24 px-3 py-2 border rounded"> | |
| <button id="addUserBtn" class="bg-blue-500 text-white px-3 py-2 rounded">Add</button> | |
| </div> | |
| <div class="flex justify-end space-x-3"> | |
| <button id="closeUserModalBtn" class="px-4 py-2 border border-gray-300 rounded-md hover:bg-gray-100">Close</button> | |
| </div> | |
| </div> | |
| </div> | |
| `; | |
| document.body.insertAdjacentHTML('beforeend', userManagementModal); | |
| document.addEventListener('DOMContentLoaded', function() { | |
| feather.replace(); | |
| AOS.init(); | |
| // Sample data for demonstration | |
| const sampleData = { | |
| labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'], | |
| datasets: [{ | |
| label: 'Sales', | |
| data: [65, 59, 80, 81, 56, 55], | |
| backgroundColor: 'rgba(59, 130, 246, 0.2)', | |
| borderColor: 'rgba(59, 130, 246, 1)', | |
| borderWidth: 1 | |
| }] | |
| }; | |
| const aiInsights = [ | |
| "The data shows a peak in sales during March and April, suggesting a seasonal trend.", | |
| "February had the lowest sales, which might indicate a need for promotional activities during this period.", | |
| "Overall, the first half of the year shows positive growth compared to previous years." | |
| ]; | |
| // Dropzone functionality | |
| const dropzone = document.getElementById('dropzone'); | |
| const fileInput = document.getElementById('fileInput'); | |
| const fileUrl = document.getElementById('fileUrl'); | |
| const fetchUrlBtn = document.getElementById('fetchUrlBtn'); | |
| const visualizationSection = document.getElementById('visualizationSection'); | |
| const chartContainer = document.getElementById('chartContainer'); | |
| const insightsContent = document.getElementById('insightsContent'); | |
| ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => { | |
| dropzone.addEventListener(eventName, preventDefaults, false); | |
| }); | |
| function preventDefaults(e) { | |
| e.preventDefault(); | |
| e.stopPropagation(); | |
| } | |
| ['dragenter', 'dragover'].forEach(eventName => { | |
| dropzone.addEventListener(eventName, highlight, false); | |
| }); | |
| ['dragleave', 'drop'].forEach(eventName => { | |
| dropzone.addEventListener(eventName, unhighlight, false); | |
| }); | |
| function highlight() { | |
| dropzone.classList.add('active'); | |
| } | |
| function unhighlight() { | |
| dropzone.classList.remove('active'); | |
| } | |
| dropzone.addEventListener('drop', handleDrop, false); | |
| fileInput.addEventListener('change', handleFiles, false); | |
| fetchUrlBtn.addEventListener('click', handleUrlFetch); | |
| function handleDrop(e) { | |
| const dt = e.dataTransfer; | |
| const files = dt.files; | |
| handleFiles({ target: { files } }); | |
| } | |
| function handleFiles(e) { | |
| const files = e.target.files; | |
| if (files.length) { | |
| processFiles(files); | |
| } | |
| } | |
| function handleUrlFetch() { | |
| const url = fileUrl.value.trim(); | |
| if (url) { | |
| // In a real app, you would fetch the file from the URL | |
| // For demo purposes, we'll just simulate processing | |
| setTimeout(() => { | |
| processFiles([{ name: url.split('/').pop() }]); | |
| }, 1000); | |
| } | |
| } | |
| function processFiles(files) { | |
| // Show loading state | |
| dropzone.innerHTML = '<div class="flex flex-col items-center justify-center h-full"><i data-feather="loader" class="animate-spin w-12 h-12 text-blue-500 mb-4"></i><p class="text-gray-700">Processing file...</p></div>'; | |
| feather.replace(); | |
| // Simulate file processing and AI analysis | |
| setTimeout(() => { | |
| generateVisualizations(); | |
| showAIInsights(); | |
| visualizationSection.classList.remove('hidden'); | |
| document.getElementById('doneBtnContainer').classList.remove('hidden'); | |
| feather.replace(); | |
| }, 1500); | |
| } | |
| // Done button functionality | |
| document.getElementById('doneBtn').addEventListener('click', function() { | |
| alert('Your report has been processed successfully!'); | |
| }); | |
| // Share functionality | |
| const shareReportBtn = document.getElementById('shareReportBtn'); | |
| const shareModal = document.getElementById('shareModal'); | |
| const shareLink = document.getElementById('shareLink'); | |
| const copyLinkBtn = document.getElementById('copyLinkBtn'); | |
| const closeShareBtn = document.getElementById('closeShareBtn'); | |
| shareReportBtn.addEventListener('click', function() { | |
| // Check if viewer needs approval | |
| if (window.location.search.includes('view=true')) { | |
| alert('This report requires approval from the creator to share further.'); | |
| return; | |
| } | |
| // Generate unique URL | |
| const reportId = Math.random().toString(36).substring(2, 8); | |
| shareLink.value = window.location.href.split('?')[0] + `?view=true&report=${reportId}`; | |
| shareModal.classList.remove('hidden'); | |
| // Show download prompt for first-time viewers | |
| if (!localStorage.getItem('downloadedApp')) { | |
| setTimeout(() => { | |
| if (confirm('Download the HTML App shortcut to your desktop?')) { | |
| const blob = new Blob([document.documentElement.outerHTML], {type: 'text/html'}); | |
| const url = URL.createObjectURL(blob); | |
| const a = document.createElement('a'); | |
| a.href = url; | |
| a.download = 'Data_Visualization_App.html'; | |
| document.body.appendChild(a); | |
| a.click(); | |
| document.body.removeChild(a); | |
| URL.revokeObjectURL(url); | |
| localStorage.setItem('downloadedApp', 'true'); | |
| } | |
| }, 1000); | |
| } | |
| }); | |
| copyLinkBtn.addEventListener('click', function() { | |
| shareLink.select(); | |
| document.execCommand('copy'); | |
| feather.replace(); | |
| alert('Link copied to clipboard!'); | |
| }); | |
| closeShareBtn.addEventListener('click', function() { | |
| shareModal.classList.add('hidden'); | |
| }); | |
| // Check for view-only mode | |
| if (window.location.search.includes('view=true')) { | |
| document.getElementById('headerControls').classList.add('hidden'); | |
| document.getElementById('chartControls').classList.add('hidden'); | |
| document.getElementById('dropzone').classList.add('hidden'); | |
| document.getElementById('fileInput').classList.add('hidden'); | |
| document.querySelector('input[type="url"]').parentElement.classList.add('hidden'); | |
| document.getElementById('doneBtnContainer').classList.add('hidden'); | |
| } | |
| function generateVisualizations() { | |
| // Clear previous charts | |
| chartContainer.innerHTML = ''; | |
| // Generate sample charts (in a real app, this would be dynamic based on the data) | |
| const chartTypes = ['bar', 'line', 'pie', 'doughnut', 'radar', 'polarArea']; | |
| chartTypes.forEach((type, index) => { | |
| const chartCard = document.createElement('div'); | |
| chartCard.className = 'chart-container bg-white p-4 rounded-lg shadow-sm border border-gray-200'; | |
| chartCard.innerHTML = ` | |
| <div class="flex justify-between items-center mb-3"> | |
| <h3 class="font-medium text-gray-700 chart-title">${type.charAt(0).toUpperCase() + type.slice(1)} Chart</h3> | |
| <i data-feather="chevron-right" class="text-gray-400"></i> | |
| </div> | |
| <div class="h-64"> | |
| <canvas id="chart-${index}"></canvas> | |
| </div> | |
| `; | |
| chartContainer.appendChild(chartCard); | |
| // Initialize chart | |
| const ctx = document.getElementById(`chart-${index}`).getContext('2d'); | |
| new Chart(ctx, { | |
| type: type, | |
| data: sampleData, | |
| options: { | |
| responsive: true, | |
| maintainAspectRatio: false, | |
| plugins: { | |
| legend: { | |
| position: 'bottom' | |
| } | |
| } | |
| } | |
| }); | |
| }); | |
| feather.replace(); | |
| } | |
| function showAIInsights() { | |
| insightsContent.innerHTML = ''; | |
| aiInsights.forEach(insight => { | |
| const insightItem = document.createElement('p'); | |
| insightItem.className = 'mb-3 pl-4 border-l-4 border-blue-500'; | |
| insightItem.textContent = insight; | |
| insightsContent.appendChild(insightItem); | |
| }); | |
| } | |
| // User management functionality | |
| const userManagementBtn = document.createElement('button'); | |
| userManagementBtn.id = 'userManagementBtn'; | |
| userManagementBtn.className = 'text-blue-600 hover:text-blue-800 flex items-center hidden'; | |
| userManagementBtn.innerHTML = '<i data-feather="users" class="mr-1"></i> Manage Users'; | |
| document.getElementById('headerControls').prepend(userManagementBtn); | |
| userManagementBtn.addEventListener('click', function() { | |
| document.getElementById('userManagementModal').classList.remove('hidden'); | |
| // Populate user list | |
| const userList = document.getElementById('userList'); | |
| userList.innerHTML = ` | |
| <tr> | |
| <td class="py-2">Celine</td> | |
| <td class="py-2">1111</td> | |
| <td class="py-2"><i data-feather="trash-2" class="text-red-500 cursor-pointer"></i></td> | |
| </tr> | |
| <tr> | |
| <td class="py-2">Jason</td> | |
| <td class="py-2">C-1111</td> | |
| <td class="py-2"><i data-feather="trash-2" class="text-red-500 cursor-pointer"></i></td> | |
| </tr> | |
| <tr> | |
| <td class="py-2">Chris</td> | |
| <td class="py-2">C-2222</td> | |
| <td class="py-2"><i data-feather="trash-2" class="text-red-500 cursor-pointer"></i></td> | |
| </tr> | |
| <tr> | |
| <td class="py-2">MNL1</td> | |
| <td class="py-2">M-1111</td> | |
| <td class="py-2"><i data-feather="trash-2" class="text-red-500 cursor-pointer"></i></td> | |
| </tr> | |
| <tr> | |
| <td class="py-2">MNL2</td> | |
| <td class="py-2">M-2222</td> | |
| <td class="py-2"><i data-feather="trash-2" class="text-red-500 cursor-pointer"></i></td> | |
| </tr> | |
| <tr> | |
| <td class="py-2">CEB3</td> | |
| <td class="py-2">C-3333</td> | |
| <td class="py-2"><i data-feather="trash-2" class="text-red-500 cursor-pointer"></i></td> | |
| </tr> | |
| `; | |
| feather.replace(); | |
| }); | |
| document.getElementById('closeUserModalBtn').addEventListener('click', function() { | |
| document.getElementById('userManagementModal').classList.add('hidden'); | |
| }); | |
| // Admin functionality | |
| const footerLink = document.getElementById('footerLink'); | |
| const pinModal = document.getElementById('pinModal'); | |
| const pinInput = document.getElementById('pinInput'); | |
| const submitPinBtn = document.getElementById('submitPinBtn'); | |
| const cancelPinBtn = document.getElementById('cancelPinBtn'); | |
| const headerControls = document.getElementById('headerControls'); | |
| const chartControls = document.getElementById('chartControls'); | |
| footerLink.addEventListener('click', function(e) { | |
| e.preventDefault(); | |
| pinModal.classList.remove('hidden'); | |
| document.getElementById('usernameInput').classList.remove('hidden'); | |
| if (pinInput.value === '1123') { | |
| document.getElementById('usernameInput').classList.add('hidden'); | |
| } | |
| }); | |
| cancelPinBtn.addEventListener('click', function() { | |
| pinModal.classList.add('hidden'); | |
| pinInput.value = ''; | |
| }); | |
| submitPinBtn.addEventListener('click', function() { | |
| const pin = pinInput.value; | |
| const username = document.getElementById('usernameInput').value; | |
| // Super Admin | |
| if (pin === '1123') { | |
| headerControls.classList.remove('hidden'); | |
| document.getElementById('editControls').classList.remove('hidden'); | |
| document.getElementById('doneEditingBtn').classList.remove('hidden'); | |
| chartControls.classList.remove('hidden'); | |
| pinModal.classList.add('hidden'); | |
| pinInput.value = ''; | |
| document.getElementById('usernameInput').classList.add('hidden'); | |
| } | |
| // Admin | |
| else if (pin === '1111' && username === 'Celine') { | |
| headerControls.classList.remove('hidden'); | |
| document.getElementById('editControls').classList.remove('hidden'); | |
| document.getElementById('doneEditingBtn').classList.remove('hidden'); | |
| chartControls.classList.remove('hidden'); | |
| pinModal.classList.add('hidden'); | |
| pinInput.value = ''; | |
| document.getElementById('usernameInput').value = ''; | |
| } | |
| // Regular Users | |
| else if ( | |
| (pin === 'C-1111' && username === 'Jason') || | |
| (pin === 'C-2222' && username === 'Chris') || | |
| (pin === 'M-1111' && username === 'MNL1') || | |
| (pin === 'M-2222' && username === 'MNL2') || | |
| (pin === 'C-3333' && username === 'CEB3') | |
| ) { | |
| headerControls.classList.remove('hidden'); | |
| document.getElementById('uploadLogoBtn').classList.add('hidden'); | |
| document.getElementById('editHeaderBtn').classList.add('hidden'); | |
| document.getElementById('doneEditingBtn').classList.add('hidden'); | |
| chartControls.classList.remove('hidden'); | |
| pinModal.classList.add('hidden'); | |
| pinInput.value = ''; | |
| document.getElementById('usernameInput').value = ''; | |
| } else { | |
| alert('Incorrect PIN or Username'); | |
| } | |
| }); | |
| // Show user management button only for super admin | |
| if (pin === '1123') { | |
| document.getElementById('userManagementBtn').classList.remove('hidden'); | |
| } | |
| // Logo upload | |
| const uploadLogoBtn = document.getElementById('uploadLogoBtn'); | |
| const logoModal = document.getElementById('logoModal'); | |
| const logoUpload = document.getElementById('logoUpload'); | |
| const saveLogoBtn = document.getElementById('saveLogoBtn'); | |
| const cancelLogoBtn = document.getElementById('cancelLogoBtn'); | |
| const companyLogo = document.getElementById('companyLogo'); | |
| uploadLogoBtn.addEventListener('click', function() { | |
| logoModal.classList.remove('hidden'); | |
| }); | |
| cancelLogoBtn.addEventListener('click', function() { | |
| logoModal.classList.add('hidden'); | |
| logoUpload.value = ''; | |
| }); | |
| saveLogoBtn.addEventListener('click', function() { | |
| if (logoUpload.files.length) { | |
| const file = logoUpload.files[0]; | |
| const reader = new FileReader(); | |
| reader.onload = function(e) { | |
| companyLogo.src = e.target.result; | |
| }; | |
| reader.readAsDataURL(file); | |
| logoModal.classList.add('hidden'); | |
| } | |
| }); | |
| // Header edit | |
| const editHeaderBtn = document.getElementById('editHeaderBtn'); | |
| const headerModal = document.getElementById('headerModal'); | |
| const headerInput = document.getElementById('headerInput'); | |
| const saveHeaderBtn = document.getElementById('saveHeaderBtn'); | |
| const cancelHeaderBtn = document.getElementById('cancelHeaderBtn'); | |
| const reportHeader = document.getElementById('reportHeader'); | |
| editHeaderBtn.addEventListener('click', function() { | |
| headerInput.value = reportHeader.textContent; | |
| headerModal.classList.remove('hidden'); | |
| }); | |
| cancelHeaderBtn.addEventListener('click', function() { | |
| headerModal.classList.add('hidden'); | |
| }); | |
| saveHeaderBtn.addEventListener('click', function() { | |
| reportHeader.textContent = headerInput.value; | |
| headerModal.classList.add('hidden'); | |
| }); | |
| // Chart title edit | |
| const editChartTitlesBtn = document.getElementById('editChartTitlesBtn'); | |
| const chartTitleModal = document.getElementById('chartTitleModal'); | |
| const chartTitleInput = document.getElementById('chartTitleInput'); | |
| const saveTitleBtn = document.getElementById('saveTitleBtn'); | |
| const cancelTitleBtn = document.getElementById('cancelTitleBtn'); | |
| let currentChartTitle = null; | |
| editChartTitlesBtn.addEventListener('click', function() { | |
| const chartTitles = document.querySelectorAll('.chart-title'); | |
| chartTitles.forEach(title => { | |
| title.style.cursor = 'pointer'; | |
| title.addEventListener('click', function() { | |
| currentChartTitle = this; | |
| chartTitleInput.value = this.textContent; | |
| chartTitleModal.classList.remove('hidden'); | |
| }); | |
| }); | |
| }); | |
| cancelTitleBtn.addEventListener('click', function() { | |
| chartTitleModal.classList.add('hidden'); | |
| }); | |
| saveTitleBtn.addEventListener('click', function() { | |
| if (currentChartTitle) { | |
| currentChartTitle.textContent = chartTitleInput.value; | |
| chartTitleModal.classList.add('hidden'); | |
| } | |
| }); | |
| }); | |
| </script> | |
| </body> | |
| </html> | |