test / index.html
dhung32's picture
Add 3 files
57d2dd1 verified
Raw
History Blame Contribute Delete
73.5 kB
<!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>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
.sidebar {
transition: all 0.3s;
}
.sidebar-collapsed {
width: 80px;
}
.sidebar-collapsed .sidebar-text {
display: none;
}
.sidebar-collapsed .sidebar-icon {
margin-right: 0;
}
.content-area {
transition: all 0.3s;
}
.content-expanded {
margin-left: 80px;
}
.active-nav {
background-color: #3B82F6;
color: white;
}
.active-nav:hover {
background-color: #3B82F6 !important;
}
.chart-container {
height: 300px;
}
[x-cloak] { display: none !important; }
</style>
</head>
<body class="bg-gray-100 font-sans">
<div x-data="adminApp()" x-cloak>
<!-- Sidebar -->
<div class="sidebar fixed inset-y-0 left-0 bg-gray-800 text-white w-64 overflow-y-auto z-50"
:class="{ 'sidebar-collapsed': sidebarCollapsed }">
<div class="p-4 flex items-center justify-between border-b border-gray-700">
<div class="flex items-center">
<i class="fas fa-shield-alt text-blue-400 text-2xl sidebar-icon"></i>
<span class="sidebar-text ml-3 text-xl font-bold">Admin Panel</span>
</div>
<button @click="toggleSidebar" class="text-gray-400 hover:text-white">
<i class="fas fa-bars"></i>
</button>
</div>
<nav class="mt-4">
<div class="px-4 py-2 text-gray-400 uppercase text-xs font-bold sidebar-text">
Main
</div>
<a href="#" @click="changeTab('dashboard')"
class="flex items-center px-4 py-3 text-gray-300 hover:bg-gray-700"
:class="{ 'active-nav': activeTab === 'dashboard' }">
<i class="fas fa-tachometer-alt sidebar-icon"></i>
<span class="sidebar-text ml-3">Dashboard</span>
</a>
<div class="px-4 py-2 text-gray-400 uppercase text-xs font-bold sidebar-text mt-4">
Management
</div>
<a href="#" @click="changeTab('users')"
class="flex items-center px-4 py-3 text-gray-300 hover:bg-gray-700"
:class="{ 'active-nav': activeTab === 'users' }">
<i class="fas fa-users sidebar-icon"></i>
<span class="sidebar-text ml-3">User Management</span>
</a>
<a href="#" @click="changeTab('orders')"
class="flex items-center px-4 py-3 text-gray-300 hover:bg-gray-700"
:class="{ 'active-nav': activeTab === 'orders' }">
<i class="fas fa-shopping-cart sidebar-icon"></i>
<span class="sidebar-text ml-3">Order Management</span>
</a>
<div class="px-4 py-2 text-gray-400 uppercase text-xs font-bold sidebar-text mt-4">
Reports
</div>
<a href="#" @click="changeTab('sales')"
class="flex items-center px-4 py-3 text-gray-300 hover:bg-gray-700"
:class="{ 'active-nav': activeTab === 'sales' }">
<i class="fas fa-chart-line sidebar-icon"></i>
<span class="sidebar-text ml-3">Sales Reports</span>
</a>
<a href="#" @click="changeTab('users-report')"
class="flex items-center px-4 py-3 text-gray-300 hover:bg-gray-700"
:class="{ 'active-nav': activeTab === 'users-report' }">
<i class="fas fa-user-chart sidebar-icon"></i>
<span class="sidebar-text ml-3">User Reports</span>
</a>
<div class="absolute bottom-0 w-full p-4 border-t border-gray-700">
<a href="#" class="flex items-center text-gray-300 hover:text-white">
<i class="fas fa-sign-out-alt sidebar-icon"></i>
<span class="sidebar-text ml-3">Logout</span>
</a>
</div>
</nav>
</div>
<!-- Main Content -->
<div class="content-area min-h-screen"
:class="{ 'content-expanded': sidebarCollapsed }">
<!-- Top Navigation -->
<header class="bg-white shadow-sm">
<div class="flex justify-between items-center px-6 py-4">
<h1 class="text-2xl font-bold text-gray-800" x-text="getTabTitle()"></h1>
<div class="flex items-center space-x-4">
<div class="relative">
<button class="text-gray-600 hover:text-gray-900">
<i class="fas fa-bell text-xl"></i>
<span class="absolute top-0 right-0 h-2 w-2 rounded-full bg-red-500"></span>
</button>
</div>
<div class="flex items-center">
<img src="https://randomuser.me/api/portraits/women/44.jpg"
class="h-8 w-8 rounded-full object-cover">
<span class="ml-2 font-medium">Admin User</span>
</div>
</div>
</div>
</header>
<!-- Content -->
<main class="p-6">
<!-- Dashboard Tab -->
<div x-show="activeTab === 'dashboard'" class="space-y-6">
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
<div class="bg-white rounded-lg shadow p-6">
<div class="flex items-center justify-between">
<div>
<p class="text-gray-500">Total Users</p>
<h3 class="text-2xl font-bold">1,248</h3>
</div>
<div class="bg-blue-100 p-3 rounded-full">
<i class="fas fa-users text-blue-500 text-xl"></i>
</div>
</div>
<p class="text-green-500 text-sm mt-2">
<i class="fas fa-arrow-up"></i> 12% from last month
</p>
</div>
<div class="bg-white rounded-lg shadow p-6">
<div class="flex items-center justify-between">
<div>
<p class="text-gray-500">Total Orders</p>
<h3 class="text-2xl font-bold">356</h3>
</div>
<div class="bg-green-100 p-3 rounded-full">
<i class="fas fa-shopping-cart text-green-500 text-xl"></i>
</div>
</div>
<p class="text-green-500 text-sm mt-2">
<i class="fas fa-arrow-up"></i> 5% from last month
</p>
</div>
<div class="bg-white rounded-lg shadow p-6">
<div class="flex items-center justify-between">
<div>
<p class="text-gray-500">Revenue</p>
<h3 class="text-2xl font-bold">$12,489</h3>
</div>
<div class="bg-purple-100 p-3 rounded-full">
<i class="fas fa-dollar-sign text-purple-500 text-xl"></i>
</div>
</div>
<p class="text-red-500 text-sm mt-2">
<i class="fas fa-arrow-down"></i> 2% from last month
</p>
</div>
<div class="bg-white rounded-lg shadow p-6">
<div class="flex items-center justify-between">
<div>
<p class="text-gray-500">Active Now</p>
<h3 class="text-2xl font-bold">43</h3>
</div>
<div class="bg-yellow-100 p-3 rounded-full">
<i class="fas fa-user-clock text-yellow-500 text-xl"></i>
</div>
</div>
<p class="text-green-500 text-sm mt-2">
<i class="fas fa-arrow-up"></i> 8% from last hour
</p>
</div>
</div>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
<div class="bg-white rounded-lg shadow p-6">
<h3 class="text-lg font-semibold mb-4">Recent Orders</h3>
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Order ID</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Customer</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Amount</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
<tr>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">#ORD-1001</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">John Smith</td>
<td class="px-6 py-4 whitespace-nowrap">
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800">Completed</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">$125.00</td>
</tr>
<tr>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">#ORD-1002</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">Sarah Johnson</td>
<td class="px-6 py-4 whitespace-nowrap">
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-yellow-100 text-yellow-800">Processing</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">$89.50</td>
</tr>
<tr>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">#ORD-1003</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">Michael Brown</td>
<td class="px-6 py-4 whitespace-nowrap">
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-blue-100 text-blue-800">Shipped</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">$234.00</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="bg-white rounded-lg shadow p-6">
<h3 class="text-lg font-semibold mb-4">Sales Overview</h3>
<div class="chart-container">
<canvas id="salesChart"></canvas>
</div>
</div>
</div>
</div>
<!-- User Management Tab -->
<div x-show="activeTab === 'users'" class="space-y-6">
<div class="flex justify-between items-center">
<h2 class="text-xl font-bold">User Management</h2>
<button @click="openUserModal('create')" class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-lg flex items-center">
<i class="fas fa-plus mr-2"></i> Add User
</button>
</div>
<div class="bg-white rounded-lg shadow overflow-hidden">
<div class="p-4 border-b border-gray-200 flex justify-between items-center">
<div class="relative w-64">
<input type="text" placeholder="Search users..."
class="w-full pl-10 pr-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
x-model="userSearchQuery" @input="searchUsers">
<i class="fas fa-search absolute left-3 top-3 text-gray-400"></i>
</div>
<div>
<select class="border rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
x-model="userFilterStatus" @change="filterUsers">
<option value="all">All Statuses</option>
<option value="active">Active</option>
<option value="inactive">Inactive</option>
<option value="suspended">Suspended</option>
</select>
</div>
</div>
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">User</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Email</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Role</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
<template x-for="user in filteredUsers" :key="user.id">
<tr>
<td class="px-6 py-4 whitespace-nowrap">
<div class="flex items-center">
<div class="flex-shrink-0 h-10 w-10">
<img class="h-10 w-10 rounded-full" :src="user.avatar" alt="">
</div>
<div class="ml-4">
<div class="text-sm font-medium text-gray-900" x-text="user.name"></div>
<div class="text-sm text-gray-500" x-text="'Joined ' + user.joinDate"></div>
</div>
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500" x-text="user.email"></td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500" x-text="user.role"></td>
<td class="px-6 py-4 whitespace-nowrap">
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full"
:class="{
'bg-green-100 text-green-800': user.status === 'active',
'bg-red-100 text-red-800': user.status === 'inactive',
'bg-yellow-100 text-yellow-800': user.status === 'suspended'
}"
x-text="user.status.charAt(0).toUpperCase() + user.status.slice(1)">
</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium">
<button @click="openUserModal('edit', user)" class="text-blue-600 hover:text-blue-900 mr-3">
<i class="fas fa-edit"></i>
</button>
<button @click="confirmDeleteUser(user)" class="text-red-600 hover:text-red-900">
<i class="fas fa-trash"></i>
</button>
</td>
</tr>
</template>
</tbody>
</table>
</div>
<div class="bg-gray-50 px-6 py-3 flex items-center justify-between border-t border-gray-200">
<div class="flex-1 flex justify-between sm:hidden">
<a href="#" class="relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50">
Previous
</a>
<a href="#" class="ml-3 relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50">
Next
</a>
</div>
<div class="hidden sm:flex-1 sm:flex sm:items-center sm:justify-between">
<div>
<p class="text-sm text-gray-700">
Showing <span class="font-medium" x-text="currentPage"></span> to <span class="font-medium" x-text="Math.min(currentPage + 5, totalPages)"></span> of <span class="font-medium" x-text="totalUsers"></span> users
</p>
</div>
<div>
<nav class="relative z-0 inline-flex rounded-md shadow-sm -space-x-px" aria-label="Pagination">
<a href="#" class="relative inline-flex items-center px-2 py-2 rounded-l-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50">
<span class="sr-only">Previous</span>
<i class="fas fa-chevron-left"></i>
</a>
<template x-for="page in visiblePages" :key="page">
<a href="#" @click="changePage(page)"
class="relative inline-flex items-center px-4 py-2 border border-gray-300 bg-white text-sm font-medium"
:class="{
'text-blue-600 bg-blue-50': currentPage === page,
'text-gray-700 hover:bg-gray-50': currentPage !== page
}"
x-text="page">
</a>
</template>
<a href="#" class="relative inline-flex items-center px-2 py-2 rounded-r-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50">
<span class="sr-only">Next</span>
<i class="fas fa-chevron-right"></i>
</a>
</nav>
</div>
</div>
</div>
</div>
</div>
<!-- Order Management Tab -->
<div x-show="activeTab === 'orders'" class="space-y-6">
<div class="flex justify-between items-center">
<h2 class="text-xl font-bold">Order Management</h2>
<div class="flex space-x-2">
<button class="bg-gray-200 hover:bg-gray-300 text-gray-800 px-4 py-2 rounded-lg flex items-center">
<i class="fas fa-filter mr-2"></i> Filter
</button>
<button class="bg-gray-200 hover:bg-gray-300 text-gray-800 px-4 py-2 rounded-lg flex items-center">
<i class="fas fa-download mr-2"></i> Export
</button>
</div>
</div>
<div class="bg-white rounded-lg shadow overflow-hidden">
<div class="p-4 border-b border-gray-200 flex justify-between items-center">
<div class="relative w-64">
<input type="text" placeholder="Search orders..."
class="w-full pl-10 pr-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
<i class="fas fa-search absolute left-3 top-3 text-gray-400"></i>
</div>
<div>
<select class="border rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500">
<option>All Statuses</option>
<option>Pending</option>
<option>Processing</option>
<option>Shipped</option>
<option>Completed</option>
<option>Cancelled</option>
</select>
</div>
</div>
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Order ID</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Customer</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Date</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Amount</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
<tr>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">#ORD-1001</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="flex items-center">
<div class="flex-shrink-0 h-10 w-10">
<img class="h-10 w-10 rounded-full" src="https://randomuser.me/api/portraits/men/32.jpg" alt="">
</div>
<div class="ml-4">
<div class="text-sm font-medium text-gray-900">John Smith</div>
<div class="text-sm text-gray-500">john@example.com</div>
</div>
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">May 15, 2023</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">$125.00</td>
<td class="px-6 py-4 whitespace-nowrap">
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800">Completed</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium">
<button class="text-blue-600 hover:text-blue-900 mr-3">
<i class="fas fa-eye"></i>
</button>
<button class="text-yellow-600 hover:text-yellow-900 mr-3">
<i class="fas fa-edit"></i>
</button>
<button class="text-red-600 hover:text-red-900">
<i class="fas fa-trash"></i>
</button>
</td>
</tr>
<tr>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">#ORD-1002</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="flex items-center">
<div class="flex-shrink-0 h-10 w-10">
<img class="h-10 w-10 rounded-full" src="https://randomuser.me/api/portraits/women/44.jpg" alt="">
</div>
<div class="ml-4">
<div class="text-sm font-medium text-gray-900">Sarah Johnson</div>
<div class="text-sm text-gray-500">sarah@example.com</div>
</div>
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">May 14, 2023</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">$89.50</td>
<td class="px-6 py-4 whitespace-nowrap">
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-yellow-100 text-yellow-800">Processing</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium">
<button class="text-blue-600 hover:text-blue-900 mr-3">
<i class="fas fa-eye"></i>
</button>
<button class="text-yellow-600 hover:text-yellow-900 mr-3">
<i class="fas fa-edit"></i>
</button>
<button class="text-red-600 hover:text-red-900">
<i class="fas fa-trash"></i>
</button>
</td>
</tr>
<tr>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">#ORD-1003</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="flex items-center">
<div class="flex-shrink-0 h-10 w-10">
<img class="h-10 w-10 rounded-full" src="https://randomuser.me/api/portraits/men/75.jpg" alt="">
</div>
<div class="ml-4">
<div class="text-sm font-medium text-gray-900">Michael Brown</div>
<div class="text-sm text-gray-500">michael@example.com</div>
</div>
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">May 12, 2023</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">$234.00</td>
<td class="px-6 py-4 whitespace-nowrap">
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-blue-100 text-blue-800">Shipped</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium">
<button class="text-blue-600 hover:text-blue-900 mr-3">
<i class="fas fa-eye"></i>
</button>
<button class="text-yellow-600 hover:text-yellow-900 mr-3">
<i class="fas fa-edit"></i>
</button>
<button class="text-red-600 hover:text-red-900">
<i class="fas fa-trash"></i>
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- Sales Reports Tab -->
<div x-show="activeTab === 'sales'" class="space-y-6">
<div class="flex justify-between items-center">
<h2 class="text-xl font-bold">Sales Reports</h2>
<div class="flex space-x-2">
<select class="border rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500">
<option>Last 7 days</option>
<option>Last 30 days</option>
<option>Last 90 days</option>
<option>This year</option>
<option>Custom range</option>
</select>
<button class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-lg flex items-center">
<i class="fas fa-download mr-2"></i> Export
</button>
</div>
</div>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
<div class="bg-white rounded-lg shadow p-6">
<h3 class="text-lg font-semibold mb-4">Sales Overview</h3>
<div class="chart-container">
<canvas id="detailedSalesChart"></canvas>
</div>
</div>
<div class="bg-white rounded-lg shadow p-6">
<h3 class="text-lg font-semibold mb-4">Revenue by Category</h3>
<div class="chart-container">
<canvas id="categoryChart"></canvas>
</div>
</div>
</div>
<div class="bg-white rounded-lg shadow overflow-hidden">
<div class="p-4 border-b border-gray-200">
<h3 class="text-lg font-semibold">Detailed Sales Data</h3>
</div>
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Date</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Orders</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Revenue</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Avg. Order</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Conversion</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
<tr>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">May 15, 2023</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">24</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">$1,245.00</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">$51.88</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">3.2%</td>
</tr>
<tr>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">May 14, 2023</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">18</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">$876.50</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">$48.69</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">2.8%</td>
</tr>
<tr>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">May 13, 2023</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">15</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">$721.00</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">$48.07</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">2.5%</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- User Reports Tab -->
<div x-show="activeTab === 'users-report'" class="space-y-6">
<div class="flex justify-between items-center">
<h2 class="text-xl font-bold">User Reports</h2>
<div class="flex space-x-2">
<select class="border rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500">
<option>Last 7 days</option>
<option>Last 30 days</option>
<option>Last 90 days</option>
<option>This year</option>
<option>Custom range</option>
</select>
<button class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-lg flex items-center">
<i class="fas fa-download mr-2"></i> Export
</button>
</div>
</div>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
<div class="bg-white rounded-lg shadow p-6">
<h3 class="text-lg font-semibold mb-4">User Growth</h3>
<div class="chart-container">
<canvas id="userGrowthChart"></canvas>
</div>
</div>
<div class="bg-white rounded-lg shadow p-6">
<h3 class="text-lg font-semibold mb-4">User Activity</h3>
<div class="chart-container">
<canvas id="userActivityChart"></canvas>
</div>
</div>
</div>
<div class="bg-white rounded-lg shadow overflow-hidden">
<div class="p-4 border-b border-gray-200">
<h3 class="text-lg font-semibold">Top Users</h3>
</div>
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">User</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Orders</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Total Spent</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Last Active</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
<tr>
<td class="px-6 py-4 whitespace-nowrap">
<div class="flex items-center">
<div class="flex-shrink-0 h-10 w-10">
<img class="h-10 w-10 rounded-full" src="https://randomuser.me/api/portraits/men/32.jpg" alt="">
</div>
<div class="ml-4">
<div class="text-sm font-medium text-gray-900">John Smith</div>
<div class="text-sm text-gray-500">john@example.com</div>
</div>
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">12</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">$589.00</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">2 hours ago</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium">
<button class="text-blue-600 hover:text-blue-900 mr-3">
<i class="fas fa-eye"></i>
</button>
<button class="text-yellow-600 hover:text-yellow-900">
<i class="fas fa-envelope"></i>
</button>
</td>
</tr>
<tr>
<td class="px-6 py-4 whitespace-nowrap">
<div class="flex items-center">
<div class="flex-shrink-0 h-10 w-10">
<img class="h-10 w-10 rounded-full" src="https://randomuser.me/api/portraits/women/44.jpg" alt="">
</div>
<div class="ml-4">
<div class="text-sm font-medium text-gray-900">Sarah Johnson</div>
<div class="text-sm text-gray-500">sarah@example.com</div>
</div>
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">8</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">$421.50</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">1 day ago</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium">
<button class="text-blue-600 hover:text-blue-900 mr-3">
<i class="fas fa-eye"></i>
</button>
<button class="text-yellow-600 hover:text-yellow-900">
<i class="fas fa-envelope"></i>
</button>
</td>
</tr>
<tr>
<td class="px-6 py-4 whitespace-nowrap">
<div class="flex items-center">
<div class="flex-shrink-0 h-10 w-10">
<img class="h-10 w-10 rounded-full" src="https://randomuser.me/api/portraits/men/75.jpg" alt="">
</div>
<div class="ml-4">
<div class="text-sm font-medium text-gray-900">Michael Brown</div>
<div class="text-sm text-gray-500">michael@example.com</div>
</div>
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">6</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">$356.00</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">3 days ago</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium">
<button class="text-blue-600 hover:text-blue-900 mr-3">
<i class="fas fa-eye"></i>
</button>
<button class="text-yellow-600 hover:text-yellow-900">
<i class="fas fa-envelope"></i>
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</main>
</div>
<!-- User Modal -->
<div x-show="showUserModal" class="fixed inset-0 overflow-y-auto z-50" x-cloak>
<div class="flex items-center justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
<div class="fixed inset-0 transition-opacity" aria-hidden="true">
<div class="absolute inset-0 bg-gray-500 opacity-75"></div>
</div>
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">&#8203;</span>
<div class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full">
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
<h3 class="text-lg leading-6 font-medium text-gray-900 mb-4" x-text="userModalMode === 'create' ? 'Add New User' : 'Edit User'"></h3>
<div class="space-y-4">
<div>
<label for="userName" class="block text-sm font-medium text-gray-700">Full Name</label>
<input type="text" id="userName" x-model="currentUser.name" class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm">
</div>
<div>
<label for="userEmail" class="block text-sm font-medium text-gray-700">Email</label>
<input type="email" id="userEmail" x-model="currentUser.email" class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm">
</div>
<div>
<label for="userRole" class="block text-sm font-medium text-gray-700">Role</label>
<select id="userRole" x-model="currentUser.role" class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm">
<option>Admin</option>
<option>Editor</option>
<option>User</option>
</select>
</div>
<div>
<label for="userStatus" class="block text-sm font-medium text-gray-700">Status</label>
<select id="userStatus" x-model="currentUser.status" class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm">
<option>active</option>
<option>inactive</option>
<option>suspended</option>
</select>
</div>
<div x-show="userModalMode === 'create'">
<label for="userPassword" class="block text-sm font-medium text-gray-700">Password</label>
<input type="password" id="userPassword" x-model="currentUser.password" class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm">
</div>
</div>
</div>
<div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
<button type="button" @click="saveUser" class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm">
Save
</button>
<button type="button" @click="closeUserModal" class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm">
Cancel
</button>
</div>
</div>
</div>
</div>
<!-- Delete Confirmation Modal -->
<div x-show="showDeleteModal" class="fixed inset-0 overflow-y-auto z-50" x-cloak>
<div class="flex items-center justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
<div class="fixed inset-0 transition-opacity" aria-hidden="true">
<div class="absolute inset-0 bg-gray-500 opacity-75"></div>
</div>
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">&#8203;</span>
<div class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full">
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
<div class="sm:flex sm:items-start">
<div class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-red-100 sm:mx-0 sm:h-10 sm:w-10">
<i class="fas fa-exclamation-triangle text-red-600"></i>
</div>
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<h3 class="text-lg leading-6 font-medium text-gray-900">Delete User</h3>
<div class="mt-2">
<p class="text-sm text-gray-500">Are you sure you want to delete this user? This action cannot be undone.</p>
</div>
</div>
</div>
</div>
<div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
<button type="button" @click="deleteUser" class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm">
Delete
</button>
<button type="button" @click="closeDeleteModal" class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm">
Cancel
</button>
</div>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js" defer></script>
<script>
function adminApp() {
return {
sidebarCollapsed: false,
activeTab: 'dashboard',
showUserModal: false,
showDeleteModal: false,
userModalMode: 'create',
userSearchQuery: '',
userFilterStatus: 'all',
currentPage: 1,
totalPages: 10,
totalUsers: 100,
currentUser: {
id: '',
name: '',
email: '',
role: 'User',
status: 'active',
password: '',
avatar: '',
joinDate: ''
},
userToDelete: null,
users: [
{
id: 1,
name: 'John Smith',
email: 'john@example.com',
role: 'Admin',
status: 'active',
avatar: 'https://randomuser.me/api/portraits/men/32.jpg',
joinDate: 'May 12, 2022'
},
{
id: 2,
name: 'Sarah Johnson',
email: 'sarah@example.com',
role: 'Editor',
status: 'active',
avatar: 'https://randomuser.me/api/portraits/women/44.jpg',
joinDate: 'June 5, 2022'
},
{
id: 3,
name: 'Michael Brown',
email: 'michael@example.com',
role: 'User',
status: 'active',
avatar: 'https://randomuser.me/api/portraits/men/75.jpg',
joinDate: 'July 18, 2022'
},
{
id: 4,
name: 'Emily Davis',
email: 'emily@example.com',
role: 'User',
status: 'inactive',
avatar: 'https://randomuser.me/api/portraits/women/68.jpg',
joinDate: 'August 3, 2022'
},
{
id: 5,
name: 'Robert Wilson',
email: 'robert@example.com',
role: 'User',
status: 'suspended',
avatar: 'https://randomuser.me/api/portraits/men/86.jpg',
joinDate: 'September 22, 2022'
}
],
get filteredUsers() {
let filtered = this.users;
// Apply search filter
if (this.userSearchQuery) {
const query = this.userSearchQuery.toLowerCase();
filtered = filtered.filter(user =>
user.name.toLowerCase().includes(query) ||
user.email.toLowerCase().includes(query)
);
}
// Apply status filter
if (this.userFilterStatus !== 'all') {
filtered = filtered.filter(user => user.status === this.userFilterStatus);
}
return filtered;
},
get visiblePages() {
const pages = [];
const startPage = Math.max(1, this.currentPage - 2);
const endPage = Math.min(this.totalPages, startPage + 4);
for (let i = startPage; i <= endPage; i++) {
pages.push(i);
}
return pages;
},
toggleSidebar() {
this.sidebarCollapsed = !this.sidebarCollapsed;
},
changeTab(tab) {
this.activeTab = tab;
// Initialize charts when tab is shown
if (tab === 'dashboard') {
this.$nextTick(() => {
this.initDashboardCharts();
});
} else if (tab === 'sales') {
this.$nextTick(() => {
this.initSalesCharts();
});
} else if (tab === 'users-report') {
this.$nextTick(() => {
this.initUserReportCharts();
});
}
},
getTabTitle() {
const titles = {
'dashboard': 'Dashboard',
'users': 'User Management',
'orders': 'Order Management',
'sales': 'Sales Reports',
'users-report': 'User Reports'
};
return titles[this.activeTab] || 'Dashboard';
},
openUserModal(mode, user = null) {
this.userModalMode = mode;
if (mode === 'edit' && user) {
this.currentUser = {...user};
} else {
// Reset for new user
this.currentUser = {
id: '',
name: '',
email: '',
role: 'User',
status: 'active',
password: '',
avatar: 'https://randomuser.me/api/portraits/lego/1.jpg',
joinDate: new Date().toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' })
};
}
this.showUserModal = true;
},
closeUserModal() {
this.showUserModal = false;
},
saveUser() {
if (this.userModalMode === 'create') {
// Add new user
const newId = Math.max(...this.users.map(u => u.id)) + 1;
this.users.unshift({
...this.currentUser,
id: newId
});
addLog(`Created new user: ${this.currentUser.name}`);
} else {
// Update existing user
const index = this.users.findIndex(u => u.id === this.currentUser.id);
if (index !== -1) {
this.users[index] = {...this.currentUser};
}
addLog(`Updated user: ${this.currentUser.name}`);
}
this.closeUserModal();
},
confirmDeleteUser(user) {
this.userToDelete = user;
this.showDeleteModal = true;
},
closeDeleteModal() {
this.showDeleteModal = false;
this.userToDelete = null;
},
deleteUser() {
if (this.userToDelete) {
this.users = this.users.filter(u => u.id !== this.userToDelete.id);
addLog(`Deleted user: ${this.userToDelete.name}`);
this.closeDeleteModal();
}
},
searchUsers() {
// The filteredUsers computed property handles this
},
filterUsers() {
// The filteredUsers computed property handles this
},
changePage(page) {
this.currentPage = page;
},
initDashboardCharts() {
// Sales Chart
const salesCtx = document.getElementById('salesChart').getContext('2d');
new Chart(salesCtx, {
type: 'line',
data: {
labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'],
datasets: [{
label: 'Sales',
data: [12000, 19000, 15000, 18000, 12000, 19000],
backgroundColor: 'rgba(59, 130, 246, 0.1)',
borderColor: 'rgba(59, 130, 246, 1)',
borderWidth: 2,
tension: 0.4,
fill: true
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false
}
},
scales: {
y: {
beginAtZero: true
}
}
}
});
},
initSalesCharts() {
// Detailed Sales Chart
const detailedSalesCtx = document.getElementById('detailedSalesChart').getContext('2d');
new Chart(detailedSalesCtx, {
type: 'bar',
data: {
labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
datasets: [{
label: 'Revenue',
data: [2100, 3200, 2800, 3500, 4200, 3800, 2900],
backgroundColor: 'rgba(59, 130, 246, 0.7)'
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false
}
},
scales: {
y: {
beginAtZero: true
}
}
}
});
// Category Chart
const categoryCtx = document.getElementById('categoryChart').getContext('2d');
new Chart(categoryCtx, {
type: 'doughnut',
data: {
labels: ['Electronics', 'Clothing', 'Home', 'Books', 'Other'],
datasets: [{
data: [35, 25, 20, 10, 10],
backgroundColor: [
'rgba(59, 130, 246, 0.7)',
'rgba(16, 185, 129, 0.7)',
'rgba(245, 158, 11, 0.7)',
'rgba(139, 92, 246, 0.7)',
'rgba(156, 163, 175, 0.7)'
]
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'right'
}
}
}
});
},
initUserReportCharts() {
// User Growth Chart
const userGrowthCtx = document.getElementById('userGrowthChart').getContext('2d');
new Chart(userGrowthCtx, {
type: 'line',
data: {
labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May'],
datasets: [{
label: 'New Users',
data: [120, 190, 150, 180, 220],
backgroundColor: 'rgba(16, 185, 129, 0.1)',
borderColor: 'rgba(16, 185, 129, 1)',
borderWidth: 2,
tension: 0.4,
fill: true
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false
}
},
scales: {
y: {
beginAtZero: true
}
}
}
});
// User Activity Chart
const userActivityCtx = document.getElementById('userActivityChart').getContext('2d');
new Chart(userActivityCtx, {
type: 'bar',
data: {
labels: ['Active', 'Inactive', 'Suspended'],
datasets: [{
label: 'Users',
data: [850, 120, 30],
backgroundColor: [
'rgba(16, 185, 129, 0.7)',
'rgba(156, 163, 175, 0.7)',
'rgba(239, 68, 68, 0.7)'
]
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false
}
},
scales: {
y: {
beginAtZero: true
}
}
}
});
}
};
}
function addLog(message) {
const logElement = document.createElement('p');
logElement.textContent = message;
document.getElementById('gameLog').appendChild(logElement);
document.getElementById('gameLog').scrollTop = document.getElementById('gameLog').scrollHeight;
}
// Initialize dashboard charts when page loads
document.addEventListener('DOMContentLoaded', function() {
const app = document.querySelector('[x-data="adminApp()"]');
const alpine = Alpine.getRootComponent(app);
alpine.initDashboardCharts();
});
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=dhung32/test" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>