CoolFace
Apppublic

PLEDIPO/msme-manager-pro

sourceHugging Faceupdated 9mo agoView on Hugging Face
0likes
script.js567 linesDownload Raw Back to root
1document.addEventListener('DOMContentLoaded', function() {2    // Initialize app3    initApp();4    5    // Event listeners6    document.getElementById('addMsmeBtn').addEventListener('click', openAddMsmeModal);7    document.getElementById('importBtn').addEventListener('click', openImportModal);8    document.getElementById('exportBtn').addEventListener('click', exportData);9    document.getElementById('filterBtn').addEventListener('click', openFilterModal);10    document.getElementById('refreshBtn').addEventListener('click', refreshData);11    document.getElementById('searchInput').addEventListener('input', searchMsmes);12});13 14// MSME Data Management15let msmeData = [];16let filteredData = [];17let sortConfig = { column: null, direction: 'asc' };18 19async function initApp() {20    // Load initial data (in a real app, this would be from an API)21    await loadData();22    updateStats();23}24 25async function loadData() {26    // Simulate API call27    try {28        // In a real app, replace with actual fetch call29        // const response = await fetch('/api/msmes');30        // msmeData = await response.json();31        32        // Mock data for demo33        msmeData = generateMockData();34        filteredData = [...msmeData];35        renderTable();36    } catch (error) {37        console.error('Error loading data:', error);38        showToast('Failed to load MSME data', 'error');39    }40}41 42function generateMockData() {43    const sectors = ['Agriculture', 'Manufacturing', 'Retail', 'Services', 'Construction'];44    const municipalities = ['Baler', 'San Luis', 'Dipaculao', 'Maria Aurora', 'Dingalan'];45    const categories = ['Micro', 'Small', 'Medium'];46    const structures = ['Sole Proprietorship', 'Partnership', 'Corporation'];47    48    const mockData = [];49    50    for (let i = 0; i < 50; i++) {51        mockData.push({52            id: `MSME-${1000 + i}`,53            businessName: `Business ${i + 1}`,54            owner: `Owner ${i + 1}`,55            dtiRegistration: `DTI-${Math.floor(1000 + Math.random() * 9000)}`,56            sector: sectors[Math.floor(Math.random() * sectors.length)],57            municipality: municipalities[Math.floor(Math.random() * municipalities.length)],58            barangay: `Barangay ${Math.floor(Math.random() * 10) + 1}`,59            province: 'Aurora',60            region: 'Central Luzon',61            category: categories[Math.floor(Math.random() * categories.length)],62            contactNumber: `09${Math.floor(100000000 + Math.random() * 900000000)}`,63            businessStructure: structures[Math.floor(Math.random() * structures.length)],64        status: 'Active',65registrationDate: new Date(Date.now() - Math.floor(Math.random() * 365 * 24 * 60 * 60 * 1000)).toISOString().split('T')[0]66        });67    }68    69    return mockData;70}71 72// Table Rendering and Sorting73function renderTable() {74    const table = document.querySelector('custom-msme-table');75    if (table) {76        table.setData(filteredData);77    }78}79 80function sortTable(column) {81    if (sortConfig.column === column) {82        sortConfig.direction = sortConfig.direction === 'asc' ? 'desc' : 'asc';83    } else {84        sortConfig.column = column;85        sortConfig.direction = 'asc';86    }87    88    filteredData.sort((a, b) => {89        const valueA = a[column] || '';90        const valueB = b[column] || '';91        92        if (valueA < valueB) {93            return sortConfig.direction === 'asc' ? -1 : 1;94        }95        if (valueA > valueB) {96            return sortConfig.direction === 'asc' ? 1 : -1;97        }98        return 0;99    });100    101    renderTable();102}103 104// Search and Filter105function searchMsmes() {106    const query = document.getElementById('searchInput').value.toLowerCase();107    108    if (!query) {109        filteredData = [...msmeData];110    } else {111        filteredData = msmeData.filter(msme => 112            Object.values(msme).some(value => 113                String(value).toLowerCase().includes(query)114            )115        );116    }117    118    renderTable();119    updateStats();120}121 122function applyFilters(filters) {123    filteredData = msmeData.filter(msme => {124        return Object.entries(filters).every(([key, value]) => {125            if (!value) return true;126            return String(msme[key]).toLowerCase() === value.toLowerCase();127        });128    });129    130    renderTable();131    updateStats();132}133 134// Stats Update135function updateStats() {136    document.getElementById('totalMsmes').textContent = filteredData.length;137}138 139// Modal Functions140function openAddMsmeModal() {141    const modalContainer = document.getElementById('modalContainer');142    modalContainer.innerHTML = `143        <div class="modal-overlay">144            <div class="modal-content fade-in">145                <div class="p-6 hovered-element">146                    <div class="flex justify-between items-center mb-4">147                        <h2 class="text-xl font-bold text-gray-800 hovered-element">Add New MSME</h2>148                        <button id="closeModal" class="text-gray-400 hover:text-gray-600">149                            <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-x"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>150                        </button>151                    </div>152                    153                    <form id="msmeForm" class="space-y-4">154                        <div class="grid grid-cols-1 md:grid-cols-2 gap-4">155                            <div class="form-group">156                                <label for="businessName" class="form-label hovered-element">Business Name</label>157                                <input type="text" id="businessName" class="form-input" required="">158                            </div>159                            <div class="form-group">160                                <label for="owner" class="form-label">Owner</label>161                                <input type="text" id="owner" class="form-input" required="">162                            </div>163                            <div class="form-group">164                                <label for="dtiRegistration" class="form-label">DTI Registration No</label>165                                <input type="text" id="dtiRegistration" class="form-input">166                            </div>167                            <div class="form-group">168                                <label for="contactNumber" class="form-label">Contact Number</label>169                                <input type="tel" id="contactNumber" class="form-input">170                            </div>171                            <div class="form-group">172                                <label for="sector" class="form-label">Sector</label>173                                <select id="sector" class="form-select">174                                    <option value="">Select Sector</option>175                                    <option value="Agriculture">Agriculture</option>176                                    <option value="Manufacturing">Manufacturing</option>177                                    <option value="Retail">Retail</option>178                                    <option value="Services">Services</option>179                                    <option value="Construction">Construction</option>180                                </select>181                            </div>182                            <div class="form-group">183                                <label for="category" class="form-label">Category</label>184                                <select id="category" class="form-select">185                                    <option value="">Select Category</option>186                                    <option value="Micro">Micro</option>187                                    <option value="Small">Small</option>188                                    <option value="Medium">Medium</option>189                                </select>190                            </div>191                        </div>192                        193                        <div class="grid grid-cols-1 md:grid-cols-3 gap-4">194                            <div class="form-group">195                                <label for="municipality" class="form-label">Municipality</label>196                                <select id="municipality" class="form-select">197                                    <option value="">Select Municipality</option>198                                    <option value="Baler">Baler</option>199                                    <option value="San Luis">San Luis</option>200                                    <option value="Dipaculao">Dipaculao</option>201                                    <option value="Maria Aurora">Maria Aurora</option>202                                    <option value="Dingalan">Dingalan</option>203                                </select>204                            </div>205                            <div class="form-group">206                                <label for="barangay" class="form-label">Barangay</label>207                                <input type="text" id="barangay" class="form-input">208                            </div>209                            <div class="form-group">210                                <label for="businessStructure" class="form-label">Business Structure</label>211                                <select id="businessStructure" class="form-select">212                                    <option value="">Select Structure</option>213                                    <option value="Sole Proprietorship">Sole Proprietorship</option>214                                    <option value="Partnership">Partnership</option>215                                    <option value="Corporation">Corporation</option>216                                </select>217                            </div>218                        </div>219                        220                        <div class="flex justify-end space-x-3 pt-4">221                            <button type="button" id="cancelForm" class="btn-secondary">Cancel</button>222                            <button type="submit" class="btn-primary">Save MSME</button>223                        </div>224                    </form>225                </div>226            </div>227        </div>228    `;229    // Replace feather icons230    if (window.feather) {231        feather.replace();232    }233 234    // Close modal handlers235    const closeModal = () => modalContainer.innerHTML = '';236    document.getElementById('closeModal').addEventListener('click', closeModal);237    document.getElementById('cancelForm').addEventListener('click', closeModal);238 239    // Form submission240    document.getElementById('msmeForm').addEventListener('submit', (e) => {241        e.preventDefault();242        saveNewMsme();243        closeModal();244    });245}246function openImportModal() {247    const modalContainer = document.getElementById('modalContainer');248    modalContainer.innerHTML = `249        <div class="modal-overlay">250            <div class="modal-content fade-in" style="width: 500px;">251                <div class="p-6">252                    <div class="flex justify-between items-center mb-4">253                        <h2 class="text-xl font-bold text-gray-800">Import MSME Data</h2>254                        <button id="closeImportModal" class="text-gray-400 hover:text-gray-600">255                            <i data-feather="x"></i>256                        </button>257                    </div>258                    259                    <div class="space-y-4">260                        <div class="border-2 border-dashed border-gray-300 rounded-lg p-6 text-center">261                            <div class="flex flex-col items-center justify-center">262                                <i data-feather="upload-cloud" class="w-12 h-12 text-gray-400 mb-2"></i>263                                <p class="text-gray-600">Drag & drop your CSV file here</p>264                                <p class="text-gray-400 text-sm mt-1">or</p>265                                <label for="fileInput" class="btn-primary inline-block mt-2 cursor-pointer">266                                    <input type="file" id="fileInput" class="hidden" accept=".csv">267                                    Select File268                                </label>269                            </div>270                        </div>271                        272                        <div class="bg-blue-50 p-3 rounded-md text-sm text-blue-700">273                            <p><strong>File Requirements:</strong></p>274                            <ul class="list-disc pl-5 mt-1">275                                <li>CSV format (comma separated values)</li>276                                <li>First row should contain headers</li>277                                <li>Max file size: 5MB</li>278                            </ul>279                        </div>280                        281                        <div class="flex justify-end space-x-3 pt-4">282                            <button type="button" id="cancelImport" class="btn-secondary">Cancel</button>283                            <button type="button" id="confirmImport" class="btn-primary" disabled>Import Data</button>284                        </div>285                    </div>286                </div>287            </div>288        </div>289    `;290    291    feather.replace();292    293    const closeModal = () => modalContainer.innerHTML = '';294    document.getElementById('closeImportModal').addEventListener('click', closeModal);295    document.getElementById('cancelImport').addEventListener('click', closeModal);296    297    const fileInput = document.getElementById('fileInput');298    const confirmBtn = document.getElementById('confirmImport');299    300    fileInput.addEventListener('change', (e) => {301        const file = e.target.files[0];302        if (file) {303            if (file.size > 5 * 1024 * 1024) {304                showToast('File size exceeds 5MB limit', 'error');305                return;306            }307            308            if (!file.name.endsWith('.csv')) {309                showToast('Please select a CSV file', 'error');310                return;311            }312            313            confirmBtn.disabled = false;314            showToast(`Selected file: ${file.name}`, 'success');315        }316    });317    318    confirmBtn.addEventListener('click', () => {319        const file = fileInput.files[0];320        if (!file) return;321        322        const reader = new FileReader();323        reader.onload = (e) => {324            try {325                const csvData = e.target.result;326                const importedData = parseCSV(csvData);327                328                if (importedData.length > 0) {329                    msmeData = [...importedData, ...msmeData];330                    filteredData = [...msmeData];331                    renderTable();332                    updateStats();333                    showToast(`Successfully imported ${importedData.length} MSMEs`, 'success');334                    closeModal();335                } else {336                    showToast('No valid data found in the file', 'error');337                }338            } catch (error) {339                console.error('Error parsing CSV:', error);340                showToast('Error processing CSV file', 'error');341            }342        };343        reader.readAsText(file);344    });345}346 347function parseCSV(csvString) {348    const lines = csvString.split('\n');349    const headers = lines[0].split(',').map(h => h.trim());350    const result = [];351    352    for (let i = 1; i < lines.length; i++) {353        if (!lines[i].trim()) continue;354        355        const obj = {};356        const currentline = lines[i].split(',');357        358        for (let j = 0; j < headers.length; j++) {359            obj[headers[j]] = currentline[j] ? currentline[j].trim() : '';360        }361        362        // Map CSV fields to our data structure363        const mappedData = {364            id: `MSME-${1000 + msmeData.length + i}`,365            businessName: obj['Business Name'] || obj['businessName'] || `Business ${i}`,366            owner: obj['Owner'] || obj['owner'] || `Owner ${i}`,367            dtiRegistration: obj['DTI Registration'] || obj['dtiRegistration'] || '',368            sector: obj['Sector'] || obj['sector'] || 'Services',369            municipality: obj['Municipality'] || obj['municipality'] || 'Baler',370            barangay: obj['Barangay'] || obj['barangay'] || 'Barangay 1',371            province: obj['Province'] || obj['province'] || 'Aurora',372            region: obj['Region'] || obj['region'] || 'Central Luzon',373            category: obj['Category'] || obj['category'] || 'Micro',374            contactNumber: obj['Contact Number'] || obj['contactNumber'] || '',375            businessStructure: obj['Business Structure'] || obj['businessStructure'] || 'Sole Proprietorship',376            status: 'Active',377            registrationDate: new Date().toISOString().split('T')[0]378        };379        380        result.push(mappedData);381    }382    383    return result;384}385function openFilterModal() {386    const modalContainer = document.getElementById('modalContainer');387    modalContainer.innerHTML = `388        <div class="modal-overlay">389            <div class="modal-content fade-in" style="width: 500px;">390                <div class="p-6">391                    <div class="flex justify-between items-center mb-4">392                        <h2 class="text-xl font-bold text-gray-800 hovered-element">Advanced Filters</h2>393                        <button id="closeFilterModal" class="text-gray-400 hover:text-gray-600 hovered-element">394                            <i data-feather="x" class="hovered-element"></i>395                        </button>396                    </div>397                    398                    <form id="filterForm" class="space-y-4">399                        <div class="form-group">400                            <label for="filterSector" class="form-label hovered-element">Sector</label>401                            <select id="filterSector" class="form-select hovered-element">402                                <option value="">All Sectors</option>403                                <option value="Agriculture">Agriculture</option>404                                <option value="Manufacturing">Manufacturing</option>405                                <option value="Retail">Retail</option>406                                <option value="Services">Services</option>407                                <option value="Construction">Construction</option>408                            </select>409                        </div>410                        411                        <div class="form-group">412                            <label for="filterMunicipality" class="form-label hovered-element">Municipality</label>413                            <select id="filterMunicipality" class="form-select hovered-element">414                                <option value="">All Municipalities</option>415                                <option value="Baler">Baler</option>416                                <option value="San Luis">San Luis</option>417                                <option value="Dipaculao">Dipaculao</option>418                                <option value="Maria Aurora">Maria Aurora</option>419                                <option value="Dingalan">Dingalan</option>420                            </select>421                        </div>422                        423                        <div class="form-group">424                            <label for="filterCategory" class="form-label hovered-element">Category</label>425                            <select id="filterCategory" class="form-select hovered-element">426                                <option value="">All Categories</option>427                                <option value="Micro">Micro</option>428                                <option value="Small">Small</option>429                                <option value="Medium">Medium</option>430                            </select>431                        </div>432                        433                        <div class="form-group">434                            <label for="filterStructure" class="form-label hovered-element">Business Structure</label>435                            <select id="filterStructure" class="form-select hovered-element">436                                <option value="">All Structures</option>437                                <option value="Sole Proprietorship">Sole Proprietorship</option>438                                <option value="Partnership">Partnership</option>439                                <option value="Corporation">Corporation</option>440                            </select>441                        </div>442                        443                        <div class="flex justify-end space-x-3 pt-4">444                            <button type="button" id="resetFilters" class="btn-secondary hovered-element">Reset</button>445                            <button type="submit" class="btn-primary hovered-element">Apply Filters</button>446                        </div>447                    </form>448                </div>449            </div>450        </div>451    `;452feather.replace();453    454    document.getElementById('closeFilterModal').addEventListener('click', () => {455        modalContainer.innerHTML = '';456    });457    458    document.getElementById('resetFilters').addEventListener('click', () => {459        document.getElementById('filterForm').reset();460    });461    462    document.getElementById('filterForm').addEventListener('submit', function(e) {463        e.preventDefault();464        const filters = {465            sector: document.getElementById('filterSector').value,466            municipality: document.getElementById('filterMunicipality').value,467            category: document.getElementById('filterCategory').value,468            businessStructure: document.getElementById('filterStructure').value469        };470        applyFilters(filters);471        modalContainer.innerHTML = '';472    });473}474 475// Data Operations476function saveNewMsme() {477    const form = document.getElementById('msmeForm');478    const newMsme = {479        id: `MSME-${1000 + msmeData.length}`,480        businessName: form.businessName.value,481        owner: form.owner.value,482        dtiRegistration: form.dtiRegistration.value,483        sector: form.sector.value,484        municipality: form.municipality.value,485        barangay: form.barangay.value,486        province: 'Aurora',487        region: 'Central Luzon',488        category: form.category.value,489        contactNumber: form.contactNumber.value,490        businessStructure: form.businessStructure.value,491        status: 'Active',492        registrationDate: new Date().toISOString().split('T')[0]493    };494    495    // In a real app, this would be an API call496    msmeData.unshift(newMsme);497    filteredData.unshift(newMsme);498    499    renderTable();500    updateStats();501    document.getElementById('modalContainer').innerHTML = '';502    showToast('MSME added successfully!', 'success');503}504function exportData() {505    if (filteredData.length === 0) {506        showToast('No data to export', 'warning');507        return;508    }509 510    // Get the headers from the first object511    const headers = Object.keys(filteredData[0]);512    513    // Convert the data to CSV format514    let csvContent = headers.join(',') + '\n';515    516    filteredData.forEach(item => {517        const row = headers.map(header => {518            // Escape quotes and wrap in quotes if contains comma519            let value = item[header] || '';520            if (typeof value === 'string' && value.includes(',')) {521                value = `"${value.replace(/"/g, '""')}"`;522            }523            return value;524        });525        csvContent += row.join(',') + '\n';526    });527 528    // Create download link529    const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });530    const url = URL.createObjectURL(blob);531    const link = document.createElement('a');532    link.setAttribute('href', url);533    link.setAttribute('download', `msme_export_${new Date().toISOString().split('T')[0]}.csv`);534    link.style.visibility = 'hidden';535    536    document.body.appendChild(link);537    link.click();538    document.body.removeChild(link);539    540    showToast(`Exported ${filteredData.length} MSMEs`, 'success');541}542function refreshData() {543    loadData();544    showToast('Data refreshed', 'success');545}546 547// Utility Functions548function showToast(message, type = 'info') {549    const toast = document.createElement('div');550    let bgColor = 'bg-blue-500';551    552    if (type === 'success') bgColor = 'bg-green-500';553    if (type === 'error') bgColor = 'bg-red-500';554    if (type === 'warning') bgColor = 'bg-yellow-500';555    556    toast.className = `fixed bottom-4 right-4 ${bgColor} text-white px-4 py-2 rounded-md shadow-lg flex items-center`;557    toast.innerHTML = `558        <span>${message}</span>559    `;560    561    document.body.appendChild(toast);562    563    setTimeout(() => {564        toast.classList.add('opacity-0', 'transition-opacity', 'duration-300');565        setTimeout(() => toast.remove(), 300);566    }, 3000);567}