Truck Owners
diff --git a/assets/css/custom.css b/assets/css/custom.css
index 0fa6bd7..2426c8d 100644
--- a/assets/css/custom.css
+++ b/assets/css/custom.css
@@ -238,8 +238,10 @@ body.app-body {
.admin-sidebar {
position: sticky;
- top: 88px;
- border-radius: 16px;
+ top: 76px;
+ height: calc(100vh - 76px);
+ overflow-y: auto;
+ border-radius: 0;
}
.admin-nav-link {
@@ -289,5 +291,7 @@ body.app-body {
.admin-sidebar {
position: static;
+ height: auto;
+ overflow-y: visible;
}
}
\ No newline at end of file
diff --git a/db/migrations/add_arabic_landing_fields.php b/db/migrations/add_arabic_landing_fields.php
new file mode 100644
index 0000000..74e6ce0
--- /dev/null
+++ b/db/migrations/add_arabic_landing_fields.php
@@ -0,0 +1,24 @@
+exec("ALTER TABLE landing_sections ADD COLUMN title_ar VARCHAR(255) NULL AFTER title");
+ echo "Added title_ar.\n";
+} catch (PDOException $e) { echo "title_ar likely exists.\n"; }
+
+try {
+ $pdo->exec("ALTER TABLE landing_sections ADD COLUMN subtitle_ar TEXT NULL AFTER subtitle");
+ echo "Added subtitle_ar.\n";
+} catch (PDOException $e) { echo "subtitle_ar likely exists.\n"; }
+
+try {
+ $pdo->exec("ALTER TABLE landing_sections ADD COLUMN content_ar TEXT NULL AFTER content");
+ echo "Added content_ar.\n";
+} catch (PDOException $e) { echo "content_ar likely exists.\n"; }
+
+try {
+ $pdo->exec("ALTER TABLE landing_sections ADD COLUMN button_text_ar VARCHAR(100) NULL AFTER button_text");
+ echo "Added button_text_ar.\n";
+} catch (PDOException $e) { echo "button_text_ar likely exists.\n"; }
+
diff --git a/db/migrations/add_notification_templates.php b/db/migrations/add_notification_templates.php
new file mode 100644
index 0000000..114605b
--- /dev/null
+++ b/db/migrations/add_notification_templates.php
@@ -0,0 +1,70 @@
+exec("
+ CREATE TABLE IF NOT EXISTS notification_templates (
+ id INT AUTO_INCREMENT PRIMARY KEY,
+ event_name VARCHAR(50) NOT NULL UNIQUE,
+ email_subject_en VARCHAR(255),
+ email_body_en TEXT,
+ email_subject_ar VARCHAR(255),
+ email_body_ar TEXT,
+ whatsapp_body_en TEXT,
+ whatsapp_body_ar TEXT,
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
+ );
+ ");
+
+ // Insert default templates
+ $defaults = [
+ [
+ 'event_name' => 'shipment_created',
+ 'email_subject_en' => 'Shipment Created: #{shipment_id}',
+ 'email_body_en' => "Dear {user_name},\n\nYour shipment from {origin} to {destination} has been successfully created.\n\nShipment ID: {shipment_id}\n\nWe will notify you when a truck owner submits an offer.",
+ 'email_subject_ar' => 'تم إنشاء الشحنة: #{shipment_id}',
+ 'email_body_ar' => "عزيزي {user_name}،\n\nتم إنشاء شحنتك من {origin} إلى {destination} بنجاح.\n\nرقم الشحنة: {shipment_id}\n\nسنقوم بإعلامك عند تقديم عرض من قبل صاحب شاحنة.",
+ 'whatsapp_body_en' => "Shipment #{shipment_id} created successfully from {origin} to {destination}.",
+ 'whatsapp_body_ar' => "تم إنشاء الشحنة #{shipment_id} بنجاح من {origin} إلى {destination}."
+ ],
+ [
+ 'event_name' => 'shipment_offered',
+ 'email_subject_en' => 'New Offer for Shipment #{shipment_id}',
+ 'email_body_en' => "Dear {user_name},\n\nA truck owner has submitted an offer for your shipment #{shipment_id}.\n\nOffer Price: {offer_price}\nTruck Owner: {offer_owner}\n\nPlease login to your dashboard to accept or reject this offer.",
+ 'email_subject_ar' => 'عرض جديد للشحنة #{shipment_id}',
+ 'email_body_ar' => "عزيزي {user_name}،\n\nلقد قدم صاحب شاحنة عرضًا لشحنتك #{shipment_id}.\n\nسعر العرض: {offer_price}\nصاحب الشاحنة: {offer_owner}\n\nيرجى تسجيل الدخول إلى لوحة التحكم لقبول أو رفض العرض.",
+ 'whatsapp_body_en' => "New offer for shipment #{shipment_id}: {offer_price}. Check your dashboard.",
+ 'whatsapp_body_ar' => "عرض جديد للشحنة #{shipment_id}: {offer_price}. تحقق من لوحة التحكم."
+ ],
+ [
+ 'event_name' => 'shipment_accepted',
+ 'email_subject_en' => 'Offer Accepted: Shipment #{shipment_id}',
+ 'email_body_en' => "Dear {user_name},\n\nYour offer for shipment #{shipment_id} has been accepted and paid for by the shipper.\n\nPlease proceed with the shipment.",
+ 'email_subject_ar' => 'تم قبول العرض: الشحنة #{shipment_id}',
+ 'email_body_ar' => "عزيزي {user_name}،\n\nتم قبول عرضك للشحنة #{shipment_id} ودفع ثمنه من قبل الشاحن.\n\nيرجى المتابعة في إجراءات الشحن.",
+ 'whatsapp_body_en' => "Your offer for shipment #{shipment_id} was accepted. Please proceed.",
+ 'whatsapp_body_ar' => "تم قبول عرضك للشحنة #{shipment_id}. يرجى المتابعة."
+ ],
+ [
+ 'event_name' => 'shipment_rejected',
+ 'email_subject_en' => 'Offer Rejected: Shipment #{shipment_id}',
+ 'email_body_en' => "Dear {user_name},\n\nYour offer for shipment #{shipment_id} was not accepted by the shipper.\n\nThe shipment is now back to 'Posted' status.",
+ 'email_subject_ar' => 'تم رفض العرض: الشحنة #{shipment_id}',
+ 'email_body_ar' => "عزيزي {user_name}،\n\nلم يتم قبول عرضك للشحنة #{shipment_id} من قبل الشاحن.\n\nعادت الشحنة الآن إلى حالة 'منشورة'.",
+ 'whatsapp_body_en' => "Your offer for shipment #{shipment_id} was rejected.",
+ 'whatsapp_body_ar' => "تم رفض عرضك للشحنة #{shipment_id}."
+ ]
+ ];
+
+ $stmt = $pdo->prepare("INSERT IGNORE INTO notification_templates (event_name, email_subject_en, email_body_en, email_subject_ar, email_body_ar, whatsapp_body_en, whatsapp_body_ar) VALUES (:event_name, :email_subject_en, :email_body_en, :email_subject_ar, :email_body_ar, :whatsapp_body_en, :whatsapp_body_ar)");
+
+ foreach ($defaults as $d) {
+ $stmt->execute($d);
+ }
+
+ echo "Notification templates table created and defaults inserted.";
+} catch (PDOException $e) {
+ echo "Error: " . $e->getMessage();
+}
diff --git a/db/migrations/add_user_ids_to_shipments.php b/db/migrations/add_user_ids_to_shipments.php
new file mode 100644
index 0000000..21ed1f4
--- /dev/null
+++ b/db/migrations/add_user_ids_to_shipments.php
@@ -0,0 +1,15 @@
+exec("ALTER TABLE shipments ADD COLUMN shipper_id INT NULL AFTER id");
+ $pdo->exec("ALTER TABLE shipments ADD COLUMN truck_owner_id INT NULL AFTER offer_price");
+
+ // Add FK constraints (optional but good practice, keeping it simple for now to avoid issues with existing data)
+ // We won't enforce FK strictly on existing data as it might be NULL
+
+ echo "Added shipper_id and truck_owner_id to shipments table.";
+} catch (PDOException $e) {
+ echo "Error (might already exist): " . $e->getMessage();
+}
diff --git a/includes/NotificationService.php b/includes/NotificationService.php
new file mode 100644
index 0000000..0bbe892
--- /dev/null
+++ b/includes/NotificationService.php
@@ -0,0 +1,73 @@
+ 123])
+ * @param string|null $lang 'en' or 'ar'. If null, sends both combined.
+ */
+ public static function send(string $eventName, array $user, array $data = [], ?string $lang = null)
+ {
+ $pdo = db();
+ $stmt = $pdo->prepare("SELECT * FROM notification_templates WHERE event_name = ?");
+ $stmt->execute([$eventName]);
+ $template = $stmt->fetch();
+
+ if (!$template) {
+ error_log("Notification template not found: $eventName");
+ return;
+ }
+
+ // Prepare data for replacement
+ $placeholders = [];
+ $values = [];
+ $data['user_name'] = $user['full_name'] ?? 'User';
+
+ foreach ($data as $key => $val) {
+ $placeholders[] = '{' . $key . '}';
+ $values[] = $val;
+ }
+
+ // Determine Subject and Body based on Lang
+ $subject = '';
+ $body = '';
+ $whatsapp = '';
+
+ if ($lang === 'en') {
+ $subject = $template['email_subject_en'];
+ $body = $template['email_body_en'];
+ $whatsapp = $template['whatsapp_body_en'];
+ } elseif ($lang === 'ar') {
+ $subject = $template['email_subject_ar'];
+ $body = $template['email_body_ar'];
+ $whatsapp = $template['whatsapp_body_ar'];
+ } else {
+ // Combined
+ $subject = $template['email_subject_en'] . ' / ' . $template['email_subject_ar'];
+ $body = $template['email_body_en'] . "\n\n---\n\n" . $template['email_body_ar'];
+ $whatsapp = $template['whatsapp_body_en'] . "\n\n" . $template['whatsapp_body_ar'];
+ }
+
+ // Replace
+ $subject = str_replace($placeholders, $values, $subject);
+ $body = str_replace($placeholders, $values, $body);
+ $whatsapp = str_replace($placeholders, $values, $whatsapp);
+
+ // Send Email
+ if (!empty($user['email'])) {
+ // Convert newlines to BR for HTML
+ $htmlBody = nl2br(htmlspecialchars($body));
+ MailService::sendMail($user['email'], $subject, $htmlBody, $body);
+ }
+
+ // Log WhatsApp (Mock)
+ // In a real app, this would call Twilio/Meta API
+ error_log("WHATSAPP Notification to {$user['email']} (Phone N/A): $whatsapp");
+ }
+}
diff --git a/includes/app.php b/includes/app.php
index 3fddf14..eadc88d 100644
--- a/includes/app.php
+++ b/includes/app.php
@@ -13,142 +13,366 @@ $_SESSION['lang'] = $lang;
$dir = $lang === 'ar' ? 'rtl' : 'ltr';
$translations = [
- 'en' => [
- 'app_name' => 'CargoLink',
- 'nav_home' => 'Overview',
- 'nav_shipper' => 'Shipper Desk',
- 'nav_owner' => 'Truck Owner Desk',
- 'nav_admin' => 'Admin Panel',
- 'hero_title' => 'Move cargo faster with verified trucks.',
- 'hero_subtitle' => 'Post shipments, collect offers, and pay via Thawani or bank transfer. Built for local and nearby cross-border moves.',
- 'hero_tagline' => 'Multilingual Logistics Marketplace',
- 'register_shipper' => 'Register as Shipper',
- 'register_owner' => 'Register as Truck Owner',
- 'cta_shipper' => 'Post a shipment',
- 'cta_owner' => 'Find loads',
- 'cta_admin' => 'Open admin',
- 'stats_shipments' => 'Shipments posted',
- 'stats_offers' => 'Active offers',
- 'stats_confirmed' => 'Confirmed trips',
- 'section_workflow' => 'How it works',
- 'recent_shipments' => 'Recent shipments',
- 'step_post' => 'Shipper posts cargo details and preferred payment.',
- 'step_offer' => 'Truck owners respond with their best rate.',
- 'step_confirm' => 'Admin confirms booking and status.',
- 'shipper_dashboard' => 'Shipper Dashboard',
- 'new_shipment' => 'Create shipment',
- 'shipper_name' => 'Shipper name',
- 'shipper_company' => 'Company',
- 'origin' => 'Origin city',
- 'destination' => 'Destination city',
- 'cargo' => 'Cargo description',
- 'weight' => 'Weight (tons)',
- 'pickup_date' => 'Pickup date',
- 'delivery_date' => 'Delivery date',
- 'payment_method' => 'Payment method',
- 'payment_thawani' => 'Thawani online payment',
- 'payment_bank' => 'Bank transfer',
- 'submit_shipment' => 'Submit shipment',
- 'shipments_list' => 'Your latest shipments',
- 'status' => 'Status',
- 'offer' => 'Best offer',
- 'actions' => 'Actions',
- 'view' => 'View',
- 'owner_dashboard' => 'Truck Owner Dashboard',
- 'available_shipments' => 'Available shipments',
- 'offer_price' => 'Offer price',
- 'offer_owner' => 'Truck owner name',
- 'submit_offer' => 'Send offer',
- 'admin_dashboard' => 'Admin Dashboard',
- 'update_status' => 'Update status',
- 'save' => 'Save',
- 'shipment_detail' => 'Shipment detail',
- 'created_at' => 'Created',
- 'best_offer' => 'Best offer',
- 'assign_owner' => 'Assigned owner',
- 'no_shipments' => 'No shipments yet. Create the first one to get started.',
- 'no_offers' => 'No offers yet.',
- 'success_shipment' => 'Shipment posted successfully.',
- 'success_offer' => 'Offer submitted to the shipper.',
- 'success_status' => 'Status updated.',
- 'error_required' => 'Please fill in all required fields.',
- 'error_invalid' => 'Please enter valid values.',
- 'status_posted' => 'Posted',
- 'status_offered' => 'Offered',
- 'status_confirmed' => 'Confirmed',
- 'status_in_transit' => 'In transit',
- 'status_delivered' => 'Delivered',
- 'footer_note' => 'This is the initial MVP slice. Payments are not yet connected.',
-'marketing_title_1' => 'For Shippers', 'marketing_desc_1' => 'Find the right truck for your cargo quickly and securely. Post your load and get offers instantly.', 'marketing_title_2' => 'For Truck Owners', 'marketing_desc_2' => 'Maximize your earnings and eliminate empty miles. Browse available shipments and offer your rate.', 'motivation_phrase' => 'Empowering the logistics of tomorrow.', 'why_choose_us' => 'لماذا تختار كارجو لينك؟', 'feature_1_title' => 'Fast Matching', 'feature_1_desc' => 'Connect with available trucks or shipments in minutes.', 'feature_2_title' => 'Secure Payments', 'feature_2_desc' => 'Your transactions are protected with security.', 'feature_3_title' => 'Verified Users', 'feature_3_desc' => 'We verify all truck owners to ensure peace of mind.',
- ],
- 'ar' => [
- 'app_name' => 'CargoLink',
- 'nav_home' => 'نظرة عامة',
- 'nav_shipper' => 'لوحة الشاحن',
- 'nav_owner' => 'لوحة مالك الشاحنة',
- 'nav_admin' => 'لوحة الإدارة',
- 'hero_title' => 'انقل شحنتك بسرعة مع شاحنات موثوقة.',
- 'hero_subtitle' => 'أنشئ شحنة، استلم عروضاً، وادفع عبر ثواني أو التحويل البنكي.',
- 'hero_tagline' => 'منصة لوجستية متعددة اللغات',
- 'register_shipper' => 'التسجيل كشاحن',
- 'register_owner' => 'التسجيل كمالك شاحنة',
- 'cta_shipper' => 'إنشاء شحنة',
- 'cta_owner' => 'البحث عن الشحنات',
- 'cta_admin' => 'الدخول للإدارة',
- 'stats_shipments' => 'الشحنات المنشورة',
- 'stats_offers' => 'العروض الحالية',
- 'stats_confirmed' => 'الرحلات المؤكدة',
- 'section_workflow' => 'طريقة العمل',
- 'recent_shipments' => 'أحدث الشحنات',
- 'step_post' => 'يقوم الشاحن بإدخال تفاصيل الشحنة وطريقة الدفع.',
- 'step_offer' => 'يرسل أصحاب الشاحنات أفضل عروضهم.',
- 'step_confirm' => 'تؤكد الإدارة الحجز وتحدث الحالة.',
- 'shipper_dashboard' => 'لوحة الشاحن',
- 'new_shipment' => 'إنشاء شحنة',
- 'shipper_name' => 'اسم الشاحن',
- 'shipper_company' => 'الشركة',
- 'origin' => 'مدينة الانطلاق',
- 'destination' => 'مدينة الوصول',
- 'cargo' => 'وصف الحمولة',
- 'weight' => 'الوزن (طن)',
- 'pickup_date' => 'تاريخ الاستلام',
- 'delivery_date' => 'تاريخ التسليم',
- 'payment_method' => 'طريقة الدفع',
- 'payment_thawani' => 'الدفع الإلكتروني عبر ثواني',
- 'payment_bank' => 'تحويل بنكي',
- 'submit_shipment' => 'إرسال الشحنة',
- 'shipments_list' => 'أحدث الشحنات',
- 'status' => 'الحالة',
- 'offer' => 'أفضل عرض',
- 'actions' => 'إجراءات',
- 'view' => 'عرض',
- 'owner_dashboard' => 'لوحة مالك الشاحنة',
- 'available_shipments' => 'الشحنات المتاحة',
- 'offer_price' => 'سعر العرض',
- 'offer_owner' => 'اسم مالك الشاحنة',
- 'submit_offer' => 'إرسال العرض',
- 'admin_dashboard' => 'لوحة الإدارة',
- 'update_status' => 'تحديث الحالة',
- 'save' => 'حفظ',
- 'shipment_detail' => 'تفاصيل الشحنة',
- 'created_at' => 'تم الإنشاء',
- 'best_offer' => 'أفضل عرض',
- 'assign_owner' => 'المالك المعتمد',
- 'no_shipments' => 'لا توجد شحنات بعد. ابدأ بإنشاء أول شحنة.',
- 'no_offers' => 'لا توجد عروض بعد.',
- 'success_shipment' => 'تم نشر الشحنة بنجاح.',
- 'success_offer' => 'تم إرسال العرض إلى الشاحن.',
- 'success_status' => 'تم تحديث الحالة.',
- 'error_required' => 'يرجى تعبئة جميع الحقول المطلوبة.',
- 'error_invalid' => 'يرجى إدخال قيم صحيحة.',
- 'status_posted' => 'منشورة',
- 'status_offered' => 'بعرض',
- 'status_confirmed' => 'مؤكدة',
- 'status_in_transit' => 'قيد النقل',
- 'status_delivered' => 'تم التسليم',
- 'footer_note' => 'هذه هي النسخة الأولية. الدفع غير متصل بعد.',
-'marketing_title_1' => 'للشاحنين', 'marketing_desc_1' => 'ابحث عن الشاحنة المناسبة لحمولتك بسرعة وأمان.', 'marketing_title_2' => 'لأصحاب الشاحنات', 'marketing_desc_2' => 'عظّم أرباحك وتجنب العودة فارغاً.', 'motivation_phrase' => 'تمكين الخدمات اللوجستية للمستقبل.', 'why_choose_us' => 'لماذا تختار كارجو لينك؟', 'feature_1_title' => 'مطابقة سريعة', 'feature_1_desc' => 'تواصل مع الشاحنات المتاحة في دقائق.', 'feature_2_title' => 'مدفوعات آمنة', 'feature_2_desc' => 'معاملاتك محمية بأعلى معايير الأمان.', 'feature_3_title' => 'مستخدمون موثوقون', 'feature_3_desc' => 'نقوم بالتحقق من جميع أصحاب الشاحنات لضمان راحتك.',
- ],
+ "en" => array (
+ 'app_name' => 'CargoLink',
+ 'nav_home' => 'Overview',
+ 'nav_shipper' => 'Shipper Desk',
+ 'nav_owner' => 'Truck Owner Desk',
+ 'nav_admin' => 'Admin Panel',
+ 'hero_title' => 'Move cargo faster with verified trucks.',
+ 'hero_subtitle' => 'Post shipments, collect offers, and pay via Thawani or bank transfer. Built for local and nearby cross-border moves.',
+ 'hero_tagline' => 'Multilingual Logistics Marketplace',
+ 'register_shipper' => 'Register as Shipper',
+ 'register_owner' => 'Register as Truck Owner',
+ 'cta_shipper' => 'Post a shipment',
+ 'cta_owner' => 'Find loads',
+ 'cta_admin' => 'Open admin',
+ 'stats_shipments' => 'Shipments posted',
+ 'stats_offers' => 'Active offers',
+ 'stats_confirmed' => 'Confirmed trips',
+ 'section_workflow' => 'How it works',
+ 'recent_shipments' => 'Recent shipments',
+ 'step_post' => 'Shipper posts cargo details and preferred payment.',
+ 'step_offer' => 'Truck owners respond with their best rate.',
+ 'step_confirm' => 'Admin confirms booking and status.',
+ 'step_confirm_desc' => 'Secure booking and track the delivery until completion.',
+ 'shipper_dashboard' => 'Shipper Dashboard',
+ 'new_shipment' => 'Create shipment',
+ 'shipper_name' => 'Shipper name',
+ 'shipper_company' => 'Company',
+ 'origin' => 'Origin city',
+ 'destination' => 'Destination city',
+ 'cargo' => 'Cargo description',
+ 'cargo_placeholder' => 'e.g. 20 Pallets of Electronics',
+ 'weight' => 'Weight (tons)',
+ 'pickup_date' => 'Pickup date',
+ 'delivery_date' => 'Delivery date',
+ 'payment_method' => 'Payment method',
+ 'payment_thawani' => 'Thawani online payment',
+ 'payment_bank' => 'Bank transfer',
+ 'submit_shipment' => 'Submit shipment',
+ 'shipments_list' => 'Your latest shipments',
+ 'status' => 'Status',
+ 'offer' => 'Best offer',
+ 'actions' => 'Actions',
+ 'view' => 'View',
+ 'owner_dashboard' => 'Truck Owner Dashboard',
+ 'available_shipments' => 'Available shipments',
+ 'offer_price' => 'Offer price',
+ 'offer_owner' => 'Truck owner name',
+ 'submit_offer' => 'Send offer',
+ 'admin_dashboard' => 'Admin Dashboard',
+ 'update_status' => 'Update status',
+ 'save' => 'Save',
+ 'shipment_detail' => 'Shipment detail',
+ 'created_at' => 'Created',
+ 'best_offer' => 'Best offer',
+ 'assign_owner' => 'Assigned owner',
+ 'no_shipments' => 'No shipments yet. Create the first one to get started.',
+ 'no_offers' => 'No offers yet.',
+ 'success_shipment' => 'Shipment posted successfully.',
+ 'success_offer' => 'Offer submitted to the shipper.',
+ 'success_status' => 'Status updated.',
+ 'error_required' => 'Please fill in all required fields.',
+ 'error_invalid' => 'Please enter valid values.',
+ 'status_posted' => 'Posted',
+ 'status_offered' => 'Offered',
+ 'status_confirmed' => 'Confirmed',
+ 'status_in_transit' => 'In transit',
+ 'status_delivered' => 'Delivered',
+ 'footer_note' => 'This is the initial MVP slice. Payments are not yet connected.',
+ 'marketing_title_1' => 'For Shippers',
+ 'marketing_desc_1' => 'Find the right truck for your cargo quickly and securely. Post your load and get offers instantly.',
+ 'marketing_title_2' => 'For Truck Owners',
+ 'marketing_desc_2' => 'Maximize your earnings and eliminate empty miles. Browse available shipments and offer your rate.',
+ 'motivation_phrase' => 'Empowering the logistics of tomorrow.',
+ 'why_choose_us' => 'Why Choose CargoLink?',
+ 'feature_1_title' => 'Fast Matching',
+ 'feature_1_desc' => 'Connect with available trucks or shipments in minutes.',
+ 'feature_2_title' => 'Secure Payments',
+ 'feature_2_desc' => 'Your transactions are protected with security.',
+ 'feature_3_title' => 'Verified Users',
+ 'feature_3_desc' => 'We verify all truck owners to ensure peace of mind.',
+ 'view_faq' => 'View FAQ',
+ 'faq_title' => 'Have Questions?',
+ 'faq_subtitle' => 'Check out our Frequently Asked Questions to learn more about how our platform works.',
+ 'motivation_title' => 'Ready to transform your logistics?',
+ 'motivation_subtitle' => 'Join our platform today to find reliable trucks or secure the best shipments in the market.',
+ 'company' => 'Company',
+ 'about_us' => 'About Us',
+ 'careers' => 'Careers',
+ 'contact' => 'Contact',
+ 'resources' => 'Resources',
+ 'help_center' => 'Help Center / FAQ',
+ 'terms_of_service' => 'Terms of Service',
+ 'privacy_policy' => 'Privacy Policy',
+ 'language' => 'Language',
+ 'all_rights_reserved' => 'All rights reserved.',
+ 'dashboard' => 'Dashboard',
+ 'settings' => 'Settings',
+ 'company_setting' => 'Company Setting',
+ 'integrations' => 'Integrations',
+ 'locations' => 'Locations',
+ 'countries' => 'Countries',
+ 'cities' => 'Cities',
+ 'users' => 'Users',
+ 'shippers' => 'Shippers',
+ 'truck_owners' => 'Truck Owners',
+ 'user_registration' => 'User Registration',
+ 'pages' => 'Pages',
+ 'faqs' => 'FAQs',
+ 'landing_pages' => 'Landing Pages',
+ 'login_title' => 'Welcome Back',
+ 'login_subtitle' => 'Sign in to your account to continue',
+ 'email_address' => 'Email address',
+ 'email_placeholder' => 'name@example.com',
+ 'password' => 'Password',
+ 'forgot_password' => 'Forgot password?',
+ 'password_placeholder' => 'Enter your password',
+ 'change_password' => 'Change Password',
+ 'new_password' => 'New Password',
+ 'confirm_password' => 'Confirm Password',
+ 'passwords_do_not_match' => 'Passwords do not match.',
+ 'password_too_short' => 'Password must be at least 6 characters.',
+ 'password_updated' => 'Password updated successfully.',
+ 'sign_in' => 'Sign In',
+ 'dont_have_account' => 'Don\'t have an account?',
+ 'register_now' => 'Register now',
+ 'reset_password_title' => 'Reset Password',
+ 'reset_password_subtitle' => 'Enter your email and we\'ll send you a link to reset your password',
+ 'send_reset_link' => 'Send Reset Link',
+ 'back_to_login' => 'Back to login',
+ 'invalid_image' => 'Invalid image format. Please upload JPG, PNG, GIF, or WEBP.',
+ 'upload_failed' => 'Failed to save uploaded file.',
+ 'profile_updated' => 'Profile updated successfully.',
+ 'my_profile' => 'My Profile',
+ 'profile_picture' => 'Profile Picture',
+ 'change_picture' => 'Change Picture',
+ 'picture_hint' => 'JPG, PNG, or GIF up to 5MB',
+ 'full_name' => 'Full Name',
+ 'email_hint' => 'Email address cannot be changed.',
+ 'account_role' => 'Account Role',
+ 'save_changes' => 'Save Changes',
+ 'reg_title' => 'Create your logistics account',
+ 'reg_subtitle' => 'Shippers and truck owners can self-register with full profile details.',
+ 'reg_success_pending' => 'Registration completed successfully. Your account is pending admin approval.',
+ 'reg_success' => 'Registration completed successfully.',
+ 'role' => 'Role',
+ 'shipper' => 'Shipper',
+ 'truck_owner' => 'Truck Owner',
+ 'email' => 'Email',
+ 'phone' => 'Phone',
+ 'country' => 'Country',
+ 'select_country' => 'Select country',
+ 'city' => 'City',
+ 'select_city' => 'Select city',
+ 'address' => 'Address',
+ 'shipper_details' => 'Shipper details',
+ 'company_name' => 'Company name',
+ 'truck_details' => 'Truck owner details',
+ 'truck_type' => 'Truck type',
+ 'load_capacity' => 'Load capacity (tons)',
+ 'plate_no' => 'Plate number',
+ 'bank_account' => 'Bank Account / IBAN',
+ 'bank_name' => 'Bank Name',
+ 'bank_branch' => 'Bank Branch',
+ 'id_card_front' => 'ID card (Front Face)',
+ 'id_card_back' => 'ID card (Back Face)',
+ 'truck_reg_front' => 'Truck Registration (Front Face)',
+ 'truck_reg_back' => 'Truck Registration (Back Face)',
+ 'truck_picture' => 'Clear Truck Photo (showing plate number)',
+ 'create_account' => 'Create account',
+ 'back_to_admin' => 'Back to admin',
+ 'welcome_back' => 'Welcome to your dashboard. Manage your cargo shipments here.',
+ 'total_shipments_posted' => 'Total Shipments',
+ 'active_shipments' => 'Active Shipments',
+ 'delivered_shipments' => 'Delivered Shipments',
+ 'route_label' => 'Route',
+ 'total_label' => 'total',
+ 'welcome_back_owner' => 'Find loads and submit your best rate.',
+ 'total_offers' => 'Total Offers',
+ 'won_shipments' => 'Won Shipments',
+),
+ "ar" => array (
+ 'app_name' => 'CargoLink',
+ 'nav_home' => 'نظرة عامة',
+ 'nav_shipper' => 'لوحة الشاحن',
+ 'nav_owner' => 'لوحة مالك الشاحنة',
+ 'nav_admin' => 'لوحة الإدارة',
+ 'hero_title' => 'انقل شحنتك بسرعة مع شاحنات موثوقة.',
+ 'hero_subtitle' => 'أنشئ شحنة، استلم عروضاً، وادفع عبر ثواني أو التحويل البنكي.',
+ 'hero_tagline' => 'منصة لوجستية متعددة اللغات',
+ 'register_shipper' => 'التسجيل كشاحن',
+ 'register_owner' => 'التسجيل كمالك شاحنة',
+ 'cta_shipper' => 'إنشاء شحنة',
+ 'cta_owner' => 'البحث عن الشحنات',
+ 'cta_admin' => 'الدخول للإدارة',
+ 'stats_shipments' => 'الشحنات المنشورة',
+ 'stats_offers' => 'العروض الحالية',
+ 'stats_confirmed' => 'الرحلات المؤكدة',
+ 'section_workflow' => 'طريقة العمل',
+ 'recent_shipments' => 'أحدث الشحنات',
+ 'step_post' => 'يقوم الشاحن بإدخال تفاصيل الشحنة وطريقة الدفع.',
+ 'step_offer' => 'يرسل أصحاب الشاحنات أفضل عروضهم.',
+ 'step_confirm' => 'تؤكد الإدارة الحجز وتحدث الحالة.',
+ 'step_confirm_desc' => 'حجز آمن وتتبع التسليم حتى الانتهاء.',
+ 'shipper_dashboard' => 'لوحة الشاحن',
+ 'new_shipment' => 'إنشاء شحنة',
+ 'shipper_name' => 'اسم الشاحن',
+ 'shipper_company' => 'الشركة',
+ 'origin' => 'مدينة الانطلاق',
+ 'destination' => 'مدينة الوصول',
+ 'cargo' => 'وصف الحمولة',
+ 'cargo_placeholder' => 'مثال: 20 منصة إلكترونيات',
+ 'weight' => 'الوزن (طن)',
+ 'pickup_date' => 'تاريخ الاستلام',
+ 'delivery_date' => 'تاريخ التسليم',
+ 'payment_method' => 'طريقة الدفع',
+ 'payment_thawani' => 'الدفع الإلكتروني عبر ثواني',
+ 'payment_bank' => 'تحويل بنكي',
+ 'submit_shipment' => 'إرسال الشحنة',
+ 'shipments_list' => 'أحدث الشحنات',
+ 'status' => 'الحالة',
+ 'offer' => 'أفضل عرض',
+ 'actions' => 'إجراءات',
+ 'view' => 'عرض',
+ 'owner_dashboard' => 'لوحة مالك الشاحنة',
+ 'available_shipments' => 'الشحنات المتاحة',
+ 'offer_price' => 'سعر العرض',
+ 'offer_owner' => 'اسم مالك الشاحنة',
+ 'submit_offer' => 'إرسال العرض',
+ 'admin_dashboard' => 'لوحة الإدارة',
+ 'update_status' => 'تحديث الحالة',
+ 'save' => 'حفظ',
+ 'shipment_detail' => 'تفاصيل الشحنة',
+ 'created_at' => 'تم الإنشاء',
+ 'best_offer' => 'أفضل عرض',
+ 'assign_owner' => 'المالك المعتمد',
+ 'no_shipments' => 'لا توجد شحنات بعد. ابدأ بإنشاء أول شحنة.',
+ 'no_offers' => 'لا توجد عروض بعد.',
+ 'success_shipment' => 'تم نشر الشحنة بنجاح.',
+ 'success_offer' => 'تم إرسال العرض إلى الشاحن.',
+ 'success_status' => 'تم تحديث الحالة.',
+ 'error_required' => 'يرجى تعبئة جميع الحقول المطلوبة.',
+ 'error_invalid' => 'يرجى إدخال قيم صحيحة.',
+ 'status_posted' => 'منشورة',
+ 'status_offered' => 'بعرض',
+ 'status_confirmed' => 'مؤكدة',
+ 'status_in_transit' => 'قيد النقل',
+ 'status_delivered' => 'تم التسليم',
+ 'footer_note' => 'هذه هي النسخة الأولية. الدفع غير متصل بعد.',
+ 'marketing_title_1' => 'للشاحنين',
+ 'marketing_desc_1' => 'ابحث عن الشاحنة المناسبة لحمولتك بسرعة وأمان.',
+ 'marketing_title_2' => 'لأصحاب الشاحنات',
+ 'marketing_desc_2' => 'عظّم أرباحك وتجنب العودة فارغاً.',
+ 'motivation_phrase' => 'تمكين الخدمات اللوجستية للمستقبل.',
+ 'why_choose_us' => 'لماذا تختار كارجو لينك؟',
+ 'feature_1_title' => 'مطابقة سريعة',
+ 'feature_1_desc' => 'تواصل مع الشاحنات المتاحة في دقائق.',
+ 'feature_2_title' => 'مدفوعات آمنة',
+ 'feature_2_desc' => 'معاملاتك محمية بأعلى معايير الأمان.',
+ 'feature_3_title' => 'مستخدمون موثوقون',
+ 'feature_3_desc' => 'نقوم بالتحقق من جميع أصحاب الشاحنات لضمان راحتك.',
+ 'view_faq' => 'عرض الأسئلة الشائعة',
+ 'faq_title' => 'لديك أسئلة؟',
+ 'faq_subtitle' => 'اطلع على الأسئلة الشائعة لمعرفة المزيد حول كيفية عمل منصتنا.',
+ 'motivation_title' => 'هل أنت مستعد لتحويل خدماتك اللوجستية؟',
+ 'motivation_subtitle' => 'انضم إلى منصتنا اليوم للعثور على شاحنات موثوقة أو تأمين أفضل الشحنات في السوق.',
+ 'company' => 'الشركة',
+ 'about_us' => 'معلومات عنا',
+ 'careers' => 'الوظائف',
+ 'contact' => 'اتصل بنا',
+ 'resources' => 'الموارد',
+ 'help_center' => 'مركز المساعدة / الأسئلة الشائعة',
+ 'terms_of_service' => 'شروط الخدمة',
+ 'privacy_policy' => 'سياسة الخصوصية',
+ 'language' => 'اللغة',
+ 'all_rights_reserved' => 'جميع الحقوق محفوظة.',
+ 'dashboard' => 'لوحة القيادة',
+ 'settings' => 'الإعدادات',
+ 'company_setting' => 'إعدادات الشركة',
+ 'integrations' => 'التكاملات',
+ 'locations' => 'المواقع',
+ 'countries' => 'البلدان',
+ 'cities' => 'المدن',
+ 'users' => 'المستخدمون',
+ 'shippers' => 'الشاحنون',
+ 'truck_owners' => 'أصحاب الشاحنات',
+ 'user_registration' => 'تسجيل المستخدم',
+ 'pages' => 'الصفحات',
+ 'faqs' => 'الأسئلة الشائعة',
+ 'landing_pages' => 'صفحات الهبوط',
+ 'login_title' => 'مرحبًا بعودتك',
+ 'login_subtitle' => 'قم بتسجيل الدخول إلى حسابك للمتابعة',
+ 'email_address' => 'البريد الإلكتروني',
+ 'email_placeholder' => 'name@example.com',
+ 'password' => 'كلمة المرور',
+ 'forgot_password' => 'هل نسيت كلمة المرور؟',
+ 'password_placeholder' => 'أدخل كلمة المرور',
+ 'change_password' => 'تغيير كلمة المرور',
+ 'new_password' => 'كلمة المرور الجديدة',
+ 'confirm_password' => 'تأكيد كلمة المرور',
+ 'passwords_do_not_match' => 'كلمات المرور غير متطابقة.',
+ 'password_too_short' => 'يجب أن تتكون كلمة المرور من 6 أحرف على الأقل.',
+ 'password_updated' => 'تم تحديث كلمة المرور بنجاح.',
+ 'sign_in' => 'تسجيل الدخول',
+ 'dont_have_account' => 'ليس لديك حساب؟',
+ 'register_now' => 'سجل الآن',
+ 'reset_password_title' => 'إعادة تعيين كلمة المرور',
+ 'reset_password_subtitle' => 'أدخل بريدك الإلكتروني وسنرسل لك رابطًا لإعادة تعيين كلمة المرور',
+ 'send_reset_link' => 'إرسال رابط إعادة التعيين',
+ 'back_to_login' => 'العودة لتسجيل الدخول',
+ 'invalid_image' => 'صيغة صورة غير صالحة. يرجى تحميل JPG أو PNG أو GIF أو WEBP.',
+ 'upload_failed' => 'فشل في حفظ الملف المحمل.',
+ 'profile_updated' => 'تم تحديث الملف الشخصي بنجاح.',
+ 'my_profile' => 'ملفي الشخصي',
+ 'profile_picture' => 'صورة الملف الشخصي',
+ 'change_picture' => 'تغيير الصورة',
+ 'picture_hint' => 'JPG، PNG، أو GIF حتى 5 ميغابايت',
+ 'full_name' => 'الاسم الكامل',
+ 'email_hint' => 'لا يمكن تغيير عنوان البريد الإلكتروني.',
+ 'account_role' => 'دور الحساب',
+ 'save_changes' => 'حفظ التغييرات',
+ 'reg_title' => 'أنشئ حسابك اللوجستي',
+ 'reg_subtitle' => 'يمكن للشاحنين وأصحاب الشاحنات التسجيل الذاتي ببيانات الملف الشخصي الكاملة.',
+ 'reg_success_pending' => 'اكتمل التسجيل بنجاح. حسابك في انتظار موافقة الإدارة.',
+ 'reg_success' => 'اكتمل التسجيل بنجاح.',
+ 'role' => 'الدور',
+ 'shipper' => 'شاحن',
+ 'truck_owner' => 'مالك شاحنة',
+ 'email' => 'البريد الإلكتروني',
+ 'phone' => 'الهاتف',
+ 'country' => 'البلد',
+ 'select_country' => 'اختر البلد',
+ 'city' => 'المدينة',
+ 'select_city' => 'اختر المدينة',
+ 'address' => 'العنوان',
+ 'shipper_details' => 'تفاصيل الشاحن',
+ 'company_name' => 'اسم الشركة',
+ 'truck_details' => 'تفاصيل مالك الشاحنة',
+ 'truck_type' => 'نوع الشاحنة',
+ 'load_capacity' => 'سعة الحمولة (طن)',
+ 'plate_no' => 'رقم اللوحة',
+ 'bank_account' => 'الحساب البنكي / الآيبان',
+ 'bank_name' => 'اسم البنك',
+ 'bank_branch' => 'فرع البنك',
+ 'id_card_front' => 'البطاقة الشخصية (الوجه الأمامي)',
+ 'id_card_back' => 'البطاقة الشخصية (الوجه الخلفي)',
+ 'truck_reg_front' => 'تسجيل الشاحنة (الوجه الأمامي)',
+ 'truck_reg_back' => 'تسجيل الشاحنة (الوجه الخلفي)',
+ 'truck_picture' => 'صورة واضحة للشاحنة (تظهر رقم اللوحة)',
+ 'create_account' => 'إنشاء حساب',
+ 'back_to_admin' => 'العودة للإدارة',
+ 'welcome_back' => 'مرحبًا بك في لوحة القيادة الخاصة بك. قم بإدارة شحناتك هنا.',
+ 'total_shipments_posted' => 'إجمالي الشحنات',
+ 'active_shipments' => 'الشحنات النشطة',
+ 'delivered_shipments' => 'الشحنات المسلمة',
+ 'route_label' => 'المسار',
+ 'total_label' => 'المجموع',
+ 'welcome_back_owner' => 'ابحث عن الأحمال وقدم أفضل سعر لديك.',
+ 'total_offers' => 'إجمالي العروض',
+ 'won_shipments' => 'الشحنات الفائزة',
+)
];
function t(string $key): string
@@ -164,8 +388,7 @@ function e($value): string
function ensure_schema(): void
{
- db()->exec("
- CREATE TABLE IF NOT EXISTS landing_sections (
+ db()->exec("\n CREATE TABLE IF NOT EXISTS landing_sections (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(255) NOT NULL,
subtitle TEXT NULL,
@@ -179,6 +402,11 @@ function ensure_schema(): void
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
");
+
+ try { db()->exec("ALTER TABLE landing_sections ADD COLUMN title_ar VARCHAR(255) NULL AFTER title"); } catch (Exception $e) {}
+ try { db()->exec("ALTER TABLE landing_sections ADD COLUMN subtitle_ar TEXT NULL AFTER subtitle"); } catch (Exception $e) {}
+ try { db()->exec("ALTER TABLE landing_sections ADD COLUMN content_ar TEXT NULL AFTER content"); } catch (Exception $e) {}
+ try { db()->exec("ALTER TABLE landing_sections ADD COLUMN button_text_ar VARCHAR(100) NULL AFTER button_text"); } catch (Exception $e) {}
$sql = <<
exec($sql);
- try { db()->exec("ALTER TABLE users ADD COLUMN status ENUM('pending','active','rejected') NOT NULL DEFAULT 'active'"); } catch (Exception $e) {}
- try { db()->exec("ALTER TABLE users ADD COLUMN profile_picture VARCHAR(255) NULL AFTER full_name"); } catch (Exception $e) {}
+ try { db()->exec("ALTER TABLE users ADD COLUMN status ENUM('pending','active','rejected') NOT NULL DEFAULT 'active'"); } catch (Exception $e) {}
+ try { db()->exec("ALTER TABLE users ADD COLUMN profile_picture VARCHAR(255) NULL AFTER full_name"); } catch (Exception $e) {}
// Payment fields for shipments
try { db()->exec("ALTER TABLE shipments ADD COLUMN platform_fee DECIMAL(10,2) DEFAULT 0.00 AFTER offer_price"); } catch (Exception $e) {}
@@ -320,4 +548,4 @@ function get_setting(string $key, $default = ''): string
{
$settings = get_settings();
return $settings[$key] ?? $default;
-}
\ No newline at end of file
+}
diff --git a/includes/layout.php b/includes/layout.php
index 9f4b362..267e0bd 100644
--- a/includes/layout.php
+++ b/includes/layout.php
@@ -1,7 +1,7 @@
">
-
-
+
-