Frontend code (javascript, css and html) for an admin dashboard. The dashboard will have the following: login_data and category info.
1) For login data, you'll will make a get request to /api/login_data which will return you a paginated list of login information described by the arguments you shall give it. Essentially, login data should look something like this: The uuid and create_data timestamp. You'll need to add limit and page params to get a specific pagination of login data.


2) For category info, you'll likewise have to make a get request to /api/category_info to get a paginated list of categories from the backend. The category entry would look something like this: uuid (string), category_name (string), url_category (string), original (string or null), thumbnail (string or null), subcategory (bool), blocked (bool), blacklist (text or null), description (text or null). The first three values wont be possible to change but the others can be and can be changed by sending the new data via a post request back to the database via route /edit_category. Something to note is that the blacklist while being a text value should only be used in a list manner where all values are separated by a comma and description should be designed to accompany large amounts of text.

3) For business info, you'll need make a get request like the others but to /api/business_info, you'll get in return the following columns: uuid (string), bussiness_name (string), url_business (string), description (text or null), shipping ( stringified json or null). Aside from uuid, all other columns are editable, a key thing to note here is that for shipping a valid json file to provide would consist of [] brackets and the values inside should be 2 letter iso code of countries. To edit shipping, i'd like to have an entire map api to use and select the countries to subscribe 2 letter iso code of countries I choose. Another thing is that the business section should have a upload form, allowing me to add new business entries which can be done via post request to /new_business.



Make the dashboard modern looking, dark themed and refrain from using colours yellow, orange, red, pink, green, purple, magenta, blue unless they very dark. The overall experience with the dashboard should be smooth and seemless.



Buttons prev and next dont work, and the map api isnt implemented either. Please fix these issues: Heres the css, js and html for this project.

CSS:
/* Reset and Base Styles */
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    display: flex;
    font-family: Arial, sans-serif;
    background-color: #121212;
    color: #e0e0e0;
    height: 100vh;
    overflow: hidden;
}

a {
    color: inherit;
    text-decoration: none;
}

h1, h2 {
    margin-bottom: 20px;
}

/* Sidebar Styles */
.sidebar {
    width: 250px;
    background-color: #1e1e1e;
    padding: 20px;
    height: 100vh;
    position: fixed;
}

    .sidebar h2 {
        color: #ffffff;
        margin-bottom: 40px;
    }

    .sidebar nav ul {
        list-style: none;
    }

        .sidebar nav ul li {
            margin-bottom: 20px;
        }

            .sidebar nav ul li a {
                display: flex;
                align-items: center;
                padding: 10px;
                border-radius: 4px;
                transition: background 0.3s;
            }

                .sidebar nav ul li a:hover,
                .sidebar nav ul li a.active {
                    background-color: #333333;
                }

                .sidebar nav ul li a i {
                    margin-right: 10px;
                    width: 20px;
                    text-align: center;
                }

/* Main Content Styles */
.main-content {
    margin-left: 250px;
    padding: 20px;
    overflow-y: auto;
    width: calc(100% - 250px);
    height: 100vh;
}

.section {
    display: none;
}

    .section.active {
        display: block;
    }

/* Table Styles */
table {
    width: 100%;
    border-collapse: collapse;
    margin-bottom: 20px;
}

thead {
    background-color: #2c2c2c;
}

    thead th {
        padding: 10px;
        text-align: left;
        border-bottom: 1px solid #444;
    }

tbody tr {
    border-bottom: 1px solid #444;
}

    tbody tr:nth-child(even) {
        background-color: #1e1e1e;
    }

tbody td {
    padding: 10px;
}

/* Pagination Styles */
.pagination {
    display: flex;
    justify-content: center;
    align-items: center;
    margin-bottom: 40px;
}

    .pagination button {
        background-color: #2c2c2c;
        color: #e0e0e0;
        border: none;
        padding: 10px 15px;
        margin: 0 5px;
        border-radius: 4px;
        cursor: pointer;
        transition: background 0.3s;
    }

        .pagination button:hover {
            background-color: #444444;
        }

        .pagination button.disabled {
            background-color: #333333;
            cursor: not-allowed;
        }

/* Form Styles */
form {
    background-color: #1e1e1e;
    padding: 20px;
    border-radius: 4px;
}

    form label {
        display: block;
        margin-bottom: 5px;
        margin-top: 15px;
    }

    form input[type="text"],
    form textarea {
        width: 100%;
        padding: 10px;
        border: 1px solid #333333;
        border-radius: 4px;
        background-color: #2c2c2c;
        color: #e0e0e0;
    }

    form textarea {
        resize: vertical;
        height: 100px;
    }

    form button {
        margin-top: 20px;
        padding: 10px 20px;
        background-color: #555555;
        border: none;
        border-radius: 4px;
        color: #ffffff;
        cursor: pointer;
        transition: background 0.3s;
    }

        form button:hover {
            background-color: #777777;
        }

/* Editable Fields */
.editable {
    background-color: #2c2c2c;
    border: 1px solid #444;
    padding: 5px;
    border-radius: 4px;
    color: #e0e0e0;
}

    .editable:focus {
        outline: none;
        border-color: #555555;
    }

/* Toggle Switch Styles */
.switch {
    position: relative;
    display: inline-block;
    width: 50px;
    height: 24px;
}

    .switch input {
        opacity: 0;
        width: 0;
        height: 0;
    }

.slider {
    position: absolute;
    cursor: pointer;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: #555555;
    transition: 0.4s;
    border-radius: 24px;
}

    .slider:before {
        position: absolute;
        content: "";
        height: 18px;
        width: 18px;
        left: 3px;
        bottom: 3px;
        background-color: white;
        transition: 0.4s;
        border-radius: 50%;
    }

input:checked + .slider {
    background-color: #4caf50;
}

    input:checked + .slider:before {
        transform: translateX(26px);
    }

/* Map Container */
#shipping-map {
    margin-top: 10px;
    border: 1px solid #444;
    border-radius: 4px;
}

/* Responsive Design */
@media (max-width: 768px) {
    .sidebar {
        width: 200px;
    }

    .main-content {
        margin-left: 200px;
        width: calc(100% - 200px);
    }
}

@media (max-width: 576px) {
    body {
        flex-direction: column;
    }

    .sidebar {
        width: 100%;
        height: auto;
        position: relative;
    }

    .main-content {
        margin-left: 0;
        width: 100%;
    }
}


HTML:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Admin Dashboard</title>
    <!-- Font Awesome for Icons -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.6.0/css/all.min.css" integrity="sha512-Kc323vGBEqzTmouAECnVceyQqyqdsSiqLQISBL29aUW4U/M7pSPA/gEUZQqv1cwx4OnYxTxve5UMg5GT6L4JJg==" crossorigin="anonymous" referrerpolicy="no-referrer" />
    <!-- Leaflet CSS for Map -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.css" integrity="sha512-Zcn6bjR/8RZbLEpLIeOwNtzREBAJnUKESxces60Mpoj+2okopSAcSUIUOseddDm0cxnGQzxIR7vJgsLZbdLE3w==" crossorigin="anonymous" referrerpolicy="no-referrer" />
    <!-- Custom CSS -->
    <link rel="stylesheet" href="/css/admin.css">
</head>
<body>
    <div class="sidebar">
        <h2>Admin Dashboard</h2>
        <nav>
            <ul>
                <li><a href="#" id="login-data-tab" class="active"><i class="fa fa-sign-in-alt"></i> Login Data</a></li>
                <li><a href="#" id="category-info-tab"><i class="fa fa-list"></i> Category Info</a></li>
                <li><a href="#" id="business-info-tab"><i class="fa fa-briefcase"></i> Business Info</a></li>
            </ul>
        </nav>
    </div>
    <div class="main-content">
        <!-- Login Data Section -->
        <section id="login-data-section" class="section active">
            <h1>Login Data</h1>
            <table>
                <thead>
                    <tr>
                        <th>UUID</th>
                        <th>Create Date</th>
                    </tr>
                </thead>
                <tbody id="login-data-table-body">
                    <!-- Data will be populated here -->
                </tbody>
            </table>
            <div class="pagination" id="login-pagination">
                <!-- Pagination controls -->
            </div>
        </section>

        <!-- Category Info Section -->
        <section id="category-info-section" class="section">
            <h1>Category Info</h1>
            <table>
                <thead>
                    <tr>
                        <th>UUID</th>
                        <th>Category Name</th>
                        <th>URL Category</th>
                        <th>Original</th>
                        <th>Thumbnail</th>
                        <th>Subcategory</th>
                        <th>Blocked</th>
                        <th>Blacklist</th>
                        <th>Description</th>
                        <th>Actions</th>
                    </tr>
                </thead>
                <tbody id="category-info-table-body">
                    <!-- Data will be populated here -->
                </tbody>
            </table>
            <div class="pagination" id="category-pagination">
                <!-- Pagination controls -->
            </div>
        </section>

        <!-- Business Info Section -->
        <section id="business-info-section" class="section">
            <h1>Business Info</h1>
            <table>
                <thead>
                    <tr>
                        <th>UUID</th>
                        <th>Business Name</th>
                        <th>URL Business</th>
                        <th>Description</th>
                        <th>Shipping</th>
                        <th>Actions</th>
                    </tr>
                </thead>
                <tbody id="business-info-table-body">
                    <!-- Data will be populated here -->
                </tbody>
            </table>
            <div class="pagination" id="business-pagination">
                <!-- Pagination controls -->
            </div>

            <!-- Upload Form -->
            <h2>Add New Business</h2>
            <form id="new-business-form">
                <label for="business_name">Business Name:</label>
                <input type="text" id="business_name" name="business_name" required>

                <label for="url_business">URL Business:</label>
                <input type="text" id="url_business" name="url_business" required>

                <label for="description">Description:</label>
                <textarea id="description" name="description"></textarea>

                <label for="shipping">Shipping:</label>
                <div id="shipping-map" style="height: 400px;"></div>
                <input type="hidden" id="shipping" name="shipping">

                <button type="submit">Add Business</button>
            </form>
        </section>
    </div>

    <!-- Leaflet JS for Map -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.js" integrity="sha512-BwHfrr4c9kmRkLw6iXFdzcdWV/PGkVgiIyIWLLlTSXzWQzxuSg4DiQUCpauz/EWjgk5TYQqX/kvn9pG1NpYfqg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <!-- Custom JS -->
    <script src="/js/admin.js"></script>
</body>
</html>


JAVASCRIPT:
// Helper Functions
const createElement = (tag, attributes = {}, ...children) => {
    const element = document.createElement(tag);
    for (let key in attributes) {
        if (key.startsWith('on') && typeof attributes[key] === 'function') {
            element.addEventListener(key.substring(2).toLowerCase(), attributes[key]);
        } else if (key === 'className') {
            element.className = attributes[key];
        } else if (key === 'innerHTML') {
            element.innerHTML = attributes[key];
        } else {
            element.setAttribute(key, attributes[key]);
        }
    }
    children.forEach(child => {
        if (typeof child === 'string') {
            element.appendChild(document.createTextNode(child));
        } else if (child instanceof Node) {
            element.appendChild(child);
        }
    });
    return element;
};

// API Base URL (Modify if needed)
const API_BASE_URL = '/api';

// Fetch Login Data
const fetchLoginData = async (page = 1, limit = 10) => {
    try {
        const response = await fetch(`${API_BASE_URL}/login_data?limit=${limit}&page=${page}`);
        const data = await response.json();
        return data;
    } catch (error) {
        console.error('Error fetching login data:', error);
        return { data: [], total: 0 };
    }
};

// Fetch Category Info
const fetchCategoryInfo = async (page = 1, limit = 10) => {
    try {
        const response = await fetch(`${API_BASE_URL}/category_info?limit=${limit}&page=${page}`);
        const data = await response.json();
        return data;
    } catch (error) {
        console.error('Error fetching category info:', error);
        return { data: [], total: 0 };
    }
};

// Fetch Business Info
const fetchBusinessInfo = async (page = 1, limit = 10) => {
    try {
        const response = await fetch(`${API_BASE_URL}/business_info?limit=${limit}&page=${page}`);
        const data = await response.json();
        return data;
    } catch (error) {
        console.error('Error fetching business info:', error);
        return { data: [], total: 0 };
    }
};

// Render Pagination
const renderPagination = (currentPage, totalPages, container, onPageChange) => {
    container.innerHTML = '';

    const prevButton = createElement('button', {
        disabled: currentPage === 1,
        onClick: () => onPageChange(currentPage - 1),
        className: currentPage === 1 ? 'disabled' : ''
    }, 'Prev');
    container.appendChild(prevButton);

    // Display up to 5 page numbers
    let start = Math.max(1, currentPage - 2);
    let end = Math.min(totalPages, currentPage + 2);
    if (currentPage <= 2) {
        end = Math.min(5, totalPages);
    }
    if (currentPage >= totalPages - 1) {
        start = Math.max(1, totalPages - 4);
    }

    for (let i = start; i <= end; i++) {
        const pageButton = createElement('button', {
            className: i === currentPage ? 'active' : '',
            onClick: () => onPageChange(i)
        }, i.toString());
        container.appendChild(pageButton);
    }

    const nextButton = createElement('button', {
        disabled: currentPage === totalPages,
        onClick: () => onPageChange(currentPage + 1),
        className: currentPage === totalPages ? 'disabled' : ''
    }, 'Next');
    container.appendChild(nextButton);
};

// Initialize Login Data Section
const initLoginData = () => {
    const tableBody = document.getElementById('login-data-table-body');
    const paginationContainer = document.getElementById('login-pagination');
    const limit = 10;
    let currentPage = 1;
    let totalPages = 1;

    const loadData = async (page) => {
        const data = await fetchLoginData(page, limit);
        tableBody.innerHTML = '';
        data.entries.forEach(entry => {
            const row = createElement('tr', {},
                createElement('td', {}, entry.uuid),
                createElement('td', {}, new Date(entry.created_date).toLocaleString())
            );
            tableBody.appendChild(row);
        });
        totalPages = Math.ceil(data.total / limit);
        renderPagination(page, totalPages, paginationContainer, loadData);
    };

    loadData(currentPage);
};

// Initialize Category Info Section
const initCategoryInfo = () => {
    const tableBody = document.getElementById('category-info-table-body');
    const paginationContainer = document.getElementById('category-pagination');
    const limit = 10;
    let currentPage = 1;
    let totalPages = 1;

    const loadData = async (page) => {
        const data = await fetchCategoryInfo(page, limit);
        console.log(data)
        tableBody.innerHTML = '';
        data.entries.forEach(entry => {
            const row = createElement('tr', {},
                createElement('td', {}, entry.uuid),
                createElement('td', {}, entry.category_name),
                createElement('td', {}, entry.url_category),
                createEditableCell('original', entry.original, entry.uuid),
                createEditableCell('thumbnail', entry.thumbnail, entry.uuid),
                createToggleCell('subcategory', entry.subcategory, entry.uuid),
                createToggleCell('blocked', entry.blocked, entry.uuid),
                createEditableCell('blacklist', entry.blacklist, entry.uuid, true),
                createEditableTextarea('description', entry.description, entry.uuid),
                createElement('td', {},
                    createElement('button', {
                        onClick: () => saveCategory(entry.uuid),
                        className: 'save-button'
                    }, 'Save')
                )
            );
            tableBody.appendChild(row);
        });
        totalPages = Math.ceil(data.total / limit);
        renderPagination(page, totalPages, paginationContainer, loadData);
    };

    loadData(currentPage);
};

// Create Editable Cell
const createEditableCell = (field, value, uuid, isList = false) => {
    const input = createElement('input', {
        type: 'text',
        className: 'editable',
        value: value || '',
        'data-uuid': uuid,
        'data-field': field,
        placeholder: isList ? 'Comma separated values' : ''
    });
    return createElement('td', {}, input);
};

// Create Editable Textarea
const createEditableTextarea = (field, value, uuid) => {
    const textarea = createElement('textarea', {
        className: 'editable',
        innerHTML: value || '',
        'data-uuid': uuid,
        'data-field': field
    });
    return createElement('td', {}, textarea);
};

// Create Toggle Cell
const createToggleCell = (field, value, uuid) => {
    const toggle = createElement('label', { className: 'switch' },
        createElement('input', {
            type: 'checkbox',
            checked: value,
            'data-uuid': uuid,
            'data-field': field
        }),
        createElement('span', { className: 'slider' })
    );
    return createElement('td', {}, toggle);
};

// Save Category Changes
const saveCategory = async (uuid) => {
    const row = [...document.querySelectorAll(`input[data-uuid="${uuid}"], textarea[data-uuid="${uuid}"]`)].reduce((acc, input) => {
        acc[input.dataset.field] = input.value;
        if (input.type === 'checkbox') acc[input.dataset.field] = input.checked;
        return acc;
    }, { uuid });

    try {
        const response = await fetch('/edit_category', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(row)
        });
        if (response.ok) {
            alert('Category updated successfully!');
        } else {
            alert('Failed to update category.');
        }
    } catch (error) {
        console.error('Error updating category:', error);
        alert('Error updating category.');
    }
};

// Initialize Business Info Section
const initBusinessInfo = () => {
    const tableBody = document.getElementById('business-info-table-body');
    const paginationContainer = document.getElementById('business-pagination');
    const limit = 10;
    let currentPage = 1;
    let totalPages = 1;

    const loadData = async (page) => {
        const data = await fetchBusinessInfo(page, limit);
        tableBody.innerHTML = '';
        data.entries.forEach(entry => {
            const shippingArray = entry.shipping ? JSON.parse(entry.shipping) : [];
            const row = createElement('tr', {},
                createElement('td', {}, entry.uuid),
                createEditableCellBusiness('business_name', entry.business_name, entry.uuid),
                createEditableCellBusiness('url_business', entry.url_business, entry.uuid),
                createEditableTextareaBusiness('description', entry.description, entry.uuid),
                createEditableCellBusiness('shipping', shippingArray.join(','), entry.uuid),
                createElement('td', {},
                    createElement('button', {
                        onClick: () => saveBusiness(entry.uuid),
                        className: 'save-button'
                    }, 'Save')
                )
            );
            tableBody.appendChild(row);
        });
        totalPages = Math.ceil(data.total / limit);
        renderPagination(page, totalPages, paginationContainer, loadData);
    };

    loadData(currentPage);
};

// Create Editable Cell for Business Info
const createEditableCellBusiness = (field, value, uuid) => {
    let input;
    if (field === 'shipping') {
        input = createElement('input', {
            type: 'text',
            className: 'editable',
            value: value || '',
            'data-uuid': uuid,
            'data-field': field,
            placeholder: 'e.g., US,CA,GB'
        });
    } else {
        input = createElement('input', {
            type: 'text',
            className: 'editable',
            value: value || '',
            'data-uuid': uuid,
            'data-field': field
        });
    }
    return createElement('td', {}, input);
};

// Create Editable Textarea for Business Info
const createEditableTextareaBusiness = (field, value, uuid) => {
    const textarea = createElement('textarea', {
        className: 'editable',
        innerHTML: value || '',
        'data-uuid': uuid,
        'data-field': field
    });
    return createElement('td', {}, textarea);
};

// Save Business Changes
const saveBusiness = async (uuid) => {
    const row = [...document.querySelectorAll(`input[data-uuid="${uuid}"], textarea[data-uuid="${uuid}"]`)].reduce((acc, input) => {
        acc[input.dataset.field] = input.value;
        return acc;
    }, { uuid });

    // Validate shipping
    if (row.shipping) {
        const shippingArray = row.shipping.split(',').map(code => code.trim().toUpperCase());
        const isValid = shippingArray.every(code => /^[A-Z]{2}$/.test(code));
        if (!isValid) {
            alert('Shipping must be a comma-separated list of 2-letter ISO country codes.');
            return;
        }
        row.shipping = JSON.stringify(shippingArray);
    }

    try {
        const response = await fetch('/edit_business', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(row)
        });
        if (response.ok) {
            alert('Business updated successfully!');
        } else {
            alert('Failed to update business.');
        }
    } catch (error) {
        console.error('Error updating business:', error);
        alert('Error updating business.');
    }
};

// Initialize Map for Shipping Selection
let selectedCountries = [];

const initMap = () => {
    const map = L.map('shipping-map').setView([20, 0], 2);

    // Add OpenStreetMap tiles
    L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
        attribution: '&copy; OpenStreetMap contributors'
    }).addTo(map);

    // Function to toggle country selection
    const onMapClick = (e) => {
        // Normally, you'd need to determine which country was clicked.
        // For simplicity, we'll simulate country selection with random ISO codes.

        // This requires a GeoJSON map with country boundaries and ISO codes.
        // For brevity, it's not implemented here.
        alert('Country selection via map is not implemented in this demo.');
    };

    map.on('click', onMapClick);

    // Alternatively, use a multi-select dropdown for selecting countries
    // since map-based selection requires extensive GeoJSON data.

    // Implementing a multi-select as a placeholder
    const shippingInput = document.getElementById('shipping');
    const placeholder = createElement('div', { style: 'margin-top:10px;' },
        'Shipping countries selection is not implemented. Please enter 2-letter ISO codes manually.')
    document.getElementById('shipping-map').appendChild(placeholder);
};

// Handle New Business Form Submission
const handleNewBusinessForm = () => {
    const form = document.getElementById('new-business-form');
    form.addEventListener('submit', async (e) => {
        e.preventDefault();
        const business_name = form.business_name.value.trim();
        const url_business = form.url_business.value.trim();
        const description = form.description.value.trim();
        const shipping = form.shipping.value.trim();

        // Validate shipping
        let shippingJSON = null;
        if (shipping) {
            const shippingArray = shipping.split(',').map(code => code.trim().toUpperCase());
            const isValid = shippingArray.every(code => /^[A-Z]{2}$/.test(code));
            if (!isValid) {
                alert('Shipping must be a comma-separated list of 2-letter ISO country codes.');
                return;
            }
            shippingJSON = JSON.stringify(shippingArray);
        }

        const payload = {
            business_name,
            url_business,
            description: description || null,
            shipping: shippingJSON
        };

        try {
            const response = await fetch('/new_business', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(payload)
            });
            if (response.ok) {
                alert('New business added successfully!');
                form.reset();
                // Optionally, reload the business info table
                initBusinessInfo();
            } else {
                alert('Failed to add new business.');
            }
        } catch (error) {
            console.error('Error adding new business:', error);
            alert('Error adding new business.');
        }
    });
};

// Tab Navigation
const initTabs = () => {
    const loginTab = document.getElementById('login-data-tab');
    const categoryTab = document.getElementById('category-info-tab');
    const businessTab = document.getElementById('business-info-tab');

    const sections = {
        'login-data-tab': 'login-data-section',
        'category-info-tab': 'category-info-section',
        'business-info-tab': 'business-info-section'
    };

    const tabs = [loginTab, categoryTab, businessTab];
    tabs.forEach(tab => {
        tab.addEventListener('click', (e) => {
            e.preventDefault();
            // Remove active class from all tabs
            tabs.forEach(t => t.classList.remove('active'));
            // Add active class to clicked tab
            tab.classList.add('active');
            // Hide all sections
            Object.values(sections).forEach(sec => {
                document.getElementById(sec).classList.remove('active');
            });
            // Show the selected section
            const activeSection = sections[tab.id];
            document.getElementById(activeSection).classList.add('active');
        });
    });
};

// Initialize Dashboard
const initDashboard = () => {
    initTabs();
    initLoginData();
    initCategoryInfo();
    initBusinessInfo();
    initMap();
    handleNewBusinessForm();
};

// Run Dashboard Initialization on DOMContentLoaded
document.addEventListener('DOMContentLoaded', initDashboard);