Update: 2026-05-03 18:01:58
This commit is contained in:
@@ -30,7 +30,8 @@ if (isset($routes[$route])) {
|
||||
if (str_starts_with($route, 'v1/')) {
|
||||
json_error("Not Found: {$route}", 404);
|
||||
} else {
|
||||
// Fallback for non-API requests (Frontend)
|
||||
echo "<h1>Musadaq API - Pure PHP</h1><p>Running on simple architecture.</p>";
|
||||
// Not an API request — serve the SPA shell
|
||||
include __DIR__ . '/shell.php';
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
127
public/shell.php
Normal file
127
public/shell.php
Normal file
@@ -0,0 +1,127 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ar" dir="rtl" data-theme="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>مُصادَق | لوحة التحكم</title>
|
||||
|
||||
<!-- Fonts -->
|
||||
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans+Arabic:wght@300;400;500;600;700&family=IBM+Plex+Mono:wght@400;500&display=swap" rel="stylesheet">
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<script defer src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script>
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--emerald: #10b981;
|
||||
--bg-base: #080c14;
|
||||
--bg-surface: #0d1424;
|
||||
--border-default: rgba(255,255,255,0.1);
|
||||
--text-primary: #f0f6fc;
|
||||
}
|
||||
body { font-family: 'IBM Plex Sans Arabic', sans-serif; background-color: var(--bg-base); color: var(--text-primary); }
|
||||
</style>
|
||||
</head>
|
||||
<body x-data="app" x-init="init()">
|
||||
<div class="flex h-screen overflow-hidden">
|
||||
<!-- Sidebar -->
|
||||
<aside class="w-64 bg-surface border-l border-gray-800 flex flex-col">
|
||||
<div class="p-6">
|
||||
<h1 class="text-xl font-bold text-emerald-500">مُصادَق</h1>
|
||||
</div>
|
||||
<nav class="flex-1 px-4 space-y-2">
|
||||
<a href="#" @click="page='dashboard'" class="block p-3 rounded hover:bg-gray-800" :class="page==='dashboard'?'bg-emerald-900/20 text-emerald-500':''">📊 لوحة التحكم</a>
|
||||
<a href="#" @click="page='users'" class="block p-3 rounded hover:bg-gray-800" :class="page==='users'?'bg-emerald-900/20 text-emerald-500':''">👥 المستخدمون</a>
|
||||
<a href="#" @click="page='trips'" class="block p-3 rounded hover:bg-gray-800" :class="page==='trips'?'bg-emerald-900/20 text-emerald-500':''">🚗 الرحلات</a>
|
||||
</nav>
|
||||
<div class="p-6 border-t border-gray-800">
|
||||
<button @click="logout()" class="w-full text-right text-red-400 text-sm">🚪 تسجيل الخروج</button>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<!-- Main -->
|
||||
<main class="flex-1 overflow-y-auto p-10">
|
||||
<header class="mb-10 flex justify-between items-center">
|
||||
<h2 class="text-2xl font-bold" x-text="title()"></h2>
|
||||
<div class="text-sm text-gray-500" x-text="user?.name"></div>
|
||||
</header>
|
||||
|
||||
<div id="content">
|
||||
<!-- Dashboard -->
|
||||
<div x-show="page === 'dashboard'">
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
<div class="p-6 bg-surface border border-gray-800 rounded">
|
||||
<p class="text-gray-500 text-sm">إجمالي الفواتير</p>
|
||||
<p class="text-3xl font-bold mt-2">1,240</p>
|
||||
</div>
|
||||
<div class="p-6 bg-surface border border-gray-800 rounded">
|
||||
<p class="text-gray-500 text-sm">قيد المعالجة</p>
|
||||
<p class="text-3xl font-bold mt-2 text-yellow-500">12</p>
|
||||
</div>
|
||||
<div class="p-6 bg-surface border border-gray-800 rounded">
|
||||
<p class="text-gray-500 text-sm">تم الاعتماد</p>
|
||||
<p class="text-3xl font-bold mt-2 text-emerald-500">1,228</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Users -->
|
||||
<div x-show="page === 'users'">
|
||||
<div class="bg-surface border border-gray-800 rounded overflow-hidden">
|
||||
<table class="w-full text-right">
|
||||
<thead class="bg-gray-900/50">
|
||||
<tr>
|
||||
<th class="p-4">الاسم</th>
|
||||
<th class="p-4">البريد الإلكتروني</th>
|
||||
<th class="p-4">الدور</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<template x-for="u in users" :key="u.id">
|
||||
<tr class="border-t border-gray-800">
|
||||
<td class="p-4" x-text="u.name"></td>
|
||||
<td class="p-4" x-text="u.email"></td>
|
||||
<td class="p-4 text-xs uppercase text-gray-500" x-text="u.role"></td>
|
||||
</tr>
|
||||
</template>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('alpine:init', () => {
|
||||
Alpine.data('app', () => ({
|
||||
user: JSON.parse(localStorage.getItem('user')),
|
||||
page: 'dashboard',
|
||||
users: [],
|
||||
|
||||
init() {
|
||||
if (!this.user) window.location.href = '/login.php';
|
||||
this.loadUsers();
|
||||
},
|
||||
|
||||
title() {
|
||||
return { dashboard: 'لوحة التحكم', users: 'المستخدمون', trips: 'الرحلات' }[this.page];
|
||||
},
|
||||
|
||||
async loadUsers() {
|
||||
const res = await fetch('/api/users', {
|
||||
headers: { 'Authorization': 'Bearer ' + localStorage.getItem('access_token') }
|
||||
});
|
||||
if (res.status === 401) this.logout();
|
||||
const json = await res.json();
|
||||
if (json.success) this.users = json.data;
|
||||
},
|
||||
|
||||
logout() {
|
||||
localStorage.clear();
|
||||
window.location.href = '/login.php';
|
||||
}
|
||||
}));
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user