m / index.html
mohammed2449's picture
📄 أمر تنفيذي: استكمال الوظائف الناقصة في تطبيق المتاجر الوطني 📌 الهدف: تنفيذ الوظائف التالية لضمان تجربة مستخدم متكاملة تشمل الطلبات، التقييم، الدعم الفني، الإشعارات، لوحة المشرف، وحماية البيانات. 🧩 المهام المطلوبة: 1. نظام الطلبات: - تصميم واجهة "طلب جديد" تشمل اختيار المنتج، الكمية، الدفع، والعنوان. - إنشاء قاعدة بيانات للطلبات (الحالة: pending, confirmed, delivered). - ربط الطلبات بواجهة المستخدم والمتجر عبر API موحد. - عرض سجل الطلبات في صفحة "طلباتي". 2. نظام التقييم والمراجعة: - واجهة تقييم بعد كل طلب (نجوم + تعليق). - حفظ التقييمات وربطها بالمتجر. - عرض متوسط التقييم في بطاقة المتجر. 3. نظام الدعم الفني: - دمج خدمة دردشة فورية (Firebase Chat أو WebSocket). - واجهة "الدعم الفني" تشمل إرسال رسالة، رفع صورة، متابعة الحالة. - لوحة تذاكر للمشرفين للرد على المستخدمين. 4. نظام الإشعارات الديناميكية: - إعداد خدمة إرسال إشعارات (FCM أو OneSignal). - لوحة تحكم لإرسال الإشعارات حسب القسم أو المتجر. - دعم الإشعارات التفاعلية (فتح صفحة معينة عند الضغط). 5. لوحة تحكم للمشرفين: - إدارة المتاجر، الطلبات، التقييمات، والإشعارات. - حماية الدخول بصلاحيات خاصة. - دعم الإحصائيات والرسوم البيانية. 6. حماية البيانات والخصوصية: - صفحة "الخصوصية" تشمل السياسات والموافقة. - دعم حذف الحساب وتصدير البيانات. - تشفير بيانات الجلسات والمفضلة محليًا. 🛠 التقنيات المقترحة: - الطلبات: RESTful API + SQLite أو MongoDB - التقييم: Firebase أو قاعدة بيانات محلية - الدعم الفني: Firebase Chat أو WebSocket - الإشعارات: FCM أو OneSignal - لوحة المشرف: React Admin أو لوحة مخصصة - الحماية: JWT + تشفير محلي 📅 الجدول الزمني المقترح: - الأسبوع 1: الطلبات والتقييم - الأسبوع 2: الدعم الفني والإشعارات - الأسبوع 3: لوحة المشرف والخصوصية - الأسبوع 4: اختبار شامل وتوثيق 📎 ملاحظات: - يجب توثيق كل وظيفة بشكل مستقل. - الالتزام بالتصميم الموحد واللغة العربية. - ضمان قابلية التوسع والتخصيص مستقبلاً. - Initial Deployment
6245a17 verified
<!DOCTYPE html>
<html lang="ar" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>مسار المستهلك</title>
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {
theme: {
extend: {
fontSize: {
'xxs': '0.6rem',
}
}
}
}
</script>
<link href="https://fonts.googleapis.com/css2?family=Tajawal:wght@400;500;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<!-- Rating Stars Template -->
<template id="ratingStarsTemplate">
<div class="flex items-center">
<div class="flex">
<i class="fas fa-star text-yellow-400"></i>
<i class="fas fa-star text-yellow-400"></i>
<i class="fas fa-star text-yellow-400"></i>
<i class="fas fa-star text-yellow-400"></i>
<i class="fas fa-star text-yellow-400"></i>
</div>
<span class="text-xs text-gray-500 mr-1">(0)</span>
</div>
</template>
<style>
body {
font-family: 'Tajawal', sans-serif;
transition: all 0.3s ease;
}
.slide-in {
animation: slideIn 0.3s forwards;
}
.slide-out {
animation: slideOut 0.3s forwards;
}
@keyframes slideIn {
from { transform: translateX(100%); }
to { transform: translateX(0); }
}
@keyframes slideOut {
from { transform: translateX(0); }
to { transform: translateX(100%); }
}
.ticker {
animation: ticker 20s linear infinite;
}
@keyframes ticker {
0% { transform: translateX(100%); }
100% { transform: translateX(-100%); }
}
.dark-mode {
background-color: #1a202c;
color: #f7fafc;
}
.dark-mode .sidebar {
background-color: #2d3748;
}
.dark-mode .card {
background-color: #2d3748;
}
/* New styles for smaller icons and modern design */
.icon-sm {
font-size: 1.1rem;
}
.store-card {
min-width: 120px;
height: 120px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
transition: all 0.2s ease;
}
.store-card:hover {
transform: translateY(-5px);
}
/* Bottom nav item animation */
nav a {
transition: all 0.2s ease;
}
nav a:hover, nav a.active {
color: #3b82f6;
}
</style>
</head>
<body class="bg-gray-100 text-gray-800">
<!-- Navigation Sidebar -->
<div class="fixed right-0 top-0 h-full w-64 bg-white shadow-lg z-50 transform translate-x-full sidebar transition-transform duration-300">
<div class="p-4 border-b border-gray-200 dark:border-gray-700">
<div class="flex items-center justify-between">
<h2 class="text-xl font-bold">مسار المستهلك</h2>
<button id="closeSidebar" class="text-gray-500 hover:text-gray-700 dark:text-gray-300 dark:hover:text-white">
<i class="fas fa-times"></i>
</button>
</div>
</div>
<nav class="p-4">
<ul class="space-y-4">
<li>
<a href="#" class="flex items-center p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700">
<i class="fas fa-home ml-2"></i>
<span>الصفحة الرئيسية</span>
</a>
</li>
<li>
<button id="categoriesBtn" class="flex items-center justify-between w-full p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700">
<div class="flex items-center">
<i class="fas fa-th-large ml-2"></i>
<span>الأقسام</span>
</div>
<i class="fas fa-chevron-down text-xs"></i>
</button>
<ul id="categoriesDropdown" class="hidden pl-4 mt-1 space-y-1">
<li><a href="#" class="block p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700">السوبر ماركت والأسواق العامة</a></li>
<li><a href="#" class="block p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700">الملابس والأزياء</a></li>
<li><a href="#" class="block p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700">الأثاث والمفروشات</a></li>
<li><a href="#" class="block p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700">الإلكترونيات والتقنية</a></li>
<li><a href="#" class="block p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700">العناية الشخصية والجمال</a></li>
<li><a href="#" class="block p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700">المطاعم والمقاهي</a></li>
<li><a href="#" class="block p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700">الصيدليات والرعاية الصحية</a></li>
<li><a href="#" class="block p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700">الخدمات المنزلية والصيانة</a></li>
<li><a href="#" class="block p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700">شركات التوصيل</a></li>
</ul>
</li>
<li>
<a href="#" class="flex items-center p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700">
<i class="fas fa-tags ml-2"></i>
<span>العروض والخصومات</span>
</a>
</li>
<li>
<a href="#" class="flex items-center p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700">
<i class="fas fa-cog ml-2"></i>
<span>الإعدادات</span>
</a>
</li>
<li>
<a href="#" class="flex items-center p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700">
<i class="fas fa-question-circle ml-2"></i>
<span>مركز المساعدة</span>
</a>
</li>
<li>
<a href="/admin" class="flex items-center p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700">
<i class="fas fa-tachometer-alt ml-2"></i>
<span>لوحة التحكم</span>
</a>
</li>
<li id="authMenuItem">
<a href="#" id="authBtn" class="flex items-center p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 text-blue-600 dark:text-blue-400">
<i class="fas fa-sign-in-alt ml-2" id="authIcon"></i>
<span id="authText">تسجيل الدخول</span>
</a>
</li>
<div id="userDropdown" class="hidden p-4 border-t border-gray-200 dark:border-gray-700">
<div class="flex items-center mb-4">
<img id="userAvatar" src="https://via.placeholder.com/40" class="rounded-full w-10 h-10 mr-3" alt="User">
<div>
<p id="userName" class="font-medium"></p>
<p id="userEmail" class="text-sm text-gray-500 dark:text-gray-400"></p>
</div>
</div>
<ul class="space-y-2">
<li><a href="#" class="flex items-center p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700"><i class="fas fa-cog ml-2"></i> الإعدادات</a></li>
<li><a href="#" class="flex items-center p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700"><i class="fas fa-shield-alt ml-2"></i> الأمان</a></li>
<li><a href="#" id="logoutBtn" class="flex items-center p-2 rounded-lg text-red-500 hover:bg-red-50 dark:hover:bg-red-900"><i class="fas fa-sign-out-alt ml-2"></i> تسجيل الخروج</a></li>
</ul>
</div>
</ul>
</nav>
</div>
<!-- Notifications Dropdown -->
<div id="notificationsDropdown" class="fixed right-4 top-16 w-72 bg-white dark:bg-gray-800 rounded-lg shadow-lg z-50 hidden border border-gray-200 dark:border-gray-700">
<div class="p-3 border-b border-gray-200 dark:border-gray-700 flex justify-between items-center">
<h3 class="font-bold">الإشعارات</h3>
<button id="markAllRead" class="text-blue-500 text-sm">تمييز الكل كمقروء</button>
</div>
<div class="max-h-96 overflow-y-auto">
<div id="notificationsList" class="p-2">
<!-- Notifications will be loaded dynamically -->
<div class="text-center py-4 text-gray-500">لا توجد إشعارات جديدة</div>
</div>
</div>
<div class="p-2 border-t border-gray-200 dark:border-gray-700 text-center">
<a href="/notifications" class="text-blue-500 text-sm">عرض جميع الإشعارات</a>
</div>
</div>
<!-- Main Content -->
<div class="container mx-auto px-4 pb-16">
<!-- Header -->
<header class="flex justify-between items-center py-4 sticky top-0 bg-white dark:bg-gray-800 z-40 shadow-sm">
<button id="menuBtn" class="text-gray-700 dark:text-gray-300">
<i class="fas fa-bars text-2xl"></i>
</button>
<h1 class="text-2xl font-bold text-blue-600 dark:text-blue-400">مسار المستهلك</h1>
<div class="flex items-center space-x-4 space-x-reverse">
<button id="notificationsBtn" class="relative text-gray-700 dark:text-gray-300">
<i class="fas fa-bell text-xl"></i>
<span id="notificationBadge" class="absolute -top-1 -right-1 bg-red-500 text-white text-xs rounded-full h-4 w-4 flex items-center justify-center hidden">0</span>
</button>
<button id="themeToggle" class="text-gray-700 dark:text-gray-300">
<i class="fas fa-moon text-xl"></i>
</button>
</header>
<!-- Ticker Slider -->
<div class="bg-blue-100 dark:bg-blue-900 p-2 mb-6 rounded-lg overflow-hidden">
<div class="flex items-center whitespace-nowrap ticker">
<div class="mx-4 text-blue-800 dark:text-blue-200">
<span class="font-bold">عرض خاص:</span> خصم ٣٠٪ على جميع المنتجات في سوق الجمال حتى نهاية الشهر
</div>
<div class="mx-4 text-blue-800 dark:text-blue-200">
<span class="font-bold">عرض جديد:</span> هاتف سامسونج جالكسي S23 مع هدية مجانية
</div>
<div class="mx-4 text-blue-800 dark:text-blue-200">
<span class="font-bold">عرض خاص:</span> توصيل مجاني لجميع الطلبات فوق ١٠٠ ريال
</div>
</div>
</div>
<!-- Quick Access Cards -->
<h2 class="text-xl font-bold mb-4">الإمكانيات السريعة</h2>
<div class="relative mb-8">
<div class="overflow-x-auto scrollbar-hide">
<div class="flex space-x-4 pb-4" id="cardsContainer">
<!-- Cards will be added dynamically -->
</div>
</div>
<button id="showMore" class="absolute left-0 bottom-0 bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition">
عرض المزيد <i class="fas fa-chevron-left mr-2"></i>
</button>
</div>
<!-- Favorite Stores -->
<h2 class="text-xl font-bold mb-4">متاجري المفضلة</h2>
<div class="relative mb-8">
<div class="overflow-x-auto scrollbar-hide">
<div class="flex space-x-4 pb-4" id="favoritesContainer">
<!-- Favorite stores will be added dynamically -->
</div>
</div>
<button id="addFavorite" class="absolute left-0 bottom-0 bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition">
إضافة متجر جديد <i class="fas fa-plus mr-2"></i>
</button>
</div>
<!-- Stores Section (hidden by default) -->
<div id="storesSection" class="hidden mb-8">
<div class="flex justify-between items-center mb-4">
<h2 class="text-xl font-bold" id="storeSectionTitle">المتاجر</h2>
<button id="backToCategories" class="text-blue-600 dark:text-blue-400">
<i class="fas fa-arrow-left mr-2"></i> الرجوع للأقسام
</button>
</div>
<!-- Search Bar -->
<div class="mb-4 relative">
<input type="text" id="storeSearch" placeholder="ابحث عن متجر..."
class="w-full p-3 rounded-lg border border-gray-300 dark:border-gray-600 dark:bg-gray-700">
<i class="fas fa-search absolute left-3 top-3.5 text-gray-400"></i>
</div>
<!-- Stores Grid -->
<div class="grid grid-cols-2 md:grid-cols-4 gap-4" id="storesGrid">
<!-- Stores will be loaded dynamically -->
</div>
</div>
<!-- Store View Container (hidden by default) -->
<div id="storeViewContainer" class="hidden fixed inset-0 bg-white dark:bg-gray-800 z-50 overflow-y-auto">
<div class="container mx-auto px-4 py-4">
<div class="flex justify-between items-center mb-4 sticky top-0 bg-white dark:bg-gray-800 py-2 z-10">
<h2 class="text-xl font-bold" id="storeNameHeader"></h2>
<button id="closeStoreView" class="text-red-500">
<i class="fas fa-times text-xl"></i>
</button>
</div>
<!-- WebView Container -->
<div id="storeWebView" class="w-full h-screen">
<!-- Store content will be loaded here via WebView/API -->
</div>
</div>
</div>
<!-- Offers Section -->
<h2 class="text-xl font-bold mb-4">عروض اليوم</h2>
<div class="grid md:grid-cols-2 gap-4 mb-8">
<div class="bg-gradient-to-r from-blue-500 to-blue-700 text-white p-6 rounded-lg">
<h3 class="text-xl font-bold mb-2">خصم يصل إلى ٤٠٪</h3>
<p class="mb-4">على جميع الأجهزة المنزلية في سوق الإلكترونيات</p>
<button class="bg-white text-blue-600 px-4 py-2 rounded-lg font-bold">عرض التفاصيل</button>
</div>
<div class="bg-gradient-to-r from-green-500 to-green-700 text-white p-6 rounded-lg">
<h3 class="text-xl font-bold mb-2">٢+١ مجانًا</h3>
<p class="mb-4">على منتجات العناية بالبشرة في صيدليات النهدي</p>
<button class="bg-white text-green-600 px-4 py-2 rounded-lg font-bold">عرض التفاصيل</button>
</div>
</div>
</div>
<script>
// Sample data for quick access cards
const quickAccessItems = [
{ icon: 'fa-search', title: 'بحث سريع', color: 'bg-blue-100', textColor: 'text-blue-600' },
{ icon: 'fa-history', title: 'آخر العروض', color: 'bg-green-100', textColor: 'text-green-600' },
{ icon: 'fa-star', title: 'المفضلة', color: 'bg-yellow-100', textColor: 'text-yellow-600' },
{ icon: 'fa-map-marker-alt', title: 'أقرب متجر', color: 'bg-red-100', textColor: 'text-red-600' },
{ icon: 'fa-bell', title: 'التنبيهات', color: 'bg-purple-100', textColor: 'text-purple-600' },
{ icon: 'fa-wallet', title: 'المحفظة', color: 'bg-indigo-100', textColor: 'text-indigo-600' },
];
// DOM Elements
const menuBtn = document.getElementById('menuBtn');
const closeSidebar = document.getElementById('closeSidebar');
const sidebar = document.querySelector('.sidebar');
const themeToggle = document.getElementById('themeToggle');
const cardsContainer = document.getElementById('cardsContainer');
const showMore = document.getElementById('showMore');
const body = document.body;
// Initialize cards
function initCards() {
quickAccessItems.forEach(item => {
const card = document.createElement('div');
card.className = `flex-shrink-0 w-24 h-24 ${item.color} ${item.textColor} rounded-lg p-3 shadow-md flex flex-col items-center justify-center`;
card.innerHTML = `
<i class="fas ${item.icon} text-base mb-1"></i>
<span class="font-bold text-xxs">${item.title}</span>
`;
cardsContainer.appendChild(card);
});
}
// Toggle categories dropdown
document.getElementById('categoriesBtn').addEventListener('click', function(e) {
e.preventDefault();
document.getElementById('categoriesDropdown').classList.toggle('hidden');
this.querySelector('.fa-chevron-down').classList.toggle('fa-rotate-180');
});
// Close dropdown when clicking outside
document.addEventListener('click', function(e) {
if (!e.target.closest('#categoriesBtn') && !e.target.closest('#categoriesDropdown')) {
document.getElementById('categoriesDropdown').classList.add('hidden');
document.querySelector('#categoriesBtn .fa-chevron-down').classList.remove('fa-rotate-180');
}
});
// Toggle sidebar
menuBtn.addEventListener('click', () => {
sidebar.classList.remove('translate-x-full');
sidebar.classList.add('slide-in');
});
closeSidebar.addEventListener('click', () => {
sidebar.classList.add('translate-x-full');
sidebar.classList.add('slide-out');
});
// Toggle theme
themeToggle.addEventListener('click', () => {
body.classList.toggle('dark-mode');
const icon = themeToggle.querySelector('i');
if (body.classList.contains('dark-mode')) {
icon.classList.replace('fa-moon', 'fa-sun');
localStorage.setItem('theme', 'dark');
} else {
icon.classList.replace('fa-sun', 'fa-moon');
localStorage.setItem('theme', 'light');
}
});
// Check for saved theme preference
if (localStorage.getItem('theme') === 'dark') {
body.classList.add('dark-mode');
themeToggle.querySelector('i').classList.replace('fa-moon', 'fa-sun');
}
// Show more button
showMore.addEventListener('click', () => {
alert('سيتم عرض جميع البطاقات في صفحة منفصلة');
});
// Store data (mock - should be replaced with API calls)
const storesData = {
'supermarkets': [
{ id: 'market1', name: 'سوق الرياض', logo: 'fa-store', apiUrl: 'https://api.example.com/markets/1' },
{ id: 'market2', name: 'هايبر بنده', logo: 'fa-shopping-basket', apiUrl: 'https://api.example.com/markets/2' }
],
'fashion': [
{ id: 'fashion1', name: 'زد', logo: 'fa-tshirt', apiUrl: 'https://api.example.com/fashion/1' }
],
'furniture': [
{ id: 'furniture1', name: 'إيكيا', logo: 'fa-couch', apiUrl: 'https://api.example.com/furniture/1' }
],
'electronics': [
{ id: 'electronics1', name: 'إكسترا', logo: 'fa-laptop', apiUrl: 'https://api.example.com/electronics/1' }
],
'beauty': [
{ id: 'beauty1', name: 'سيفورا', logo: 'fa-spa', apiUrl: 'https://api.example.com/beauty/1' }
],
'restaurants': [
{ id: 'restaurant1', name: 'مطاعم هرفي', logo: 'fa-utensils', apiUrl: 'https://api.example.com/restaurants/1' }
],
'pharmacies': [
{ id: 'pharmacy1', name: 'صيدليات النهدي', logo: 'fa-prescription-bottle-alt', apiUrl: 'https://api.example.com/pharmacies/1' }
],
'services': [
{ id: 'service1', name: 'نجارون', logo: 'fa-tools', apiUrl: 'https://api.example.com/services/1' }
],
'delivery': [
{ id: 'delivery1', name: 'هنقرستيشن', logo: 'fa-motorcycle', apiUrl: 'https://api.example.com/delivery/1' }
]
};
// Current session state
const appState = {
currentCategory: null,
currentStore: null,
storeSessions: JSON.parse(localStorage.getItem('storeSessions')) || {}
};
// Auth State
const authState = {
isAuthenticated: false,
accessToken: null,
refreshToken: null,
userInfo: null,
tokenExpiry: null
};
// Sample favorite stores data
const favoriteStores = [
{ id: 'fav1', name: 'سوق الرياض', icon: 'fa-store' },
{ id: 'fav2', name: 'النهدي', icon: 'fa-prescription-bottle-alt' },
{ id: 'fav3', name: 'إلكترونيات', icon: 'fa-laptop' }
];
// Initialize favorite stores
function initFavorites() {
const container = document.getElementById('favoritesContainer');
favoriteStores.forEach(store => {
const element = document.createElement('div');
element.className = 'store-card bg-white dark:bg-gray-700 p-4 rounded-lg shadow-md flex-shrink-0';
element.innerHTML = `
<i class="fas ${store.icon} text-base text-blue-500 mb-2"></i>
<span class="text-sm font-medium">${store.name}</span>
`;
container.appendChild(element);
});
}
// Initialize the app
document.addEventListener('DOMContentLoaded', () => {
initCards();
initFavorites();
setupStoreView();
loadSavedSessions();
initAuth();
// Set first nav item as active
document.querySelector('nav a').classList.add('active');
});
// Auth Functions
function initAuth() {
// Check for existing auth in localStorage
const savedAuth = localStorage.getItem('unifiedAuth');
if (savedAuth) {
const authData = JSON.parse(savedAuth);
if (new Date(authData.tokenExpiry) > new Date()) {
authState.isAuthenticated = true;
authState.accessToken = authData.accessToken;
authState.refreshToken = authData.refreshToken;
authState.userInfo = authData.userInfo;
authState.tokenExpiry = new Date(authData.tokenExpiry);
updateAuthUI();
} else {
// Token expired, try refresh
refreshToken(authData.refreshToken);
}
}
// Setup auth button handlers
document.getElementById('authBtn').addEventListener('click', toggleAuthModal);
document.getElementById('closeLoginModal').addEventListener('click', () => {
document.getElementById('loginModal').classList.add('hidden');
});
document.getElementById('loginBtn').addEventListener('click', handleLogin);
document.getElementById('sendOtpBtn').addEventListener('click', sendOTP);
document.getElementById('verifyOtpBtn').addEventListener('click', verifyOTP);
document.getElementById('logoutBtn').addEventListener('click', handleLogout);
}
function toggleAuthModal() {
if (authState.isAuthenticated) {
document.getElementById('userDropdown').classList.toggle('hidden');
} else {
document.getElementById('loginModal').classList.remove('hidden');
}
}
async function handleLogin() {
const email = document.getElementById('emailInput').value;
const password = document.getElementById('passwordInput').value;
try {
// In real app, this would call your OAuth 2.0/OpenID Connect endpoint
const response = await mockLogin(email, password);
authState.isAuthenticated = true;
authState.accessToken = response.access_token;
authState.refreshToken = response.refresh_token;
authState.userInfo = response.user_info;
authState.tokenExpiry = new Date(new Date().getTime() + (response.expires_in * 1000));
localStorage.setItem('unifiedAuth', JSON.stringify(authState));
updateAuthUI();
document.getElementById('loginModal').classList.add('hidden');
// Check if 2FA is required
if (response.requires_2fa) {
document.getElementById('twoFAModal').classList.remove('hidden');
}
} catch (error) {
alert('فشل تسجيل الدخول: ' + error.message);
}
}
function mockLogin(email, password) {
return new Promise((resolve, reject) => {
// Simulate API call
setTimeout(() => {
if (email && password) {
resolve({
access_token: 'mock_access_token_' + Math.random().toString(36).substr(2, 9),
refresh_token: 'mock_refresh_token_' + Math.random().toString(36).substr(2, 9),
expires_in: 3600,
token_type: 'Bearer',
user_info: {
name: 'محمد أحمد',
email: email,
phone: '0501234567',
avatar: 'https://via.placeholder.com/150'
},
requires_2fa: false
});
} else {
reject(new Error('البريد الإلكتروني أو كلمة المرور غير صحيحة'));
}
}, 1000);
});
}
function updateAuthUI() {
if (authState.isAuthenticated) {
document.getElementById('authIcon').classList.replace('fa-sign-in-alt', 'fa-user-circle');
document.getElementById('authText').textContent = authState.userInfo.name.split(' ')[0];
document.getElementById('userName').textContent = authState.userInfo.name;
document.getElementById('userEmail').textContent = authState.userInfo.email;
document.getElementById('userAvatar').src = authState.userInfo.avatar;
} else {
document.getElementById('authIcon').classList.replace('fa-user-circle', 'fa-sign-in-alt');
document.getElementById('authText').textContent = 'تسجيل الدخول';
document.getElementById('userDropdown').classList.add('hidden');
}
}
function handleLogout() {
// Call logout endpoint
fetch('/auth/logout', {
method: 'POST',
headers: {
'Authorization': `Bearer ${authState.accessToken}`
}
});
// Clear auth state
authState.isAuthenticated = false;
authState.accessToken = null;
authState.refreshToken = null;
authState.userInfo = null;
authState.tokenExpiry = null;
localStorage.removeItem('unifiedAuth');
updateAuthUI();
}
function refreshToken(refreshToken) {
// Implement token refresh logic
console.log('Refreshing token...');
}
function sendOTP() {
const mobile = document.getElementById('mobileInput').value;
if (!mobile) {
alert('من فضلك أدخل رقم الجوال');
return;
}
// Simulate sending OTP
document.getElementById('otpMobileNumber').textContent = '+966' + mobile;
document.getElementById('loginBtn').classList.add('hidden');
document.getElementById('otpSection').classList.remove('hidden');
document.getElementById('sendOtpBtn').style.display = 'none';
}
function verifyOTP() {
// Verify OTP logic would go here
alert('تم التحقق بنجاح');
document.getElementById('loginModal').classList.add('hidden');
}
// Handle category navigation
function setupCategoryNavigation() {
// Set up category links in dropdown
document.querySelectorAll('#categoriesDropdown a').forEach(link => {
link.addEventListener('click', (e) => {
e.preventDefault();
const categoryName = link.textContent.trim();
// Map readable category names to data keys
const categoryMap = {
'السوبر ماركت والأسواق العامة': 'supermarkets',
'الملابس والأزياء': 'fashion',
'الأثاث والمفروشات': 'furniture',
'الإلكترونيات والتقنية': 'electronics',
'العناية الشخصية والجمال': 'beauty',
'المطاعم والمقاهي': 'restaurants',
'الصيدليات والرعاية الصحية': 'pharmacies',
'الخدمات المنزلية والصيانة': 'services',
'شركات التوصيل': 'delivery'
};
const category = categoryMap[categoryName];
if (category) {
appState.currentCategory = category;
showStoresForCategory(category);
sidebar.classList.add('translate-x-full');
}
});
});
document.getElementById('backToCategories').addEventListener('click', () => {
document.getElementById('storesSection').classList.add('hidden');
document.querySelector('#categoriesContainer').classList.remove('hidden');
});
}
// Show stores for selected category
function showStoresForCategory(category) {
document.querySelector('#categoriesContainer').classList.add('hidden');
const storesSection = document.getElementById('storesSection');
storesSection.classList.remove('hidden');
document.getElementById('storeSectionTitle').textContent = `متاجر ${category}`;
const storesGrid = document.getElementById('storesGrid');
storesGrid.innerHTML = '';
// Load stores from API - using mock data here
const stores = storesData[category] || [];
stores.forEach(store => {
const storeElement = document.createElement('div');
storeElement.className = 'store-card bg-white dark:bg-gray-700 p-4 rounded-lg shadow-md text-center cursor-pointer hover:shadow-lg transition';
storeElement.dataset.storeId = store.id;
storeElement.innerHTML = `
<i class="fas ${store.logo} text-2xl text-blue-500 mb-2"></i>
<h3 class="font-bold">${store.name}</h3>
${appState.storeSessions[store.id] ?
'<span class="text-xs text-green-500 block mt-1">لديك جلسة سابقة</span>' : ''}
`;
storeElement.addEventListener('click', () => {
openStore(store);
});
storesGrid.appendChild(storeElement);
});
}
// Open store in WebView
function openStore(store) {
appState.currentStore = store.id;
const storeView = document.getElementById('storeViewContainer');
storeView.classList.remove('hidden');
document.getElementById('storeNameHeader').textContent = store.name;
// Load store content - in a real app this would be a WebView or API call
const storeContent = document.getElementById('storeWebView');
storeContent.innerHTML = `
<iframe src="${store.apiUrl}" class="w-full h-full"
frameborder="0" allowfullscreen></iframe>
`;
// Restore session if available
if (appState.storeSessions[store.id]) {
// In a real app, would restore scroll position and state
console.log(`Restoring session for ${store.name}`);
}
}
// Setup store view controls
function setupStoreView() {
document.getElementById('closeStoreView').addEventListener('click', () => {
// Save current session before closing
if (appState.currentStore) {
appState.storeSessions[appState.currentStore] = {
lastVisited: new Date().toISOString(),
// In a real app, would save scroll position and other state
url: window.location.href
};
localStorage.setItem('storeSessions', JSON.stringify(appState.storeSessions));
}
document.getElementById('storeViewContainer').classList.add('hidden');
});
}
// Load saved sessions
function loadSavedSessions() {
if (Object.keys(appState.storeSessions).length > 0) {
// Could show a quick access section for stores with saved sessions
console.log('Loaded saved store sessions:', appState.storeSessions);
}
}
// Search functionality
document.getElementById('storeSearch').addEventListener('input', (e) => {
const searchTerm = e.target.value.toLowerCase();
const storeCards = document.querySelectorAll('.store-card');
storeCards.forEach(card => {
const storeName = card.querySelector('h3').textContent.toLowerCase();
card.style.display = storeName.includes(searchTerm) ? 'block' : 'none';
});
});
// Handle swipe gestures for mobile
let touchStartX = 0;
let touchEndX = 0;
document.addEventListener('touchstart', e => {
touchStartX = e.changedTouches[0].screenX;
}, false);
document.addEventListener('touchend', e => {
touchEndX = e.changedTouches[0].screenX;
handleSwipe();
}, false);
function handleSwipe() {
if (touchStartX - touchEndX > 50) {
// Swipe left - open sidebar
sidebar.classList.remove('translate-x-full');
sidebar.classList.add('slide-in');
}
if (touchEndX - touchStartX > 50 && !sidebar.classList.contains('translate-x-full')) {
// Swipe right - close sidebar
sidebar.classList.add('translate-x-full');
sidebar.classList.add('slide-out');
}
}
</script>
<!-- Bottom Navigation Bar -->
<nav class="fixed bottom-0 left-0 right-0 bg-white dark:bg-gray-800 border-t border-gray-200 dark:border-gray-700 flex justify-around items-center py-3 z-40">
<a href="#" class="flex flex-col items-center text-blue-600 dark:text-blue-400">
<i class="fas fa-home text-xl mb-1"></i>
<span class="text-xs">الرئيسية</span>
</a>
<a href="#" class="flex flex-col items-center text-gray-600 dark:text-gray-400">
<i class="fas fa-search text-xl mb-1"></i>
<span class="text-xs">البحث</span>
</a>
<a href="#" class="flex flex-col items-center text-gray-600 dark:text-gray-400">
<i class="fas fa-shopping-bag text-xl mb-1"></i>
<span class="text-xs">طلباتي</span>
</a>
<a href="#" class="flex flex-col items-center text-gray-600 dark:text-gray-400">
<i class="fas fa-user text-xl mb-1"></i>
<span class="text-xs">ملفي</span>
</a>
<a href="#" id="liveSupportBtn" class="flex flex-col items-center text-gray-600 dark:text-gray-400">
<i class="fas fa-headset text-xl mb-1"></i>
<span class="text-xs">المساعدة</span>
</a>
</nav>
<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=mohammed2449/m" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>