From c17c11d23abed9b65bd515167fef877501a5c899 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Sun, 8 Mar 2026 05:41:10 +0000 Subject: [PATCH] password edit --- admin_dashboard.php | 233 ++++++++++++++++------- admin_shipment_edit.php | 159 ++++++++++++++++ admin_shipments.php | 218 ++++++++++++++++++++++ admin_shipper_edit.php | 16 +- admin_shippers.php | 47 +++-- admin_truck_owner_edit.php | 15 +- admin_truck_owners.php | 49 +++-- includes/layout.php | 59 +++--- index.php | 12 +- login.php | 30 +-- patch_app_translations.php | 369 +++++++++++++++++++++++++++++++++++++ patch_lines.php | 23 +++ profile.php | 26 +-- register.php | 66 +++---- shipment_detail.php | 23 ++- shipper_dashboard.php | 182 +++++++++++++----- truck_owner_dashboard.php | 133 ++++++++++--- 17 files changed, 1397 insertions(+), 263 deletions(-) create mode 100644 admin_shipment_edit.php create mode 100644 admin_shipments.php create mode 100644 patch_app_translations.php create mode 100644 patch_lines.php diff --git a/admin_dashboard.php b/admin_dashboard.php index ecb188d..52684bb 100644 --- a/admin_dashboard.php +++ b/admin_dashboard.php @@ -31,6 +31,20 @@ try { $shipments = []; } +$stats = [ + 'total_shipments' => 0, + 'active_shipments' => 0, + 'total_shippers' => 0, + 'total_truck_owners' => 0, +]; + +try { + $stats['total_shipments'] = (int)db()->query("SELECT COUNT(*) FROM shipments")->fetchColumn(); + $stats['active_shipments'] = (int)db()->query("SELECT COUNT(*) FROM shipments WHERE status != 'delivered'")->fetchColumn(); + $stats['total_shippers'] = (int)db()->query("SELECT COUNT(*) FROM users WHERE role = 'shipper'")->fetchColumn(); + $stats['total_truck_owners'] = (int)db()->query("SELECT COUNT(*) FROM users WHERE role = 'truck_owner'")->fetchColumn(); +} catch (Throwable $e) {} + $flash = get_flash(); render_header(t('admin_dashboard'), 'admin'); @@ -41,74 +55,165 @@ render_header(t('admin_dashboard'), 'admin');
-
+

-

Control shipment status, manage locations, and onboard new users from one place.

+

Overview of your platform's performance and recent activity.

-
-

Quick actions

- -
-
-
-

- total -
- -
- - -
- - -

- -
- - - - - - - - - - - - - - - - - - - - - - - -
-
- - - - -
-
+ + +
+
+
+
+
+

+

Total Shipments

- +
+
+
+
+
+

+

Active Shipments

+
+
+
+
+
+
+

+

Total Shippers

+
+
+
+
+
+
+

+

Truck Owners

+
+
+
+ +
+ +
+
+
+

Recent Shipments

+ shown +
+ +
+ + +
+ + +
+ +

+
+ +
+ + + + + + + + + + + + + + + + + + + +
ShipmentRouteAction
+
+ +
+
+ + + +
+
+
+ + + + +
+
+
+ +
+
+ + +
- + \ No newline at end of file diff --git a/admin_shipment_edit.php b/admin_shipment_edit.php new file mode 100644 index 0000000..77ff653 --- /dev/null +++ b/admin_shipment_edit.php @@ -0,0 +1,159 @@ +prepare("SELECT * FROM shipments WHERE id = ?"); +$stmt->execute([$id]); +$shipment = $stmt->fetch(); + +if (!$shipment) { + header('Location: admin_shipments.php'); exit; +} + +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $shipper_name = trim($_POST['shipper_name'] ?? ''); + $shipper_company = trim($_POST['shipper_company'] ?? ''); + $origin_city = trim($_POST['origin_city'] ?? ''); + $destination_city = trim($_POST['destination_city'] ?? ''); + $cargo_description = trim($_POST['cargo_description'] ?? ''); + $weight_tons = (float)($_POST['weight_tons'] ?? 0); + $pickup_date = trim($_POST['pickup_date'] ?? ''); + $delivery_date = trim($_POST['delivery_date'] ?? ''); + $payment_method = trim($_POST['payment_method'] ?? 'thawani'); + $status = trim($_POST['status'] ?? 'posted'); + + if ($shipper_name === '') $errors[] = "Shipper name is required."; + if ($origin_city === '') $errors[] = "Origin city is required."; + if ($destination_city === '') $errors[] = "Destination city is required."; + + if (empty($errors)) { + $updateSql = " + UPDATE shipments + SET shipper_name = ?, shipper_company = ?, origin_city = ?, destination_city = ?, + cargo_description = ?, weight_tons = ?, pickup_date = ?, delivery_date = ?, + payment_method = ?, status = ? + WHERE id = ? + "; + db()->prepare($updateSql)->execute([ + $shipper_name, $shipper_company, $origin_city, $destination_city, + $cargo_description, $weight_tons, $pickup_date, $delivery_date, + $payment_method, $status, $id + ]); + $flash = "Shipment updated successfully."; + + // Refresh + $stmt->execute([$id]); + $shipment = $stmt->fetch(); + } +} + +render_header('Edit Shipment', 'admin'); +?> + +
+
+ +
+
+
+ + + + + +
+

Edit Shipment #

+

Update shipment details and status.

+
+
+ + +
+ + + +
+
    + +
  • + +
+
+ + +
+
+
+
+ + +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + +
+ +
+ + +
+
+ + +
+
+ + +
+ +
+ + +
+
+ + +
+
+ +
+ +
+
+
+
+
+ + diff --git a/admin_shipments.php b/admin_shipments.php new file mode 100644 index 0000000..71de516 --- /dev/null +++ b/admin_shipments.php @@ -0,0 +1,218 @@ +prepare("DELETE FROM shipments WHERE id = ?")->execute([$shipmentId]); + $flash = 'Shipment deleted successfully.'; + } +} + +// Search, Filter, Sort and Pagination parameters +$q = trim($_GET['q'] ?? ''); +$status = trim($_GET['status'] ?? ''); +$sort = trim($_GET['sort'] ?? 'newest'); +$page = max(1, (int)($_GET['page'] ?? 1)); +$limit = 10; +$offset = ($page - 1) * $limit; + +$whereClause = "1=1"; +$params = []; + +if ($q !== '') { + $whereClause .= " AND (shipper_name LIKE ? OR shipper_company LIKE ? OR origin_city LIKE ? OR destination_city LIKE ? OR cargo_description LIKE ?)"; + $likeQ = "%$q%"; + $params = array_merge($params, array_fill(0, 5, $likeQ)); +} + +if ($status !== '' && in_array($status, ['posted', 'offered', 'confirmed', 'in_transit', 'delivered'])) { + $whereClause .= " AND status = ?"; + $params[] = $status; +} + +// Sorting logic +$orderBy = match ($sort) { + 'oldest' => 'created_at ASC', + 'pickup_asc' => 'pickup_date ASC', + 'pickup_desc' => 'pickup_date DESC', + default => 'created_at DESC', // newest +}; + +// Total count +$countSql = "SELECT COUNT(*) FROM shipments WHERE $whereClause"; +$stmt = db()->prepare($countSql); +$stmt->execute($params); +$total = (int)$stmt->fetchColumn(); +$totalPages = (int)ceil($total / $limit); + +// Fetch shipments +$sql = " + SELECT * + FROM shipments + WHERE $whereClause + ORDER BY $orderBy + LIMIT $limit OFFSET $offset +"; +$stmt = db()->prepare($sql); +$stmt->execute($params); +$shipments = $stmt->fetchAll(); + +render_header('Manage Shipments', 'admin'); +?> + +
+
+ +
+
+
+
+

Shipments

+

Manage all shipments across the platform.

+
+
+ + +
+ + +
+
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+
+ +
+ +

No shipments found matching your criteria.

+ +

No shipments found on the platform yet.

+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
IDShipperRouteDatesStatusAction
+
+
+
+
From:
+
To:
+
+
Pick:
+
Drop:
+
+ + + +
+ + + + + + + + + + + +
+ + +
+
+
+
+ + 1): ?> +
+ Showing of shipments + +
+ + +
+
+
+ + \ No newline at end of file diff --git a/admin_shipper_edit.php b/admin_shipper_edit.php index 6c4a376..d3741ee 100644 --- a/admin_shipper_edit.php +++ b/admin_shipper_edit.php @@ -40,6 +40,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $addressLine = trim($_POST['address_line'] ?? ''); $companyName = trim($_POST['company_name'] ?? ''); $status = trim($_POST['status'] ?? ''); + $password = $_POST['password'] ?? ''; if ($fullName === '') $errors[] = 'Full name is required.'; if (!filter_var($email, FILTER_VALIDATE_EMAIL)) $errors[] = 'Valid email is required.'; @@ -64,6 +65,11 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $stmtUser = db()->prepare("UPDATE users SET full_name = ?, email = ?, status = ? WHERE id = ? AND role = 'shipper'"); $stmtUser->execute([$fullName, $email, $status, $userId]); + if ($password !== '') { + $stmtPass = db()->prepare("UPDATE users SET password = ? WHERE id = ? AND role = 'shipper'"); + $stmtPass->execute([password_hash($password, PASSWORD_DEFAULT), $userId]); + } + $stmtProfile = db()->prepare(" UPDATE shipper_profiles SET company_name = ?, phone = ?, address_line = ?, country_id = ?, city_id = ? @@ -157,11 +163,17 @@ render_header('Edit Shipper', 'admin');
-
+
-
+ +
+ + +
+ +
- - - Clear - -
+
+
+
+ + +
+
+ + +
+
+ +
+
+
+
- -

No shippers found matching your search.

+ +

No shippers found matching your criteria.

No shippers registered yet.

@@ -181,15 +200,15 @@ render_header('Manage Shippers', 'admin'); Showing of shippers
diff --git a/admin_truck_owner_edit.php b/admin_truck_owner_edit.php index 13750e8..9533884 100644 --- a/admin_truck_owner_edit.php +++ b/admin_truck_owner_edit.php @@ -45,6 +45,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $loadCapacity = trim($_POST['load_capacity'] ?? ''); $plateNo = trim($_POST['plate_no'] ?? ''); $status = trim($_POST['status'] ?? ''); + $password = $_POST['password'] ?? ''; + $bankAccount = trim($_POST['bank_account'] ?? ''); $bankName = trim($_POST['bank_name'] ?? ''); $bankBranch = trim($_POST['bank_branch'] ?? ''); @@ -76,6 +78,11 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $stmtUser = db()->prepare("UPDATE users SET full_name = ?, email = ?, status = ? WHERE id = ? AND role = 'truck_owner'"); $stmtUser->execute([$fullName, $email, $status, $userId]); + + if ($password !== '') { + $stmtPass = db()->prepare("UPDATE users SET password = ? WHERE id = ? AND role = 'truck_owner'"); + $stmtPass->execute([password_hash($password, PASSWORD_DEFAULT), $userId]); + } $stmtProfile = db()->prepare(" UPDATE truck_owner_profiles @@ -154,11 +161,15 @@ render_header('Edit Truck Owner', 'admin');
-
+
-
+
+ + +
+
- - - Clear - -
+
+
+
+ + +
+
+ + +
+
+ +
+
+
+
- -

No truck owners found matching your search.

+ +

No truck owners found matching your criteria.

No truck owners registered yet.

@@ -189,15 +208,15 @@ render_header('Manage Truck Owners', 'admin'); Showing of truck owners
@@ -258,4 +277,4 @@ $pic = $owner['truck_pic_path'];
- + \ No newline at end of file diff --git a/includes/layout.php b/includes/layout.php index 2f23ba0..9f4b362 100644 --- a/includes/layout.php +++ b/includes/layout.php @@ -31,7 +31,11 @@ function render_header(string $title, string $active = ''): void - + + + + + @@ -168,23 +172,23 @@ function render_footer(): void
-
Company
+
-
Resources
+
-
Language
+
EN | @@ -194,7 +198,7 @@ function render_footer(): void
- © . All rights reserved. + © .
@@ -214,71 +218,74 @@ function render_admin_sidebar(string $active = 'dashboard'): void $pagesActive = in_array($active, ['faqs', 'landing_pages']); ?>
-

Secure booking and track the delivery until completion.

+

@@ -219,17 +219,17 @@ try {
> -

-

+

+

diff --git a/login.php b/login.php index 76a7a74..24ab1e6 100644 --- a/login.php +++ b/login.php @@ -97,30 +97,30 @@ render_header('Login / Reset Password', 'login');
-

Welcome Back

-

Sign in to your account to continue

+

+

- - + +
- - Forgot password? + +
- +
- +
-

Don't have an account? Register now

+

@@ -129,22 +129,22 @@ render_header('Login / Reset Password', 'login');
-

Reset Password

-

Enter your email and we'll send you a link to reset your password

+

+

- - + +
- +
diff --git a/patch_app_translations.php b/patch_app_translations.php new file mode 100644 index 0000000..129aa9c --- /dev/null +++ b/patch_app_translations.php @@ -0,0 +1,369 @@ + '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', + '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', +]; + +$translations_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' => 'تؤكد الإدارة الحجز وتحدث الحالة.', + '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' => 'أدخل كلمة المرور', + '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' => 'الشحنات الفائزة', +]; + +$trans_str_en = var_export($translations_en, true); +$trans_str_ar = var_export($translations_ar, true); + +$new_translations = '$translations = [ + "en" => ' . $trans_str_en . ', + "ar" => ' . $trans_str_ar . ' +];'; + +// Find where $translations array starts and ends. +// In the current file it starts at '$translations = [' and ends before 'function t(' +$pattern = '/\$translations\s*=\s*\[.*?(?=\nfunction t\(\))/s'; +$content = preg_replace($pattern, $new_translations . "\n\n", $content); + +file_put_contents('includes/app.php', $content); +echo "Updated translations in app.php\n"; +?> diff --git a/patch_lines.php b/patch_lines.php new file mode 100644 index 0000000..3c2eea5 --- /dev/null +++ b/patch_lines.php @@ -0,0 +1,23 @@ + $line) { + if (strpos($line, '$translations = [') === 0) { + $start = $i; + } + if (strpos($line, 'function t(') === 0) { + $end = $i; + break; + } +} +if ($start !== -1 && $end !== -1) { + $new_content = array_slice($lines, 0, $start); + $new_content[] = file_get_contents('new_trans.txt'); + $new_content = array_merge($new_content, array_slice($lines, $end)); + file_put_contents('includes/app.php', implode("", $new_content)); + echo "Replaced lines $start to $end\n"; +} else { + echo "Could not find start/end\n"; +} +?> diff --git a/profile.php b/profile.php index c45c4a4..0f66b99 100644 --- a/profile.php +++ b/profile.php @@ -39,7 +39,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'updat finfo_close($fileInfo); if (!in_array($mimeType, $allowedTypes)) { - $errors[] = "Invalid image format. Please upload JPG, PNG, GIF, or WEBP."; + $errors[] = t('invalid_image'); } else { $uploadDir = __DIR__ . '/uploads/profiles/'; if (!is_dir($uploadDir)) { @@ -53,7 +53,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'updat if (move_uploaded_file($_FILES['profile_picture']['tmp_name'], $destination)) { $profilePicPath = '/uploads/profiles/' . $filename; } else { - $errors[] = "Failed to save uploaded file."; + $errors[] = t('upload_failed'); } } } @@ -66,7 +66,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'updat ':pic' => $profilePicPath, ':id' => $userId ]); - set_flash('success', "Profile updated successfully."); + set_flash('success', t('profile_updated')); header("Location: " . url_with_lang('profile.php')); exit; } catch (Throwable $e) { @@ -75,7 +75,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'updat } } -render_header('My Profile', 'profile'); +render_header(t('my_profile'), 'profile'); $flash = get_flash(); ?> @@ -84,7 +84,7 @@ $flash = get_flash();
-

My Profile

+

@@ -109,39 +109,39 @@ $flash = get_flash();
- Profile Picture + <?= e(t('profile_picture')) ?>
-
-
JPG, PNG, or GIF up to 5MB
+
- +
- + -
Email address cannot be changed.
+
- +
diff --git a/register.php b/register.php index bc94614..47db03b 100644 --- a/register.php +++ b/register.php @@ -230,16 +230,16 @@ render_header('Shipper & Truck Owner Registration'); ?>
-

Create your logistics account

-

Shippers and truck owners can self-register with full profile details.

+

+

-
Registration completed successfully. Your account is pending admin approval.
+
-
Registration completed successfully.
+
@@ -249,32 +249,32 @@ render_header('Shipper & Truck Owner Registration');
- +
- +
- +
- +
- +
- +
- +
- +
-

Shipper details

+

- +
- - Back to admin + +
@@ -370,7 +370,7 @@ function syncCities() { const countryId = document.getElementById('country_id').value; const citySelect = document.getElementById('city_id'); const selectedValue = citySelect.dataset.selected || ''; - citySelect.innerHTML = ''; + citySelect.innerHTML = ''; allCities.forEach((city) => { if (String(city.country_id) !== String(countryId)) { diff --git a/shipment_detail.php b/shipment_detail.php index 46dd63a..f865f5b 100644 --- a/shipment_detail.php +++ b/shipment_detail.php @@ -39,6 +39,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'submi } $flash = get_flash(); +$isAdmin = ($_SESSION['user_role'] ?? '') === 'admin'; render_header(t('shipment_detail')); ?> @@ -46,6 +47,13 @@ render_header(t('shipment_detail'));

+
+ + Back to Shipments + + + +
@@ -100,8 +108,17 @@ render_header(t('shipment_detail'));
-
@@ -131,4 +148,4 @@ render_header(t('shipment_detail'));
- + \ No newline at end of file diff --git a/shipper_dashboard.php b/shipper_dashboard.php index 34fe5de..118a444 100644 --- a/shipper_dashboard.php +++ b/shipper_dashboard.php @@ -7,6 +7,21 @@ ensure_schema(); $errors = []; +// Try to pre-fill from profile if logged in +$prefillName = $_SESSION['shipper_name'] ?? ''; +$prefillCompany = ''; +if (isset($_SESSION['user_id'])) { + try { + $stmt = db()->prepare("SELECT u.full_name, p.company_name FROM users u LEFT JOIN shipper_profiles p ON u.id = p.user_id WHERE u.id = ?"); + $stmt->execute([$_SESSION['user_id']]); + $profile = $stmt->fetch(); + if ($profile) { + $prefillName = $profile['full_name']; + $prefillCompany = $profile['company_name'] ?? ''; + } + } catch (Throwable $e) {} +} + if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'create_shipment') { $shipperName = trim($_POST['shipper_name'] ?? ''); $shipperCompany = trim($_POST['shipper_company'] ?? ''); @@ -41,6 +56,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'creat ':payment_method' => $payment, ]); $_SESSION['shipper_name'] = $shipperName; + $_SESSION['shipper_company_session'] = $shipperCompany; // for rudimentary filtering set_flash('success', t('success_shipment')); header('Location: ' . url_with_lang('shipper_dashboard.php')); exit; @@ -48,22 +64,79 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'creat } $shipments = []; +$filterCompany = $_SESSION['shipper_company_session'] ?? $prefillCompany; + try { - $stmt = db()->query("SELECT * FROM shipments ORDER BY created_at DESC LIMIT 20"); + if ($filterCompany) { + $stmt = db()->prepare("SELECT * FROM shipments WHERE shipper_company = ? ORDER BY created_at DESC LIMIT 20"); + $stmt->execute([$filterCompany]); + } else { + $stmt = db()->query("SELECT * FROM shipments ORDER BY created_at DESC LIMIT 20"); + } $shipments = $stmt->fetchAll(); } catch (Throwable $e) { $shipments = []; } -render_header(t('shipper_dashboard'), 'shipper'); +$stats = [ + 'total' => 0, + 'active' => 0, + 'delivered' => 0, +]; +try { + if ($filterCompany) { + $stats['total'] = (int)db()->prepare("SELECT COUNT(*) FROM shipments WHERE shipper_company = ?")->execute([$filterCompany]) ? (int)db()->query("SELECT COUNT(*) FROM shipments WHERE shipper_company = " . db()->quote($filterCompany))->fetchColumn() : 0; + $stats['active'] = (int)db()->query("SELECT COUNT(*) FROM shipments WHERE shipper_company = " . db()->quote($filterCompany) . " AND status != 'delivered'")->fetchColumn(); + $stats['delivered'] = (int)db()->query("SELECT COUNT(*) FROM shipments WHERE shipper_company = " . db()->quote($filterCompany) . " AND status = 'delivered'")->fetchColumn(); + } else { + $stats['total'] = (int)db()->query("SELECT COUNT(*) FROM shipments")->fetchColumn(); + $stats['active'] = (int)db()->query("SELECT COUNT(*) FROM shipments WHERE status != 'delivered'")->fetchColumn(); + $stats['delivered'] = (int)db()->query("SELECT COUNT(*) FROM shipments WHERE status = 'delivered'")->fetchColumn(); + } +} catch (Throwable $e) {} + +render_header(t('shipper_dashboard'), 'shipper'); $flash = get_flash(); ?> +
+

+

+
+ + +
+
+
+
+
+

+

+
+
+
+
+
+
+

+

+
+
+
+
+
+
+

+

+
+
+
+
-
-

+
+

@@ -73,81 +146,102 @@ $flash = get_flash();
- - + +
- - + +
-
- - -
-
- - -
-
- - -
-
+ +
- + + +
+
+ + +
+
+ +
+ + +
+ +
+
+
- +
-
+
- +
- +
- +
-
-
-

- total +
+
+

+
+ -

+
+ +

+
-
+
- - - - - + + + + - - - - + + + @@ -161,4 +255,4 @@ $flash = get_flash(); - + \ No newline at end of file diff --git a/truck_owner_dashboard.php b/truck_owner_dashboard.php index 960c175..11f85da 100644 --- a/truck_owner_dashboard.php +++ b/truck_owner_dashboard.php @@ -7,6 +7,16 @@ ensure_schema(); $errors = []; +// Try to prefill owner name from profile if logged in +$prefillOwnerName = ''; +if (isset($_SESSION['user_id'])) { + try { + $stmt = db()->prepare("SELECT full_name FROM users WHERE id = ?"); + $stmt->execute([$_SESSION['user_id']]); + $prefillOwnerName = $stmt->fetchColumn() ?: ''; + } catch (Throwable $e) {} +} + if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'submit_offer') { $shipmentId = (int) ($_POST['shipment_id'] ?? 0); $offerOwner = trim($_POST['offer_owner'] ?? ''); @@ -29,6 +39,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'submi ':id' => $shipmentId, ]); if ($stmt->rowCount() > 0) { + $_SESSION['last_offer_owner'] = $offerOwner; // Save for next time set_flash('success', t('success_offer')); header('Location: ' . url_with_lang('truck_owner_dashboard.php')); exit; @@ -38,6 +49,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'submi } } +$ownerName = $_SESSION['last_offer_owner'] ?? $prefillOwnerName; + $shipments = []; try { $stmt = db()->query("SELECT * FROM shipments WHERE status IN ('posted','offered') ORDER BY created_at DESC LIMIT 20"); @@ -46,57 +59,125 @@ try { $shipments = []; } -render_header(t('owner_dashboard'), 'owner'); +$stats = [ + 'available' => count($shipments), + 'my_offers' => 0, + 'won' => 0, +]; +try { + if ($ownerName) { + $stats['my_offers'] = (int)db()->query("SELECT COUNT(*) FROM shipments WHERE offer_owner = " . db()->quote($ownerName))->fetchColumn(); + $stats['won'] = (int)db()->query("SELECT COUNT(*) FROM shipments WHERE offer_owner = " . db()->quote($ownerName) . " AND status IN ('confirmed','in_transit','delivered')")->fetchColumn(); + } +} catch (Throwable $e) {} + +render_header(t('owner_dashboard'), 'owner'); $flash = get_flash(); ?> -
-
-

- total +
+

+

+
+ + +
+
+
+
+
+

+

+
+
+
+
+
+

+

+
+
+
+
+
+
+

+

+
+
+
+ +
+
+

+ +
+
+ -

+
+ +

+
- +
+ + + +
+ +
+ +
$
+ + + + +
+
- - - - - - + + + + + - - - - - + + + + @@ -107,4 +188,4 @@ $flash = get_flash(); - + \ No newline at end of file
-
+
+ +
+
+ + + +
+
+
Ton(s)
+ +
+ +
$
+ + + + +
+ - - -
- - - - + +
+ $ +
+ + + +