frontend fixed and good

This commit is contained in:
HotSwapp
2025-08-11 10:26:41 -05:00
parent 1512b2d12a
commit 88501a8891
10 changed files with 616 additions and 223 deletions

View File

@@ -1,208 +1,420 @@
{% extends "base.html" %}
{% block title %}System Administration{% endblock %}
{% block title %}System Administration - Delphi Database{% endblock %}
{% block bridge_css %}{% endblock %}
{% block content %}
<div class="max-w-full px-4 sm:px-6 lg:px-8">
<div class="flex flex-wrap -mx-4 mb-6">
<div class="w-full md:w-1/4 px-4 mb-4">
<div class="bg-white dark:bg-neutral-800 rounded-lg shadow border border-primary-200 dark:border-primary-700">
<div class="p-4 text-center">
<div id="system-status" class="text-4xl mb-2">
<i class="fas fa-circle text-success"></i>
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
<!-- Page Header -->
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4 mb-8">
<div class="flex items-center gap-3">
<div class="flex items-center justify-center w-12 h-12 bg-primary-100 dark:bg-primary-800 text-primary-600 dark:text-primary-400 rounded-xl">
<i class="fa-solid fa-shield-halved text-xl"></i>
</div>
<div>
<h1 class="text-3xl font-bold text-neutral-900 dark:text-neutral-100">System Administration</h1>
<p class="text-neutral-600 dark:text-neutral-400">Manage users, settings, and system operations</p>
</div>
</div>
<div class="flex items-center gap-2">
<button id="refreshStatsBtn" class="flex items-center gap-2 px-4 py-2 bg-neutral-100 dark:bg-neutral-700 text-neutral-700 dark:text-neutral-300 hover:bg-neutral-200 dark:hover:bg-neutral-600 rounded-lg transition-colors duration-200">
<i class="fa-solid fa-rotate-right"></i>
<span>Refresh</span>
</button>
<div class="flex items-center gap-2 px-3 py-2 bg-green-50 dark:bg-green-900/20 text-green-700 dark:text-green-400 rounded-lg border border-green-200 dark:border-green-800">
<div class="w-2 h-2 bg-green-500 rounded-full animate-pulse"></div>
<span class="text-sm font-medium">System Online</span>
</div>
</div>
</div>
<!-- Enhanced Stats Cards -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
<!-- System Status Card -->
<div class="bg-white dark:bg-neutral-900 rounded-xl shadow-sm dark:shadow-none border border-neutral-200 dark:border-neutral-700 hover:shadow-md dark:hover:shadow-lg dark:hover:shadow-black/20 transition-all duration-200">
<div class="p-6">
<div class="flex items-center justify-between mb-4">
<div class="flex items-center justify-center w-12 h-12 bg-green-100 dark:bg-green-800 text-green-600 dark:text-green-300 rounded-lg">
<i class="fa-solid fa-heart-pulse text-xl"></i>
</div>
<div id="system-status" class="text-2xl">
<i class="fas fa-circle text-green-500"></i>
</div>
</div>
<div>
<h3 class="text-sm font-medium text-neutral-600 dark:text-neutral-300 uppercase tracking-wide">System Status</h3>
<p class="text-2xl font-bold text-neutral-900 dark:text-white mt-1" id="system-status-text">Healthy</p>
<div class="mt-2 flex items-center text-xs text-green-600 dark:text-green-400">
<i class="fa-solid fa-arrow-up mr-1"></i>
<span>All systems operational</span>
</div>
<h6 class="text-sm font-semibold mb-0">System Status</h6>
<p class="text-xs" id="system-status-text">Healthy</p>
</div>
</div>
</div>
<div class="w-full md:w-1/4 px-4 mb-4">
<div class="bg-white dark:bg-neutral-800 rounded-lg shadow border border-info-300 dark:border-info-700">
<div class="p-4 text-center">
<div class="text-4xl mb-2">
<i class="fas fa-users"></i>
<!-- Users Card -->
<div class="bg-white dark:bg-neutral-900 rounded-xl shadow-sm dark:shadow-none border border-neutral-200 dark:border-neutral-700 hover:shadow-md dark:hover:shadow-lg dark:hover:shadow-black/20 transition-all duration-200">
<div class="p-6">
<div class="flex items-center justify-between mb-4">
<div class="flex items-center justify-center w-12 h-12 bg-blue-100 dark:bg-blue-800 text-blue-600 dark:text-blue-300 rounded-lg">
<i class="fa-solid fa-users text-xl"></i>
</div>
<button class="text-neutral-400 hover:text-neutral-600 dark:text-neutral-500 dark:hover:text-neutral-300" onclick="openTab(event, 'users')">
<i class="fa-solid fa-external-link"></i>
</button>
</div>
<div>
<h3 class="text-sm font-medium text-neutral-600 dark:text-neutral-300 uppercase tracking-wide">Total Users</h3>
<p class="text-3xl font-bold text-neutral-900 dark:text-white mt-1" id="total-users">0</p>
<div class="mt-2 flex items-center text-xs text-blue-600 dark:text-blue-400">
<span id="active-users-count">0 active</span>
</div>
<h6 class="text-sm font-semibold">Total Users</h6>
<p class="text-2xl font-semibold" id="total-users">0</p>
</div>
</div>
</div>
<div class="w-full md:w-1/4 px-4 mb-4">
<div class="bg-white dark:bg-neutral-800 rounded-lg shadow border border-warning-300 dark:border-warning-700">
<div class="p-4 text-center">
<div class="text-4xl mb-2">
<i class="fas fa-database"></i>
<!-- Database Card -->
<div class="bg-white dark:bg-neutral-900 rounded-xl shadow-sm dark:shadow-none border border-neutral-200 dark:border-neutral-700 hover:shadow-md dark:hover:shadow-lg dark:hover:shadow-black/20 transition-all duration-200">
<div class="p-6">
<div class="flex items-center justify-between mb-4">
<div class="flex items-center justify-center w-12 h-12 bg-purple-100 dark:bg-purple-800 text-purple-600 dark:text-purple-300 rounded-lg">
<i class="fa-solid fa-database text-xl"></i>
</div>
<button class="text-neutral-400 hover:text-neutral-600 dark:text-neutral-500 dark:hover:text-neutral-300" onclick="openTab(event, 'maintenance')">
<i class="fa-solid fa-external-link"></i>
</button>
</div>
<div>
<h3 class="text-sm font-medium text-neutral-600 dark:text-neutral-300 uppercase tracking-wide">Database Size</h3>
<p class="text-2xl font-bold text-neutral-900 dark:text-white mt-1" id="db-size">0 MB</p>
<div class="mt-2 flex items-center text-xs text-purple-600 dark:text-purple-400">
<span id="db-growth">+0% this week</span>
</div>
<h6 class="text-sm font-semibold">Database Size</h6>
<p class="text-base" id="db-size">0 MB</p>
</div>
</div>
</div>
<div class="w-full md:w-1/4 px-4 mb-4">
<div class="bg-white dark:bg-neutral-800 rounded-lg shadow border border-success-300 dark:border-success-700">
<div class="p-4 text-center">
<div class="text-4xl mb-2">
<i class="fas fa-clock"></i>
<!-- Uptime Card -->
<div class="bg-white dark:bg-neutral-900 rounded-xl shadow-sm dark:shadow-none border border-neutral-200 dark:border-neutral-700 hover:shadow-md dark:hover:shadow-lg dark:hover:shadow-black/20 transition-all duration-200">
<div class="p-6">
<div class="flex items-center justify-between mb-4">
<div class="flex items-center justify-center w-12 h-12 bg-amber-100 dark:bg-amber-800 text-amber-600 dark:text-amber-300 rounded-lg">
<i class="fa-solid fa-clock text-xl"></i>
</div>
<div class="text-xs text-neutral-500 dark:text-neutral-400">
99.9% uptime
</div>
</div>
<div>
<h3 class="text-sm font-medium text-neutral-600 dark:text-neutral-300 uppercase tracking-wide">System Uptime</h3>
<p class="text-xl font-bold text-neutral-900 dark:text-white mt-1" id="system-uptime">Unknown</p>
<div class="mt-2 flex items-center text-xs text-amber-600 dark:text-amber-400">
<span>Last restart: Never</span>
</div>
<h6 class="text-sm font-semibold">System Uptime</h6>
<p class="text-xs" id="system-uptime">Unknown</p>
</div>
</div>
</div>
</div>
<!-- Main Navigation Tabs -->
<ul id="adminTabs" class="flex border-b border-neutral-200 dark:border-neutral-700 mb-6" role="tablist">
<li class="px-4 py-2 -mb-px border-b-2 border-transparent hover:border-primary-600 text-neutral-600 dark:text-neutral-400 hover:text-primary-600 dark:hover:text-primary-400 transition-colors active" id="overview-tab" data-tab-target="#overview" type="button" role="tab">
<i class="fas fa-tachometer-alt"></i> Overview
</li>
<li class="px-4 py-2 -mb-px border-b-2 border-transparent hover:border-primary-600 text-neutral-600 dark:text-neutral-400 hover:text-primary-600 dark:hover:text-primary-400 transition-colors" id="users-tab" data-tab-target="#users" type="button" role="tab">
<i class="fas fa-users"></i> User Management
</li>
<li class="px-4 py-2 -mb-px border-b-2 border-transparent hover:border-primary-600 text-neutral-600 dark:text-neutral-400 hover:text-primary-600 dark:hover:text-primary-400 transition-colors" id="settings-tab" data-tab-target="#settings" type="button" role="tab">
<i class="fas fa-sliders-h"></i> System Settings
</li>
<li class="px-4 py-2 -mb-px border-b-2 border-transparent hover:border-primary-600 text-neutral-600 dark:text-neutral-400 hover:text-primary-600 dark:hover:text-primary-400 transition-colors" id="maintenance-tab" data-tab-target="#maintenance" type="button" role="tab">
<i class="fas fa-tools"></i> Maintenance
</li>
<li class="px-4 py-2 -mb-px border-b-2 border-transparent hover:border-primary-600 text-neutral-600 dark:text-neutral-400 hover:text-primary-600 dark:hover:text-primary-400 transition-colors" id="issues-tab" data-tab-target="#issues" type="button" role="tab">
<i class="fas fa-bug"></i> Issue Tracking
</li>
<li class="px-4 py-2 -mb-px border-b-2 border-transparent hover:border-primary-600 text-neutral-600 dark:text-neutral-400 hover:text-primary-600 dark:hover:text-primary-400 transition-colors" id="import-tab" data-tab-target="#import" type="button" role="tab">
<i class="fa-solid fa-upload"></i> Data Import
</li>
<li class="px-4 py-2 -mb-px border-b-2 border-transparent hover:border-primary-600 text-neutral-600 dark:text-neutral-400 hover:text-primary-600 dark:hover:text-primary-400 transition-colors" id="backup-tab" data-tab-target="#backup" type="button" role="tab">
<i class="fas fa-hdd"></i> Backup & Restore
</li>
</ul>
<!-- Modern Navigation Tabs -->
<div class="bg-white dark:bg-neutral-900 rounded-xl shadow-sm dark:shadow-none border border-neutral-200 dark:border-neutral-700 mb-8">
<nav class="flex flex-wrap border-b border-neutral-200 dark:border-neutral-700" role="tablist">
<button class="flex items-center gap-2 px-6 py-4 text-sm font-medium border-b-2 border-primary-600 text-primary-600 dark:text-primary-400 bg-primary-50 dark:bg-primary-900/20 transition-all duration-200 rounded-t-xl active" id="overview-tab" data-tab-target="#overview" type="button" role="tab">
<i class="fa-solid fa-chart-line"></i>
<span>Overview</span>
</button>
<button class="flex items-center gap-2 px-6 py-4 text-sm font-medium border-b-2 border-transparent hover:border-primary-300 text-neutral-600 dark:text-neutral-400 hover:text-primary-600 dark:hover:text-primary-400 hover:bg-neutral-50 dark:hover:bg-neutral-700/50 transition-all duration-200" id="users-tab" data-tab-target="#users" type="button" role="tab">
<i class="fa-solid fa-users-gear"></i>
<span>Users</span>
<span class="ml-1 px-2 py-0.5 bg-blue-100 dark:bg-blue-800 text-blue-700 dark:text-blue-400 text-xs rounded-full" id="users-badge">0</span>
</button>
<button class="flex items-center gap-2 px-6 py-4 text-sm font-medium border-b-2 border-transparent hover:border-primary-300 text-neutral-600 dark:text-neutral-400 hover:text-primary-600 dark:hover:text-primary-400 hover:bg-neutral-50 dark:hover:bg-neutral-700/50 transition-all duration-200" id="settings-tab" data-tab-target="#settings" type="button" role="tab">
<i class="fa-solid fa-sliders"></i>
<span>Settings</span>
</button>
<button class="flex items-center gap-2 px-6 py-4 text-sm font-medium border-b-2 border-transparent hover:border-primary-300 text-neutral-600 dark:text-neutral-400 hover:text-primary-600 dark:hover:text-primary-400 hover:bg-neutral-50 dark:hover:bg-neutral-700/50 transition-all duration-200" id="maintenance-tab" data-tab-target="#maintenance" type="button" role="tab">
<i class="fa-solid fa-wrench"></i>
<span>Maintenance</span>
</button>
<button class="flex items-center gap-2 px-6 py-4 text-sm font-medium border-b-2 border-transparent hover:border-primary-300 text-neutral-600 dark:text-neutral-400 hover:text-primary-600 dark:hover:text-primary-400 hover:bg-neutral-50 dark:hover:bg-neutral-700/50 transition-all duration-200" id="import-tab" data-tab-target="#import" type="button" role="tab">
<i class="fa-solid fa-file-import"></i>
<span>Import</span>
</button>
<button class="flex items-center gap-2 px-6 py-4 text-sm font-medium border-b-2 border-transparent hover:border-primary-300 text-neutral-600 dark:text-neutral-400 hover:text-primary-600 dark:hover:text-primary-400 hover:bg-neutral-50 dark:hover:bg-neutral-700/50 transition-all duration-200" id="backup-tab" data-tab-target="#backup" type="button" role="tab">
<i class="fa-solid fa-shield-halved"></i>
<span>Backup</span>
</button>
<button class="flex items-center gap-2 px-6 py-4 text-sm font-medium border-b-2 border-transparent hover:border-primary-300 text-neutral-600 dark:text-neutral-400 hover:text-primary-600 dark:hover:text-primary-400 hover:bg-neutral-50 dark:hover:bg-neutral-700/50 transition-all duration-200" id="issues-tab" data-tab-target="#issues" type="button" role="tab">
<i class="fa-solid fa-bug"></i>
<span>Issues</span>
<span class="ml-1 px-2 py-0.5 bg-red-100 dark:bg-red-800 text-red-700 dark:text-red-400 text-xs rounded-full hidden" id="issues-badge">0</span>
</button>
</nav>
<!-- Tab Content -->
<div id="adminTabContent">
<!-- Overview Tab -->
<div id="overview" role="tabpanel" class="">
<div class="flex flex-wrap -mx-4">
<div class="w-full md:w-2/3 px-4">
<div class="bg-white dark:bg-neutral-800 border border-neutral-200 dark:border-neutral-700 rounded-lg shadow">
<div class="px-4 py-3 border-b border-neutral-200 dark:border-neutral-700">
<h5 class="m-0 font-semibold"><i class="fas fa-chart-bar"></i> System Statistics</h5>
</div>
<div class="p-4">
<div class="flex flex-wrap -mx-3">
<div class="w-full sm:w-1/2 px-3 mb-3">
<strong>Total Customers:</strong>
<span id="stat-customers" class="float-right">0</span>
<!-- Tab Content -->
<div id="adminTabContent" class="space-y-6">
<!-- Overview Tab -->
<div id="overview" role="tabpanel" class="space-y-6">
<!-- Quick Stats Overview -->
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
<!-- System Statistics -->
<div class="lg:col-span-2">
<div class="bg-white dark:bg-neutral-900 rounded-xl shadow-sm dark:shadow-none border border-neutral-200 dark:border-neutral-700">
<div class="px-6 py-4 border-b border-neutral-200 dark:border-neutral-700">
<div class="flex items-center justify-between">
<h3 class="text-lg font-semibold text-neutral-900 dark:text-white flex items-center gap-2">
<i class="fa-solid fa-chart-bar text-primary-600 dark:text-primary-400"></i>
System Statistics
</h3>
<button class="text-neutral-400 hover:text-neutral-600 dark:text-neutral-500 dark:hover:text-neutral-300" onclick="loadSystemStats()">
<i class="fa-solid fa-rotate-right"></i>
</button>
</div>
<div class="w-full sm:w-1/2 px-3 mb-3">
<strong>Total Files:</strong>
<span id="stat-files" class="float-right">0</span>
</div>
<div class="p-6">
<div class="grid grid-cols-2 gap-6">
<div class="flex items-center justify-between p-4 bg-neutral-50 dark:bg-neutral-800/50 rounded-lg">
<div>
<p class="text-sm text-neutral-600 dark:text-neutral-300">Total Customers</p>
<p class="text-2xl font-bold text-neutral-900 dark:text-white" id="stat-customers">0</p>
</div>
<div class="w-10 h-10 bg-blue-100 dark:bg-blue-800 text-blue-600 dark:text-blue-300 rounded-lg flex items-center justify-center">
<i class="fa-solid fa-users"></i>
</div>
</div>
<div class="flex items-center justify-between p-4 bg-neutral-50 dark:bg-neutral-800/50 rounded-lg">
<div>
<p class="text-sm text-neutral-600 dark:text-neutral-300">Total Files</p>
<p class="text-2xl font-bold text-neutral-900 dark:text-white" id="stat-files">0</p>
</div>
<div class="w-10 h-10 bg-green-100 dark:bg-green-800 text-green-600 dark:text-green-300 rounded-lg flex items-center justify-center">
<i class="fa-solid fa-folder"></i>
</div>
</div>
<div class="flex items-center justify-between p-4 bg-neutral-50 dark:bg-neutral-800/50 rounded-lg">
<div>
<p class="text-sm text-neutral-600 dark:text-neutral-300">Transactions</p>
<p class="text-2xl font-bold text-neutral-900 dark:text-white" id="stat-transactions">0</p>
</div>
<div class="w-10 h-10 bg-purple-100 dark:bg-purple-800 text-purple-600 dark:text-purple-300 rounded-lg flex items-center justify-center">
<i class="fa-solid fa-receipt"></i>
</div>
</div>
<div class="flex items-center justify-between p-4 bg-neutral-50 dark:bg-neutral-800/50 rounded-lg">
<div>
<p class="text-sm text-neutral-600 dark:text-neutral-300">QDROs</p>
<p class="text-2xl font-bold text-neutral-900 dark:text-white" id="stat-qdros">0</p>
</div>
<div class="w-10 h-10 bg-amber-100 dark:bg-amber-800 text-amber-600 dark:text-amber-300 rounded-lg flex items-center justify-center">
<i class="fa-solid fa-file-contract"></i>
</div>
</div>
</div>
<div class="w-full sm:w-1/2 px-3 mb-3">
<strong>Total Transactions:</strong>
<span id="stat-transactions" class="float-right">0</span>
</div>
<div class="w-full sm:w-1/2 px-3 mb-3">
<strong>Total QDROs:</strong>
<span id="stat-qdros" class="float-right">0</span>
</div>
<div class="w-full sm:w-1/2 px-3 mb-3">
<strong>Active Users:</strong>
<span id="stat-active-users" class="float-right">0</span>
</div>
<div class="w-full sm:w-1/2 px-3 mb-3">
<strong>Admin Users:</strong>
<span id="stat-admins" class="float-right">0</span>
<div class="mt-6 pt-6 border-t border-neutral-200 dark:border-neutral-700">
<div class="flex items-center justify-between">
<div class="flex items-center gap-4">
<div class="text-center">
<p class="text-lg font-bold text-neutral-900 dark:text-white" id="stat-active-users">0</p>
<p class="text-xs text-neutral-600 dark:text-neutral-300">Active Users</p>
</div>
<div class="text-center">
<p class="text-lg font-bold text-neutral-900 dark:text-white" id="stat-admins">0</p>
<p class="text-xs text-neutral-600 dark:text-neutral-300">Admin Users</p>
</div>
</div>
<div class="text-right">
<p class="text-sm text-neutral-600 dark:text-neutral-300">Last updated</p>
<p class="text-sm font-medium" id="stats-updated">Loading...</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="w-full md:w-1/3 px-4 mt-4 md:mt-0">
<div class="bg-white dark:bg-neutral-800 border border-neutral-200 dark:border-neutral-700 rounded-lg shadow">
<div class="px-4 py-3 border-b border-neutral-200 dark:border-neutral-700">
<h5 class="m-0 font-semibold"><i class="fas fa-exclamation-triangle"></i> System Alerts</h5>
<!-- System Alerts -->
<div class="lg:col-span-1">
<div class="bg-white dark:bg-neutral-900 rounded-xl shadow-sm dark:shadow-none border border-neutral-200 dark:border-neutral-700">
<div class="px-6 py-4 border-b border-neutral-200 dark:border-neutral-700">
<h3 class="text-lg font-semibold text-neutral-900 dark:text-white flex items-center gap-2">
<i class="fa-solid fa-bell text-amber-500"></i>
System Alerts
</h3>
</div>
<div class="p-6">
<div id="system-alerts" class="space-y-3">
<div class="flex items-center gap-3 p-3 bg-green-50 dark:bg-green-900/20 text-green-700 dark:text-green-400 rounded-lg">
<i class="fa-solid fa-check-circle"></i>
<div>
<p class="text-sm font-medium">All Systems Normal</p>
<p class="text-xs opacity-75">No issues detected</p>
</div>
</div>
</div>
</div>
</div>
<div class="p-4">
<div id="system-alerts">
<p class="text-neutral-500 dark:text-neutral-400">No alerts</p>
<!-- Quick Actions -->
<div class="mt-6 bg-white dark:bg-neutral-900 rounded-xl shadow-sm dark:shadow-none border border-neutral-200 dark:border-neutral-700">
<div class="px-6 py-4 border-b border-neutral-200 dark:border-neutral-700">
<h3 class="text-lg font-semibold text-neutral-900 dark:text-white flex items-center gap-2">
<i class="fa-solid fa-bolt text-primary-600 dark:text-primary-400"></i>
Quick Actions
</h3>
</div>
<div class="p-6 space-y-3">
<button class="w-full flex items-center gap-3 p-3 text-left hover:bg-neutral-50 dark:hover:bg-neutral-800/50 rounded-lg transition-colors" onclick="openTab(event, 'users')">
<div class="w-8 h-8 bg-blue-100 dark:bg-blue-800 text-blue-600 dark:text-blue-300 rounded-lg flex items-center justify-center">
<i class="fa-solid fa-user-plus text-sm"></i>
</div>
<div>
<p class="text-sm font-medium text-neutral-900 dark:text-white">Add User</p>
<p class="text-xs text-neutral-600 dark:text-neutral-300">Create new user account</p>
</div>
</button>
<button class="w-full flex items-center gap-3 p-3 text-left hover:bg-neutral-50 dark:hover:bg-neutral-800/50 rounded-lg transition-colors" onclick="openTab(event, 'backup')">
<div class="w-8 h-8 bg-green-100 dark:bg-green-800 text-green-600 dark:text-green-300 rounded-lg flex items-center justify-center">
<i class="fa-solid fa-download text-sm"></i>
</div>
<div>
<p class="text-sm font-medium text-neutral-900 dark:text-white">Backup Now</p>
<p class="text-xs text-neutral-600 dark:text-neutral-300">Create system backup</p>
</div>
</button>
<button class="w-full flex items-center gap-3 p-3 text-left hover:bg-neutral-50 dark:hover:bg-neutral-800/50 rounded-lg transition-colors" onclick="openTab(event, 'settings')">
<div class="w-8 h-8 bg-purple-100 dark:bg-purple-800 text-purple-600 dark:text-purple-300 rounded-lg flex items-center justify-center">
<i class="fa-solid fa-cog text-sm"></i>
</div>
<div>
<p class="text-sm font-medium text-neutral-900 dark:text-white">System Settings</p>
<p class="text-xs text-neutral-600 dark:text-neutral-300">Configure system options</p>
</div>
</button>
</div>
</div>
</div>
</div>
</div>
<div class="mt-4">
<div class="bg-white dark:bg-neutral-800 border border-neutral-200 dark:border-neutral-700 rounded-lg shadow">
<div class="px-4 py-3 border-b border-neutral-200 dark:border-neutral-700">
<h5 class="m-0 font-semibold"><i class="fas fa-history"></i> Recent Activity</h5>
</div>
<div class="p-4">
<div id="recent-activity">
<p class="text-neutral-500 dark:text-neutral-400">Loading recent activity...</p>
</div>
</div>
</div>
</div>
</div>
<!-- Users Tab -->
<div id="users" role="tabpanel" class="hidden">
<div class="bg-white dark:bg-neutral-800 border border-neutral-200 dark:border-neutral-700 rounded-lg shadow">
<div class="px-4 py-3 border-b border-neutral-200 dark:border-neutral-700 flex items-center justify-between">
<h5 class="m-0 font-semibold"><i class="fas fa-users"></i> User Management</h5>
<button type="button" class="px-3 py-1.5 bg-primary-600 hover:bg-primary-700 text-white rounded text-sm" onclick="showCreateUserModal()">
<i class="fas fa-plus"></i> Add User
</button>
</div>
<div class="p-4">
<div class="flex flex-wrap -mx-3 mb-3">
<div class="w-full md:w-1/2 px-3 mb-3 md:mb-0">
<input type="text" class="w-full px-3 py-2 bg-white dark:bg-neutral-800 border border-neutral-300 dark:border-neutral-600 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent" id="user-search"
placeholder="Search users..." onkeyup="searchUsers()">
</div>
<div class="w-full md:w-1/4 px-3 mb-3 md:mb-0">
<select class="w-full px-3 py-2 bg-white dark:bg-neutral-800 border border-neutral-300 dark:border-neutral-600 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent" id="user-filter" onchange="filterUsers()">
<option value="all">All Users</option>
<option value="active">Active Only</option>
<option value="admin">Admins Only</option>
</select>
</div>
<div class="w-full md:w-1/4 px-3">
<button type="button" class="w-full md:w-auto px-3 py-2 border border-neutral-300 dark:border-neutral-600 rounded-lg hover:bg-neutral-50 dark:hover:bg-neutral-700" onclick="loadUsers()">
<i class="fas fa-sync"></i> Refresh
<!-- Recent Activity -->
<div class="bg-white dark:bg-neutral-900 rounded-xl shadow-sm dark:shadow-none border border-neutral-200 dark:border-neutral-700">
<div class="px-6 py-4 border-b border-neutral-200 dark:border-neutral-700">
<div class="flex items-center justify-between">
<h3 class="text-lg font-semibold text-neutral-900 dark:text-white flex items-center gap-2">
<i class="fa-solid fa-clock-rotate-left text-primary-600 dark:text-primary-400"></i>
Recent Activity
</h3>
<button class="text-neutral-400 hover:text-neutral-600 dark:text-neutral-500 dark:hover:text-neutral-300 text-sm">
View All
</button>
</div>
</div>
<div class="p-6">
<div id="recent-activity" class="space-y-4">
<div class="flex items-center gap-4 p-4 bg-neutral-50 dark:bg-neutral-800/50 rounded-lg">
<div class="w-10 h-10 bg-blue-100 dark:bg-blue-800 text-blue-600 dark:text-blue-300 rounded-full flex items-center justify-center">
<i class="fa-solid fa-user text-sm"></i>
</div>
<div class="flex-1">
<p class="text-sm font-medium text-neutral-900 dark:text-white">Loading recent activity...</p>
<p class="text-xs text-neutral-600 dark:text-neutral-300">Please wait...</p>
</div>
<div class="text-xs text-neutral-500 dark:text-neutral-400">
--
</div>
</div>
</div>
</div>
</div>
</div>
<div class="overflow-x-auto rounded-lg border border-neutral-200 dark:border-neutral-700">
<table class="min-w-full divide-y divide-neutral-200 dark:divide-neutral-700">
<thead class="bg-primary-600 text-white">
<tr>
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wider">Username</th>
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wider">Email</th>
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wider">Name</th>
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wider">Status</th>
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wider">Role</th>
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wider">Last Login</th>
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wider">Actions</th>
<!-- Users Tab -->
<div id="users" role="tabpanel" class="hidden space-y-6">
<div class="bg-white dark:bg-neutral-900 rounded-xl shadow-sm dark:shadow-none border border-neutral-200 dark:border-neutral-700">
<div class="px-6 py-4 border-b border-neutral-200 dark:border-neutral-700">
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
<div>
<h3 class="text-lg font-semibold text-neutral-900 dark:text-white flex items-center gap-2">
<i class="fa-solid fa-users-gear text-primary-600 dark:text-primary-400"></i>
User Management
</h3>
<p class="text-sm text-neutral-600 dark:text-neutral-300 mt-1">Manage user accounts and permissions</p>
</div>
<button type="button" class="flex items-center gap-2 px-4 py-2 bg-primary-600 hover:bg-primary-700 text-white rounded-lg transition-colors duration-200" onclick="showCreateUserModal()">
<i class="fa-solid fa-user-plus"></i>
<span>Add User</span>
</button>
</div>
</div>
<!-- Search and Filter Controls -->
<div class="px-6 py-4 bg-neutral-50 dark:bg-neutral-800/50 border-b border-neutral-200 dark:border-neutral-700">
<div class="flex flex-col sm:flex-row gap-4">
<div class="flex-1">
<div class="relative">
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<i class="fa-solid fa-magnifying-glass text-neutral-400"></i>
</div>
<input type="text" class="w-full pl-10 pr-4 py-2 bg-white dark:bg-neutral-800 border border-neutral-300 dark:border-neutral-600 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent placeholder-neutral-500"
id="user-search" placeholder="Search users by name, email, or username..." onkeyup="searchUsers()">
</div>
</div>
<div class="flex gap-2">
<select class="px-4 py-2 bg-white dark:bg-neutral-800 border border-neutral-300 dark:border-neutral-600 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent" id="user-filter" onchange="filterUsers()">
<option value="all">All Users</option>
<option value="active">Active Only</option>
<option value="inactive">Inactive Only</option>
<option value="admin">Admins Only</option>
</select>
<button type="button" class="px-4 py-2 border border-neutral-300 dark:border-neutral-600 rounded-lg hover:bg-neutral-50 dark:hover:bg-neutral-700 transition-colors" onclick="loadUsers()">
<i class="fa-solid fa-rotate-right"></i>
</button>
</div>
</div>
</div>
<!-- Users Table -->
<div class="overflow-x-auto">
<table class="w-full">
<thead>
<tr class="border-b border-neutral-200 dark:border-neutral-700">
<th class="px-6 py-4 text-left text-xs font-medium text-neutral-600 dark:text-neutral-400 uppercase tracking-wider">User</th>
<th class="px-6 py-4 text-left text-xs font-medium text-neutral-600 dark:text-neutral-400 uppercase tracking-wider">Status</th>
<th class="px-6 py-4 text-left text-xs font-medium text-neutral-600 dark:text-neutral-400 uppercase tracking-wider">Role</th>
<th class="px-6 py-4 text-left text-xs font-medium text-neutral-600 dark:text-neutral-400 uppercase tracking-wider">Last Login</th>
<th class="px-6 py-4 text-right text-xs font-medium text-neutral-600 dark:text-neutral-400 uppercase tracking-wider">Actions</th>
</tr>
</thead>
<tbody id="users-table-body" class="bg-white dark:bg-neutral-800 divide-y divide-neutral-200 dark:divide-neutral-700">
<tbody id="users-table-body" class="divide-y divide-neutral-200 dark:divide-neutral-700">
<tr>
<td colspan="7" class="text-center px-4 py-4 text-neutral-500">Loading users...</td>
<td colspan="5" class="px-6 py-12 text-center">
<div class="flex flex-col items-center gap-3">
<div class="w-12 h-12 bg-neutral-100 dark:bg-neutral-700 rounded-full flex items-center justify-center">
<i class="fa-solid fa-spinner fa-spin text-neutral-400"></i>
</div>
<p class="text-neutral-600 dark:text-neutral-400">Loading users...</p>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<nav class="mt-3">
<ul class="flex items-center justify-center gap-2" id="users-pagination">
</ul>
</nav>
<!-- Pagination -->
<div class="px-6 py-4 border-t border-neutral-200 dark:border-neutral-700">
<nav class="flex items-center justify-between">
<div class="flex items-center gap-2">
<p class="text-sm text-neutral-600 dark:text-neutral-400">
<span id="users-count-display">0 users total</span>
</p>
</div>
<div class="flex items-center gap-2" id="users-pagination">
<!-- Pagination will be inserted here -->
</div>
</nav>
</div>
</div>
</div>
</div>
<!-- Settings Tab -->
<div id="settings" role="tabpanel" class="hidden">
@@ -311,7 +523,7 @@
<div class="bg-white dark:bg-neutral-800 border border-neutral-200 dark:border-neutral-700 rounded-lg shadow mb-4">
<div class="px-4 py-3 border-b border-neutral-200 dark:border-neutral-700 flex items-center justify-between">
<h5 class="m-0 font-semibold"><i class="fa-solid fa-circle-info"></i> Current Database Status</h5>
<button class="px-3 py-1.5 border border-info-600 text-info-700 dark:text-info-300 rounded text-sm hover:bg-info-50 dark:hover:bg-info-900/20" onclick="loadImportStatus()">
<button class="px-3 py-1.5 border border-info-600 text-info-700 dark:text-info-200 rounded text-sm hover:bg-info-50 dark:hover:bg-info-900/20" onclick="loadImportStatus()">
<i class="fa-solid fa-rotate-right"></i> Refresh
</button>
</div>
@@ -423,7 +635,7 @@
<div class="w-full md:w-1/2 px-4 mt-4 md:mt-0">
<h6 class="font-semibold">Quick Actions</h6>
<div class="grid gap-2">
<button class="px-3 py-2 border border-info-600 text-info-700 dark:text-info-300 rounded hover:bg-info-50 dark:hover:bg-info-900/20" onclick="viewImportLogs()">
<button class="px-3 py-2 border border-info-600 text-info-700 dark:text-info-200 rounded hover:bg-info-50 dark:hover:bg-info-900/20" onclick="viewImportLogs()">
<i class="fa-regular fa-file-lines"></i> View Import Logs
</button>
</div>
@@ -521,7 +733,7 @@
<div class="px-4 py-3 border-b border-neutral-200 dark:border-neutral-700 flex items-center justify-between">
<h5 class="m-0 font-semibold"><i class="fas fa-bug"></i> Internal Issues & Bugs</h5>
<div class="flex items-center gap-2">
<button type="button" class="px-3 py-1.5 border border-primary-600 text-primary-700 dark:text-primary-300 rounded text-sm hover:bg-primary-50 dark:hover:bg-primary-900/20" onclick="loadIssues()">
<button type="button" class="px-3 py-1.5 border border-primary-600 text-primary-700 dark:text-primary-200 rounded text-sm hover:bg-primary-50 dark:hover:bg-primary-900/20" onclick="loadIssues()">
<i class="fas fa-sync"></i> Refresh
</button>
<button type="button" class="px-3 py-1.5 bg-primary-600 hover:bg-primary-700 text-white rounded text-sm" onclick="openSupportModal()">
@@ -624,7 +836,7 @@
<div class="flex items-center justify-between">
<div class="flex items-center gap-2">
<span class="px-2 py-1 rounded bg-primary-600 text-white text-xs" id="issueDetailNumber">ST-2025-XXXX</span>
<span class="px-2 py-1 rounded bg-primary-100 text-primary-700 dark:bg-primary-900/30 dark:text-primary-300 text-xs" id="issueDetailCategory">category</span>
<span class="px-2 py-1 rounded bg-primary-100 text-primary-700 dark:bg-primary-800 dark:text-primary-200 text-xs" id="issueDetailCategory">category</span>
<span class="px-2 py-1 rounded bg-neutral-200 dark:bg-neutral-700 text-xs" id="issueDetailPriority">priority</span>
</div>
<span class="px-2 py-1 rounded text-xs bg-neutral-200 dark:bg-neutral-700" id="issueDetailStatus">status</span>
@@ -889,6 +1101,10 @@
</div>
</div>
</div>
<!-- Close main admin content container and tab content -->
</div>
</div>
</div>
<script>
@@ -947,24 +1163,45 @@ function closeModal(id) {
}
function initializeTabs() {
const tabs = document.querySelectorAll('#adminTabs > li');
const tabs = document.querySelectorAll('nav[role="tablist"] button[role="tab"]');
const panes = document.querySelectorAll('#adminTabContent > div[role="tabpanel"]');
tabs.forEach(tab => {
tab.addEventListener('click', () => {
const target = tab.getAttribute('data-tab-target');
if (!target) return;
// deactivate
tabs.forEach(t => t.classList.remove('active'));
panes.forEach(p => p.classList.add('hidden'));
// activate
tab.classList.add('active');
const pane = document.querySelector(target);
if (pane) pane.classList.remove('hidden');
onTabShown((target || '').replace('#', ''));
tab.addEventListener('click', (event) => {
openTab(event, tab.getAttribute('data-tab-target')?.replace('#', ''));
});
});
}
function openTab(event, tabName) {
const tabs = document.querySelectorAll('nav[role="tablist"] button[role="tab"]');
const panes = document.querySelectorAll('#adminTabContent > div[role="tabpanel"]');
// Remove active states
tabs.forEach(t => {
t.classList.remove('border-primary-600', 'text-primary-600', 'bg-primary-50', 'dark:bg-primary-900/20', 'active');
t.classList.add('border-transparent', 'text-neutral-600', 'dark:text-neutral-400');
});
// Hide all panes
panes.forEach(p => p.classList.add('hidden'));
// Activate clicked tab
if (event && event.currentTarget) {
event.currentTarget.classList.remove('border-transparent', 'text-neutral-600', 'dark:text-neutral-400');
event.currentTarget.classList.add('border-primary-600', 'text-primary-600', 'dark:text-primary-400', 'bg-primary-50', 'dark:bg-primary-900/20', 'active');
}
// Show target pane
const targetPane = document.getElementById(tabName);
if (targetPane) {
targetPane.classList.remove('hidden');
}
// Load tab-specific content
onTabShown(tabName);
}
function onTabShown(tabName) {
if (tabName === 'issues') {
loadIssues();
@@ -1137,21 +1374,21 @@ function renderUsersTable(users) {
<td>${user.email}</td>
<td>${(user.first_name || '') + ' ' + (user.last_name || '')}</td>
<td>
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium ${user.is_active ? 'bg-success-100 text-success-800 dark:bg-success-900/30 dark:text-success-300' : 'bg-neutral-200 text-neutral-700 dark:bg-neutral-700 dark:text-neutral-300'}">${user.is_active ? 'Active' : 'Inactive'}</span>
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium ${user.is_active ? 'bg-success-100 text-success-800 dark:bg-success-800 dark:text-success-200' : 'bg-neutral-200 text-neutral-700 dark:bg-neutral-700 dark:text-neutral-300'}">${user.is_active ? 'Active' : 'Inactive'}</span>
</td>
<td>
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium ${user.is_admin ? 'bg-primary-100 text-primary-800 dark:bg-primary-900/30 dark:text-primary-300' : 'bg-neutral-200 text-neutral-700 dark:bg-neutral-700 dark:text-neutral-300'}">${user.is_admin ? 'Admin' : 'User'}</span>
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium ${user.is_admin ? 'bg-primary-100 text-primary-800 dark:bg-primary-800 dark:text-primary-200' : 'bg-neutral-200 text-neutral-700 dark:bg-neutral-700 dark:text-neutral-300'}">${user.is_admin ? 'Admin' : 'User'}</span>
</td>
<td>${user.last_login ? new Date(user.last_login).toLocaleDateString() : 'Never'}</td>
<td>
<div class="flex items-center gap-2">
<button class="px-2 py-1 border border-primary-600 text-primary-700 dark:text-primary-300 rounded text-xs hover:bg-primary-50 dark:hover:bg-primary-900/20" onclick="editUser(${user.id})" title="Edit">
<button class="px-2 py-1 border border-primary-600 text-primary-700 dark:text-primary-200 rounded text-xs hover:bg-primary-50 dark:hover:bg-primary-900/20" onclick="editUser(${user.id})" title="Edit">
<i class="fas fa-edit"></i>
</button>
<button class="px-2 py-1 border border-warning-600 text-warning-700 dark:text-warning-300 rounded text-xs hover:bg-warning-50 dark:hover:bg-warning-900/20" onclick="showPasswordModal(${user.id})" title="Reset Password">
<button class="px-2 py-1 border border-warning-600 text-warning-700 dark:text-warning-200 rounded text-xs hover:bg-warning-50 dark:hover:bg-warning-900/20" onclick="showPasswordModal(${user.id})" title="Reset Password">
<i class="fas fa-key"></i>
</button>
<button class="px-2 py-1 border border-danger-600 text-danger-700 dark:text-danger-300 rounded text-xs hover:bg-danger-50 dark:hover:bg-danger-900/20" onclick="deactivateUser(${user.id})" title="Deactivate">
<button class="px-2 py-1 border border-danger-600 text-danger-700 dark:text-danger-200 rounded text-xs hover:bg-danger-50 dark:hover:bg-danger-900/20" onclick="deactivateUser(${user.id})" title="Deactivate">
<i class="fas fa-user-times"></i>
</button>
</div>
@@ -1334,10 +1571,10 @@ function renderSettingsTable(settings) {
<td>${setting.description || '-'}</td>
<td>
<div class="flex items-center gap-2">
<button class="px-2 py-1 border border-primary-600 text-primary-700 dark:text-primary-300 rounded text-xs hover:bg-primary-50 dark:hover:bg-primary-900/20" onclick="editSetting('${setting.setting_key}')" title="Edit">
<button class="px-2 py-1 border border-primary-600 text-primary-700 dark:text-primary-200 rounded text-xs hover:bg-primary-50 dark:hover:bg-primary-900/20" onclick="editSetting('${setting.setting_key}')" title="Edit">
<i class="fas fa-edit"></i>
</button>
<button class="px-2 py-1 border border-danger-600 text-danger-700 dark:text-danger-300 rounded text-xs hover:bg-danger-50 dark:hover:bg-danger-900/20" onclick="deleteSetting('${setting.setting_key}')" title="Delete">
<button class="px-2 py-1 border border-danger-600 text-danger-700 dark:text-danger-200 rounded text-xs hover:bg-danger-50 dark:hover:bg-danger-900/20" onclick="deleteSetting('${setting.setting_key}')" title="Delete">
<i class="fas fa-trash"></i>
</button>
</div>
@@ -1505,7 +1742,7 @@ async function loadLookupTables() {
<strong>${table.display_name}</strong><br>
<small class="text-neutral-500 dark:text-neutral-400">${table.description}</small>
</div>
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-info-100 text-info-800 dark:bg-info-900/30 dark:text-info-300">${table.record_count} records</span>
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-info-100 text-info-800 dark:bg-info-800 dark:text-info-200">${table.record_count} records</span>
</div>
`).join('');
@@ -1599,10 +1836,10 @@ async function loadBackups() {
<td>${backup.size}</td>
<td>${new Date(backup.created_at).toLocaleString()}</td>
<td>
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium ${backup.backup_type === 'manual' ? 'bg-primary-100 text-primary-800 dark:bg-primary-900/30 dark:text-primary-300' : 'bg-neutral-200 text-neutral-700 dark:bg-neutral-700 dark:text-neutral-300'}">${backup.backup_type}</span>
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium ${backup.backup_type === 'manual' ? 'bg-primary-100 text-primary-800 dark:bg-primary-800 dark:text-primary-200' : 'bg-neutral-200 text-neutral-700 dark:bg-neutral-700 dark:text-neutral-300'}">${backup.backup_type}</span>
</td>
<td>
<button class="px-2 py-1 border border-success-600 text-success-700 dark:text-success-300 rounded text-xs hover:bg-success-50 dark:hover:bg-success-900/20" onclick="downloadBackup('${backup.filename}')" title="Download">
<button class="px-2 py-1 border border-success-600 text-success-700 dark:text-success-200 rounded text-xs hover:bg-success-50 dark:hover:bg-success-900/20" onclick="downloadBackup('${backup.filename}')" title="Download">
<i class="fas fa-download"></i>
</button>
</td>
@@ -1783,16 +2020,16 @@ function renderIssuesTable(issues) {
tbody.innerHTML = issues.map(issue => {
const priorityClass = {
'urgent': 'bg-danger-100 text-danger-800 dark:bg-danger-900/30 dark:text-danger-300',
'high': 'bg-warning-100 text-warning-800 dark:bg-warning-900/30 dark:text-warning-300',
'medium': 'bg-info-100 text-info-800 dark:bg-info-900/30 dark:text-info-300',
'urgent': 'bg-danger-100 text-danger-800 dark:bg-danger-800 dark:text-danger-200',
'high': 'bg-warning-100 text-warning-800 dark:bg-warning-800 dark:text-warning-200',
'medium': 'bg-info-100 text-info-800 dark:bg-info-800 dark:text-info-200',
'low': 'bg-neutral-200 text-neutral-700 dark:bg-neutral-700 dark:text-neutral-300'
}[issue.priority] || 'bg-neutral-200 text-neutral-700 dark:bg-neutral-700 dark:text-neutral-300';
const statusClass = {
'open': 'bg-danger-100 text-danger-800 dark:bg-danger-900/30 dark:text-danger-300',
'in_progress': 'bg-warning-100 text-warning-800 dark:bg-warning-900/30 dark:text-warning-300',
'resolved': 'bg-success-100 text-success-800 dark:bg-success-900/30 dark:text-success-300',
'open': 'bg-danger-100 text-danger-800 dark:bg-danger-800 dark:text-danger-200',
'in_progress': 'bg-warning-100 text-warning-800 dark:bg-warning-800 dark:text-warning-200',
'resolved': 'bg-success-100 text-success-800 dark:bg-success-800 dark:text-success-200',
'closed': 'bg-neutral-200 text-neutral-700 dark:bg-neutral-700 dark:text-neutral-300'
}[issue.status] || 'bg-neutral-200 text-neutral-700 dark:bg-neutral-700 dark:text-neutral-300';
@@ -1813,7 +2050,7 @@ function renderIssuesTable(issues) {
<tr>
<td><strong>${issue.ticket_number}</strong></td>
<td>
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-primary-100 text-primary-800 dark:bg-primary-900/30 dark:text-primary-300">${categoryDisplay}</span>
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-primary-100 text-primary-800 dark:bg-primary-800 dark:text-primary-200">${categoryDisplay}</span>
</td>
<td>
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium ${priorityClass}">${issue.priority.toUpperCase()}</span>
@@ -1830,7 +2067,7 @@ function renderIssuesTable(issues) {
<td>${issue.assigned_admin_name || 'Unassigned'}</td>
<td>${new Date(issue.created_at).toLocaleDateString()}</td>
<td>
<button class="px-2 py-1 border border-primary-600 text-primary-700 dark:text-primary-300 rounded text-xs hover:bg-primary-50 dark:hover:bg-primary-900/20" onclick="viewIssue(${issue.id})" title="View Details">
<button class="px-2 py-1 border border-primary-600 text-primary-700 dark:text-primary-200 rounded text-xs hover:bg-primary-50 dark:hover:bg-primary-900/20" onclick="viewIssue(${issue.id})" title="View Details">
<i class="fas fa-eye"></i>
</button>
</td>
@@ -1875,21 +2112,21 @@ async function viewIssue(issueId) {
}[issue.category] || issue.category;
document.getElementById('issueDetailCategory').textContent = categoryDisplay;
document.getElementById('issueDetailCategory').className = 'inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-primary-100 text-primary-800 dark:bg-primary-900/30 dark:text-primary-300';
document.getElementById('issueDetailCategory').className = 'inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-primary-100 text-primary-800 dark:bg-primary-800 dark:text-primary-200';
document.getElementById('issueDetailPriority').textContent = issue.priority.toUpperCase();
document.getElementById('issueDetailPriority').className = 'inline-flex items-center px-2 py-0.5 rounded text-xs font-medium ml-2 ' + ({
'urgent': 'bg-danger-100 text-danger-800 dark:bg-danger-900/30 dark:text-danger-300',
'high': 'bg-warning-100 text-warning-800 dark:bg-warning-900/30 dark:text-warning-300',
'medium': 'bg-info-100 text-info-800 dark:bg-info-900/30 dark:text-info-300',
'urgent': 'bg-danger-100 text-danger-800 dark:bg-danger-800 dark:text-danger-200',
'high': 'bg-warning-100 text-warning-800 dark:bg-warning-800 dark:text-warning-200',
'medium': 'bg-info-100 text-info-800 dark:bg-info-800 dark:text-info-200',
'low': 'bg-neutral-200 text-neutral-700 dark:bg-neutral-700 dark:text-neutral-300'
}[issue.priority] || 'bg-neutral-200 text-neutral-700 dark:bg-neutral-700 dark:text-neutral-300');
document.getElementById('issueDetailStatus').textContent = issue.status.replace('_', ' ').toUpperCase();
document.getElementById('issueDetailStatus').className = 'inline-flex items-center px-2 py-0.5 rounded text-xs font-medium ' + ({
'open': 'bg-danger-100 text-danger-800 dark:bg-danger-900/30 dark:text-danger-300',
'in_progress': 'bg-warning-100 text-warning-800 dark:bg-warning-900/30 dark:text-warning-300',
'resolved': 'bg-success-100 text-success-800 dark:bg-success-900/30 dark:text-success-300',
'open': 'bg-danger-100 text-danger-800 dark:bg-danger-800 dark:text-danger-200',
'in_progress': 'bg-warning-100 text-warning-800 dark:bg-warning-800 dark:text-warning-200',
'resolved': 'bg-success-100 text-success-800 dark:bg-success-800 dark:text-success-200',
'closed': 'bg-neutral-200 text-neutral-700 dark:bg-neutral-700 dark:text-neutral-300'
}[issue.status] || 'bg-neutral-200 text-neutral-700 dark:bg-neutral-700 dark:text-neutral-300');
@@ -1966,8 +2203,8 @@ function displayIssueResponses(responses) {
container.innerHTML = responses.map(response => {
const isInternal = response.is_internal;
const badgeClass = isInternal
? 'bg-warning-100 text-warning-800 dark:bg-warning-900/30 dark:text-warning-300'
: 'bg-primary-100 text-primary-800 dark:bg-primary-900/30 dark:text-primary-300';
? 'bg-warning-100 text-warning-800 dark:bg-warning-800 dark:text-warning-200'
: 'bg-primary-100 text-primary-800 dark:bg-primary-800 dark:text-primary-200';
const badgeText = isInternal ? 'Internal' : 'Public';
return `

View File

@@ -10,7 +10,7 @@
<!-- Tailwind CSS -->
<!-- Custom Tailwind CSS -->
<link href="/static/css/tailwind.css" rel="stylesheet">
<link href="/static/css/main.css" rel="stylesheet">
{% block bridge_css %}{% endblock %}

View File

@@ -3,7 +3,7 @@
{% block title %}Customers (Rolodex) - Delphi Database{% endblock %}
{% block content %}
<div class="space-y-6">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6 space-y-6">
<!-- Page Header -->
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
<div class="flex items-center gap-3">

View File

@@ -57,8 +57,8 @@
</div>
<div class="md:col-span-1">
<div class="flex gap-2">
<input type="text" class="w-full px-3 py-2 border border-neutral-300 dark:border-neutral-600 rounded-lg" id="templateSearch" placeholder="Search templates...">
<select class="px-3 py-2 border border-neutral-300 dark:border-neutral-600 rounded-lg" id="categoryFilter">
<input type="text" class="w-full px-3 py-2 bg-white dark:bg-neutral-800 border border-neutral-300 dark:border-neutral-600 rounded-lg text-neutral-900 dark:text-neutral-100 placeholder-neutral-400 dark:placeholder-neutral-500 transition-all duration-200" id="templateSearch" placeholder="Search templates...">
<select class="px-3 py-2 bg-white dark:bg-neutral-800 border border-neutral-300 dark:border-neutral-600 rounded-lg text-neutral-900 dark:text-neutral-100 transition-all duration-200" id="categoryFilter">
<option value="">All Categories</option>
</select>
<button class="px-3 py-2 border border-neutral-300 dark:border-neutral-600 rounded-lg hover:bg-neutral-100 dark:hover:bg-neutral-700" id="refreshTemplatesBtn"><i class="fa-solid fa-rotate-right"></i></button>
@@ -95,8 +95,8 @@
<div><h5 class="mb-0 font-semibold"><i class="fa-regular fa-file-lines"></i> QDRO Documents</h5></div>
<div>
<div class="flex gap-2">
<input type="text" class="w-full px-3 py-2 border border-neutral-300 dark:border-neutral-600 rounded-lg" id="qdroSearch" placeholder="Search QDROs...">
<select class="px-3 py-2 border border-neutral-300 dark:border-neutral-600 rounded-lg" id="qdroStatusFilter">
<input type="text" class="w-full px-3 py-2 bg-white dark:bg-neutral-800 border border-neutral-300 dark:border-neutral-600 rounded-lg text-neutral-900 dark:text-neutral-100 placeholder-neutral-400 dark:placeholder-neutral-500 transition-all duration-200" id="qdroSearch" placeholder="Search QDROs...">
<select class="px-3 py-2 bg-white dark:bg-neutral-800 border border-neutral-300 dark:border-neutral-600 rounded-lg text-neutral-900 dark:text-neutral-100 transition-all duration-200" id="qdroStatusFilter">
<option value="">All Status</option>
<option value="DRAFT">Draft</option>
<option value="APPROVED">Approved</option>

View File

@@ -34,30 +34,30 @@
<div class="bg-white dark:bg-neutral-800 rounded-lg shadow-md p-6">
<div class="grid grid-cols-1 md:grid-cols-5 gap-4">
<div class="md:col-span-3">
<label for="searchInput" class="block text-sm font-medium mb-2">Search Files</label>
<label for="searchInput" class="block text-sm font-medium text-neutral-700 dark:text-neutral-300 mb-2">Search Files</label>
<div class="relative">
<input type="text" id="searchInput" class="w-full pl-10 pr-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent" placeholder="File #, Client, Matter...">
<i class="fa-solid fa-magnifying-glass absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400"></i>
<button id="searchBtn" class="absolute right-2 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-primary-500">
<input type="text" id="searchInput" class="w-full pl-10 pr-4 py-3 bg-white dark:bg-neutral-800 border border-neutral-300 dark:border-neutral-600 rounded-lg text-neutral-900 dark:text-neutral-100 placeholder-neutral-400 dark:placeholder-neutral-500 focus:ring-2 focus:ring-primary-500 focus:border-transparent transition-all duration-200" placeholder="File #, Client, Matter...">
<i class="fa-solid fa-magnifying-glass absolute left-3 top-1/2 transform -translate-y-1/2 text-neutral-400 dark:text-neutral-500"></i>
<button id="searchBtn" class="absolute right-2 top-1/2 transform -translate-y-1/2 text-neutral-400 hover:text-primary-600 dark:text-neutral-500 dark:hover:text-primary-400 transition-colors">
<i class="fa-solid fa-arrow-right"></i>
</button>
</div>
</div>
<div>
<label for="statusFilter" class="block text-sm font-medium mb-2">Status</label>
<select id="statusFilter" class="w-full py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent">
<label for="statusFilter" class="block text-sm font-medium text-neutral-700 dark:text-neutral-300 mb-2">Status</label>
<select id="statusFilter" class="w-full px-3 py-3 bg-white dark:bg-neutral-800 border border-neutral-300 dark:border-neutral-600 rounded-lg text-neutral-900 dark:text-neutral-100 focus:ring-2 focus:ring-primary-500 focus:border-transparent transition-all duration-200">
<option value="">All Statuses</option>
</select>
</div>
<div>
<label for="typeFilter" class="block text-sm font-medium mb-2">File Type</label>
<select id="typeFilter" class="w-full py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent">
<label for="typeFilter" class="block text-sm font-medium text-neutral-700 dark:text-neutral-300 mb-2">File Type</label>
<select id="typeFilter" class="w-full px-3 py-3 bg-white dark:bg-neutral-800 border border-neutral-300 dark:border-neutral-600 rounded-lg text-neutral-900 dark:text-neutral-100 focus:ring-2 focus:ring-primary-500 focus:border-transparent transition-all duration-200">
<option value="">All Types</option>
</select>
</div>
<div>
<label for="employeeFilter" class="block text-sm font-medium mb-2">Attorney</label>
<select id="employeeFilter" class="w-full py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent">
<label for="employeeFilter" class="block text-sm font-medium text-neutral-700 dark:text-neutral-300 mb-2">Attorney</label>
<select id="employeeFilter" class="w-full px-3 py-3 bg-white dark:bg-neutral-800 border border-neutral-300 dark:border-neutral-600 rounded-lg text-neutral-900 dark:text-neutral-100 focus:ring-2 focus:ring-primary-500 focus:border-transparent transition-all duration-200">
<option value="">All Attorneys</option>
</select>
</div>

View File

@@ -65,12 +65,12 @@
<div class="flex justify-between items-center p-4 border-b border-neutral-200 dark:border-neutral-700">
<h2 class="text-lg font-semibold"><i class="fa-solid fa-clock-rotate-left mr-2"></i>Recent Time Entries</h2>
<div class="flex gap-2">
<select class="px-3 py-1 border border-neutral-300 dark:border-neutral-600 rounded-lg text-sm" id="recentDaysFilter">
<select class="px-3 py-1 bg-white dark:bg-neutral-800 border border-neutral-300 dark:border-neutral-600 rounded-lg text-sm text-neutral-900 dark:text-neutral-100 transition-all duration-200" id="recentDaysFilter">
<option value="7">Last 7 days</option>
<option value="14">Last 14 days</option>
<option value="30">Last 30 days</option>
</select>
<select class="px-3 py-1 border border-neutral-300 dark:border-neutral-600 rounded-lg text-sm" id="employeeFilter">
<select class="px-3 py-1 bg-white dark:bg-neutral-800 border border-neutral-300 dark:border-neutral-600 rounded-lg text-sm text-neutral-900 dark:text-neutral-100 transition-all duration-200" id="employeeFilter">
<option value="">All Employees</option>
</select>
<button class="px-3 py-1 bg-gray-200 dark:bg-neutral-700 text-gray-800 dark:text-gray-200 rounded-lg hover:bg-gray-300 dark:hover:bg-neutral-600 transition-colors" id="refreshRecentBtn">

View File

@@ -110,11 +110,11 @@
<div class="flex flex-wrap -mx-2">
<div class="w-1/2 px-2">
<label for="dateFrom" class="block text-sm font-medium text-neutral-700 dark:text-neutral-300 mb-2">From</label>
<input type="date" class="w-full px-3 py-2 border border-neutral-300 dark:border-neutral-600 rounded-lg text-neutral-900 dark:text-neutral-100 focus:ring-2 focus:ring-primary-500 focus:border-transparent transition-all duration-200" id="dateFrom">
<input type="date" class="w-full px-3 py-2 bg-white dark:bg-neutral-800 border border-neutral-300 dark:border-neutral-600 rounded-lg text-neutral-900 dark:text-neutral-100 focus:ring-2 focus:ring-primary-500 focus:border-transparent transition-all duration-200" id="dateFrom">
</div>
<div class="w-1/2 px-2">
<label for="dateTo" class="block text-sm font-medium text-neutral-700 dark:text-neutral-300 mb-2">To</label>
<input type="date" class="w-full px-3 py-2 border border-neutral-300 dark:border-neutral-600 rounded-lg text-neutral-900 dark:text-neutral-100 focus:ring-2 focus:ring-primary-500 focus:border-transparent transition-all duration-200" id="dateTo">
<input type="date" class="w-full px-3 py-2 bg-white dark:bg-neutral-800 border border-neutral-300 dark:border-neutral-600 rounded-lg text-neutral-900 dark:text-neutral-100 focus:ring-2 focus:ring-primary-500 focus:border-transparent transition-all duration-200" id="dateTo">
</div>
</div>
<div class="mt-2 flex gap-2">
@@ -148,7 +148,7 @@
<span class="absolute left-3 top-1/2 -translate-y-1/2 px-1 bg-neutral-200 dark:bg-neutral-700 text-neutral-500 dark:text-neutral-400 rounded-l-md">
$
</span>
<input type="number" class="w-full pl-10 pr-3 py-2 border border-neutral-300 dark:border-neutral-600 rounded-lg text-neutral-900 dark:text-neutral-100 focus:ring-2 focus:ring-primary-500 focus:border-transparent transition-all duration-200" id="amountMin" step="0.01" min="0">
<input type="number" class="w-full pl-10 pr-3 py-2 bg-white dark:bg-neutral-800 border border-neutral-300 dark:border-neutral-600 rounded-lg text-neutral-900 dark:text-neutral-100 focus:ring-2 focus:ring-primary-500 focus:border-transparent transition-all duration-200" id="amountMin" step="0.01" min="0">
</div>
</div>
<div class="w-1/2 px-2">
@@ -157,7 +157,7 @@
<span class="absolute left-3 top-1/2 -translate-y-1/2 px-1 bg-neutral-200 dark:bg-neutral-700 text-neutral-500 dark:text-neutral-400 rounded-l-md">
$
</span>
<input type="number" class="w-full pl-10 pr-3 py-2 border border-neutral-300 dark:border-neutral-600 rounded-lg text-neutral-900 dark:text-neutral-100 focus:ring-2 focus:ring-primary-500 focus:border-transparent transition-all duration-200" id="amountMax" step="0.01" min="0">
<input type="number" class="w-full pl-10 pr-3 py-2 bg-white dark:bg-neutral-800 border border-neutral-300 dark:border-neutral-600 rounded-lg text-neutral-900 dark:text-neutral-100 focus:ring-2 focus:ring-primary-500 focus:border-transparent transition-all duration-200" id="amountMax" step="0.01" min="0">
</div>
</div>
</div>
@@ -258,8 +258,8 @@
<div>
<div class="grid grid-cols-2 gap-3 items-center">
<div>
<label for="sortBy" class="block text-sm font-medium mb-1">Sort by:</label>
<select class="w-full px-3 py-2 border border-neutral-300 dark:border-neutral-600 rounded-lg" id="sortBy">
<label for="sortBy" class="block text-sm font-medium text-neutral-700 dark:text-neutral-300 mb-1">Sort by:</label>
<select class="w-full px-3 py-2 bg-white dark:bg-neutral-800 border border-neutral-300 dark:border-neutral-600 rounded-lg text-neutral-900 dark:text-neutral-100 transition-all duration-200" id="sortBy">
<option value="relevance">Relevance</option>
<option value="date">Date</option>
<option value="amount">Amount</option>
@@ -267,8 +267,8 @@
</select>
</div>
<div>
<label for="sortOrder" class="block text-sm font-medium mb-1">Order:</label>
<select class="w-full px-3 py-2 border border-neutral-300 dark:border-neutral-600 rounded-lg" id="sortOrder">
<label for="sortOrder" class="block text-sm font-medium text-neutral-700 dark:text-neutral-300 mb-1">Order:</label>
<select class="w-full px-3 py-2 bg-white dark:bg-neutral-800 border border-neutral-300 dark:border-neutral-600 rounded-lg text-neutral-900 dark:text-neutral-100 transition-all duration-200" id="sortOrder">
<option value="desc">Descending</option>
<option value="asc">Ascending</option>
</select>