Files
orion/static/admin/dashboard.html

429 lines
21 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Admin Dashboard - Multi-Tenant Ecommerce Platform</title>
<!-- Font Awesome -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<!-- Styles -->
<link rel="stylesheet" href="/static/css/shared/base.css">
<link rel="stylesheet" href="/static/css/shared/components.css">
<link rel="stylesheet" href="/static/css/shared/modals.css">
<link rel="stylesheet" href="/static/css/admin/admin.css">
<style>
[x-cloak] { display: none !important; }
</style>
</head>
<body x-data="adminDashboard()" x-init="init()" x-cloak>
<!-- Admin Header (Injected from template) -->
<div x-html="adminLayoutTemplates.header()"></div>
<!-- Admin Sidebar (Injected from template) -->
<div x-html="adminLayoutTemplates.sidebar()"></div>
<!-- Main Content -->
<main class="admin-content">
<!-- Dashboard View -->
<div x-show="currentSection === 'dashboard'">
<!-- Stats Grid -->
<div class="stats-grid">
<div class="stat-card">
<div class="stat-header">
<div class="stat-title">Total Vendors</div>
<div class="stat-icon">🏪</div>
</div>
<div class="stat-value" x-text="stats.vendors?.total_vendors || 0"></div>
<div class="stat-subtitle">
<span x-text="stats.vendors?.active_vendors || 0"></span> active
</div>
</div>
<div class="stat-card">
<div class="stat-header">
<div class="stat-title">Total Users</div>
<div class="stat-icon">👥</div>
</div>
<div class="stat-value" x-text="stats.users?.total_users || 0"></div>
<div class="stat-subtitle">
<span x-text="stats.users?.active_users || 0"></span> active
</div>
</div>
<div class="stat-card">
<div class="stat-header">
<div class="stat-title">Verified Vendors</div>
<div class="stat-icon"></div>
</div>
<div class="stat-value" x-text="stats.vendors?.verified_vendors || 0"></div>
<div class="stat-subtitle">
<span x-text="Math.round(stats.vendors?.verification_rate || 0)"></span>% verification rate
</div>
</div>
<div class="stat-card">
<div class="stat-header">
<div class="stat-title">Import Jobs</div>
<div class="stat-icon">📦</div>
</div>
<div class="stat-value" x-text="stats.imports?.total_imports || 0"></div>
<div class="stat-subtitle">
<span x-text="stats.imports?.completed_imports || 0"></span> completed
</div>
</div>
</div>
<!-- Recent Vendors -->
<div class="content-section">
<div class="section-header">
<h2 class="section-title">Recent Vendors</h2>
<button class="btn-primary" @click="showSection('vendors')">View All</button>
</div>
<div x-show="loading && !recentVendors.length" class="loading">
<span class="loading-spinner loading-spinner-lg"></span>
<p class="loading-text">Loading recent vendors...</p>
</div>
<template x-if="!loading && recentVendors.length === 0">
<div class="empty-state">
<div class="empty-state-icon">🏪</div>
<h3>No Vendors Yet</h3>
<p>Create your first vendor to get started</p>
<button class="btn-primary mt-3" onclick="window.location.href='/admin/vendors.html'">
Create Vendor
</button>
</div>
</template>
<template x-if="recentVendors.length > 0">
<div class="table-responsive">
<table class="data-table">
<thead>
<tr>
<th>Vendor Code</th>
<th>Name</th>
<th>Subdomain</th>
<th>Status</th>
<th>Created</th>
</tr>
</thead>
<tbody>
<template x-for="vendor in recentVendors" :key="vendor.id">
<tr>
<td><strong x-text="vendor.vendor_code"></strong></td>
<td x-text="vendor.name"></td>
<td x-text="vendor.subdomain"></td>
<td>
<span class="badge"
:class="vendor.is_verified ? 'badge-success' : 'badge-warning'"
x-text="vendor.is_verified ? 'Verified' : 'Pending'"></span>
<span class="badge"
:class="vendor.is_active ? 'badge-success' : 'badge-danger'"
x-text="vendor.is_active ? 'Active' : 'Inactive'"></span>
</td>
<td x-text="formatDate(vendor.created_at)"></td>
</tr>
</template>
</tbody>
</table>
</div>
</template>
</div>
<!-- Recent Import Jobs -->
<div class="content-section">
<div class="section-header">
<h2 class="section-title">Recent Import Jobs</h2>
<button class="btn-primary" @click="showSection('imports')">View All</button>
</div>
<div x-show="loading && !recentImports.length" class="loading">
<span class="loading-spinner loading-spinner-lg"></span>
<p class="loading-text">Loading recent imports...</p>
</div>
<template x-if="!loading && recentImports.length === 0">
<div class="empty-state">
<div class="empty-state-icon">📦</div>
<h3>No Import Jobs Yet</h3>
<p>Import jobs will appear here once vendors start importing products</p>
</div>
</template>
<template x-if="recentImports.length > 0">
<div class="table-responsive">
<table class="data-table">
<thead>
<tr>
<th>ID</th>
<th>Marketplace</th>
<th>Vendor</th>
<th>Status</th>
<th>Processed</th>
<th>Created</th>
</tr>
</thead>
<tbody>
<template x-for="job in recentImports" :key="job.id">
<tr>
<td><strong x-text="'#' + job.id"></strong></td>
<td x-text="job.marketplace"></td>
<td x-text="job.vendor_name || '-'"></td>
<td>
<span class="badge"
:class="{
'badge-success': job.status === 'completed',
'badge-danger': job.status === 'failed',
'badge-warning': job.status !== 'completed' && job.status !== 'failed'
}"
x-text="job.status === 'completed' ? 'Completed' :
job.status === 'failed' ? 'Failed' : 'Processing'"></span>
</td>
<td x-text="job.total_processed || 0"></td>
<td x-text="formatDate(job.created_at)"></td>
</tr>
</template>
</tbody>
</table>
</div>
</template>
</div>
</div>
<!-- Vendors View -->
<div x-show="currentSection === 'vendors'">
<div class="content-section">
<div class="section-header">
<h2 class="section-title">Vendor Management</h2>
<a href="/admin/vendors.html" class="btn-primary">
Create New Vendor
</a>
</div>
<div x-show="loading" class="loading">
<span class="loading-spinner loading-spinner-lg"></span>
<p class="loading-text">Loading vendors...</p>
</div>
<template x-if="!loading && vendors.length === 0">
<div class="empty-state">
<div class="empty-state-icon">🏪</div>
<h3>No Vendors Found</h3>
<p>Get started by creating your first vendor</p>
<a href="/admin/vendors.html" class="btn-primary mt-3">
Create First Vendor
</a>
</div>
</template>
<template x-if="vendors.length > 0">
<div class="table-responsive">
<table class="data-table">
<thead>
<tr>
<th>ID</th>
<th>Vendor Code</th>
<th>Name</th>
<th>Subdomain</th>
<th>Email</th>
<th>Status</th>
<th>Created</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<template x-for="vendor in vendors" :key="vendor.id">
<tr>
<td x-text="vendor.id"></td>
<td><strong x-text="vendor.vendor_code"></strong></td>
<td x-text="vendor.name"></td>
<td x-text="vendor.subdomain"></td>
<td x-text="vendor.business_email || vendor.contact_email || '-'"></td>
<td>
<span class="badge"
:class="vendor.is_verified ? 'badge-success' : 'badge-warning'"
x-text="vendor.is_verified ? 'Verified' : 'Pending'"></span>
<span class="badge"
:class="vendor.is_active ? 'badge-success' : 'badge-danger'"
x-text="vendor.is_active ? 'Active' : 'Inactive'"></span>
</td>
<td x-text="formatDate(vendor.created_at)"></td>
<td>
<a :href="`/admin/vendor-edit.html?id=${vendor.id}`"
class="btn btn-sm btn-primary">
✏️ Edit
</a>
</td>
</tr>
</template>
</tbody>
</table>
</div>
</template>
</div>
</div>
<!-- Users View -->
<div x-show="currentSection === 'users'">
<div class="content-section">
<div class="section-header">
<h2 class="section-title">User Management</h2>
</div>
<div x-show="loading" class="loading">
<span class="loading-spinner loading-spinner-lg"></span>
<p class="loading-text">Loading users...</p>
</div>
<template x-if="!loading && users.length === 0">
<div class="empty-state">
<div class="empty-state-icon">👥</div>
<h3>No Users Found</h3>
<p>Users will appear here when vendors are created</p>
</div>
</template>
<template x-if="users.length > 0">
<div class="table-responsive">
<table class="data-table">
<thead>
<tr>
<th>ID</th>
<th>Username</th>
<th>Email</th>
<th>Role</th>
<th>Status</th>
<th>Created</th>
</tr>
</thead>
<tbody>
<template x-for="user in users" :key="user.id">
<tr>
<td x-text="user.id"></td>
<td><strong x-text="user.username"></strong></td>
<td x-text="user.email"></td>
<td>
<span class="badge badge-primary" x-text="user.role"></span>
</td>
<td>
<span class="badge"
:class="user.is_active ? 'badge-success' : 'badge-danger'"
x-text="user.is_active ? 'Active' : 'Inactive'"></span>
</td>
<td x-text="formatDate(user.created_at)"></td>
</tr>
</template>
</tbody>
</table>
</div>
</template>
</div>
</div>
<!-- Imports View -->
<div x-show="currentSection === 'imports'">
<div class="content-section">
<div class="section-header">
<h2 class="section-title">Import Jobs</h2>
</div>
<div x-show="loading" class="loading">
<span class="loading-spinner loading-spinner-lg"></span>
<p class="loading-text">Loading import jobs...</p>
</div>
<template x-if="!loading && imports.length === 0">
<div class="empty-state">
<div class="empty-state-icon">📦</div>
<h3>No Import Jobs Found</h3>
<p>Marketplace import jobs will appear here</p>
</div>
</template>
<template x-if="imports.length > 0">
<div class="table-responsive">
<table class="data-table">
<thead>
<tr>
<th>Job ID</th>
<th>Marketplace</th>
<th>Vendor</th>
<th>Status</th>
<th>Processed</th>
<th>Errors</th>
<th>Created</th>
</tr>
</thead>
<tbody>
<template x-for="job in imports" :key="job.id">
<tr>
<td><strong x-text="'#' + (job.job_id || job.id)"></strong></td>
<td x-text="job.marketplace"></td>
<td x-text="job.vendor_name || '-'"></td>
<td>
<span class="badge"
:class="{
'badge-success': job.status === 'completed',
'badge-danger': job.status === 'failed',
'badge-warning': job.status !== 'completed' && job.status !== 'failed'
}"
x-text="job.status === 'completed' ? 'Completed' :
job.status === 'failed' ? 'Failed' : 'Processing'"></span>
</td>
<td x-text="job.total_processed || 0"></td>
<td>
<span x-text="job.error_count || 0"
:class="{ 'text-danger': (job.error_count || 0) > 0 }"></span>
</td>
<td x-text="formatDate(job.created_at)"></td>
</tr>
</template>
</tbody>
</table>
</div>
</template>
</div>
</div>
</main>
<!-- Universal Modals (Injected from shared templates) -->
<div x-html="modalTemplates.confirmModal()"></div>
<div x-html="modalTemplates.successModal()"></div>
<div x-html="modalTemplates.errorModal()"></div>
<div x-html="modalTemplates.loadingOverlay()"></div>
<!-- Scripts -->
<script src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js" defer></script>
<script src="/static/js/shared/api-client.js"></script>
<script src="/static/js/shared/modal-templates.js"></script>
<script src="/static/js/shared/alpine-components.js"></script>
<script src="/static/js/shared/modal-system.js"></script>
<script src="/static/js/admin/admin-layout-templates.js"></script>
<script src="/static/js/admin/dashboard.js"></script>
<script>
// Initialize table scroll detection
document.addEventListener('alpine:init', () => {
// Wait for Alpine to finish rendering
setTimeout(() => {
const tables = document.querySelectorAll('.table-responsive');
tables.forEach(table => {
table.addEventListener('scroll', function() {
if (this.scrollLeft > 0) {
this.classList.add('is-scrolled');
} else {
this.classList.remove('is-scrolled');
}
});
});
}, 100);
});
</script>
</body>
</html>