arabic translation

This commit is contained in:
Flatlogic Bot 2026-03-13 10:55:45 +00:00
parent 2ee38edf60
commit 0ebb8e142e
12 changed files with 633 additions and 472 deletions

View File

@ -43,7 +43,7 @@ render_header(t('admin_dashboard'), 'admin', true);
<div class="col-md-10 p-4">
<div class="page-intro mb-4">
<h1 class="section-title mb-1"><?= e(t('admin_dashboard')) ?></h1>
<p class="muted mb-0">Overview of your platform's performance and recent activity.</p>
<p class="muted mb-0"><?= e(t('overview_performance')) ?></p>
</div>
<!-- Stats Row -->
@ -53,7 +53,7 @@ render_header(t('admin_dashboard'), 'admin', true);
<div class="position-absolute opacity-10" style="inset-inline-end: 10px; top: 15px;"><i class="bi bi-box-seam" style="font-size: 3.5rem;"></i></div>
<div class="text-primary mb-2 position-relative"><i class="bi bi-box-seam fs-2"></i></div>
<h3 class="h2 mb-0 fw-bold position-relative"><?= $stats['total_shipments'] ?></h3>
<p class="text-muted small text-uppercase mb-0 fw-bold position-relative" style="letter-spacing: 0.5px;">Total Shipments</p>
<p class="text-muted small text-uppercase mb-0 fw-bold position-relative" style="letter-spacing: 0.5px;"><?= e(t('total_shipments')) ?></p>
</div>
</div>
<div class="col-md-3">
@ -61,7 +61,7 @@ render_header(t('admin_dashboard'), 'admin', true);
<div class="position-absolute opacity-10" style="inset-inline-end: 10px; top: 15px;"><i class="bi bi-truck" style="font-size: 3.5rem;"></i></div>
<div class="text-warning mb-2 position-relative"><i class="bi bi-truck fs-2"></i></div>
<h3 class="h2 mb-0 fw-bold position-relative"><?= $stats['active_shipments'] ?></h3>
<p class="text-muted small text-uppercase mb-0 fw-bold position-relative" style="letter-spacing: 0.5px;">Active Shipments</p>
<p class="text-muted small text-uppercase mb-0 fw-bold position-relative" style="letter-spacing: 0.5px;"><?= e(t('active_shipments')) ?></p>
</div>
</div>
<div class="col-md-3">
@ -69,7 +69,7 @@ render_header(t('admin_dashboard'), 'admin', true);
<div class="position-absolute opacity-10" style="inset-inline-end: 10px; top: 15px;"><i class="bi bi-people" style="font-size: 3.5rem;"></i></div>
<div class="text-success mb-2 position-relative"><i class="bi bi-people fs-2"></i></div>
<h3 class="h2 mb-0 fw-bold position-relative"><?= $stats['total_shippers'] ?></h3>
<p class="text-muted small text-uppercase mb-0 fw-bold position-relative" style="letter-spacing: 0.5px;">Total Shippers</p>
<p class="text-muted small text-uppercase mb-0 fw-bold position-relative" style="letter-spacing: 0.5px;"><?= e(t('total_shippers')) ?></p>
</div>
</div>
<div class="col-md-3">
@ -77,7 +77,7 @@ render_header(t('admin_dashboard'), 'admin', true);
<div class="position-absolute opacity-10" style="inset-inline-end: 10px; top: 15px;"><i class="bi bi-person-vcard" style="font-size: 3.5rem;"></i></div>
<div class="text-info mb-2 position-relative"><i class="bi bi-person-vcard fs-2"></i></div>
<h3 class="h2 mb-0 fw-bold position-relative"><?= $stats['total_truck_owners'] ?></h3>
<p class="text-muted small text-uppercase mb-0 fw-bold position-relative" style="letter-spacing: 0.5px;">Truck Owners</p>
<p class="text-muted small text-uppercase mb-0 fw-bold position-relative" style="letter-spacing: 0.5px;"><?= e(t('total_truck_owners')) ?></p>
</div>
</div>
</div>
@ -87,8 +87,8 @@ render_header(t('admin_dashboard'), 'admin', true);
<div class="col-lg-8">
<div class="panel shadow-sm border-0 h-100 rounded-4 d-flex flex-column">
<div class="panel-heading d-flex justify-content-between align-items-center">
<h2 class="h5 mb-0 fw-bold text-white"><i class="bi bi-clock-history text-white-50 me-2"></i>Recent Shipments</h2>
<span class="badge bg-white text-dark"><?= e(count($shipments)) ?> shown</span>
<h2 class="h5 mb-0 fw-bold text-white"><i class="bi bi-clock-history text-white-50 me-2"></i><?= e(t('recent_shipments')) ?></h2>
<span class="badge bg-white text-dark"><?= e(count($shipments)) ?> <?= e(t('shown')) ?></span>
</div>
<div class="p-4 flex-grow-1 d-flex flex-column">
<?php if ($flash): ?>
@ -107,10 +107,10 @@ render_header(t('admin_dashboard'), 'admin', true);
<table class="table align-middle mb-0">
<thead>
<tr>
<th class="text-uppercase small text-muted border-top-0">Shipment</th>
<th class="text-uppercase small text-muted border-top-0">Route</th>
<th class="text-uppercase small text-muted border-top-0"><?= e(t('shipment')) ?></th>
<th class="text-uppercase small text-muted border-top-0"><?= e(t('route')) ?></th>
<th class="text-uppercase small text-muted border-top-0"><?= e(t('status')) ?></th>
<th class="text-uppercase small text-muted border-top-0 text-end">Action</th>
<th class="text-uppercase small text-muted border-top-0 text-end"><?= e(t('action')) ?></th>
</tr>
</thead>
<tbody>
@ -129,7 +129,7 @@ render_header(t('admin_dashboard'), 'admin', true);
</td>
<td><span class="badge <?= e($row['status']) ?> rounded-pill px-3 py-2"><?= e(status_label($row['status'])) ?></span></td>
<td class="text-end">
<a href="<?= e(url_with_lang('shipment_detail.php', ['id' => $row['id']])) ?>" class="btn btn-sm p-1 border-0 bg-transparent text-primary" title="View Details">
<a href="<?= e(url_with_lang('shipment_detail.php', ['id' => $row['id']])) ?>" class="btn btn-sm p-1 border-0 bg-transparent text-primary" title="<?= e(t('view_details')) ?>">
<i class="bi bi-eye"></i>
</a>
</td>
@ -147,47 +147,47 @@ render_header(t('admin_dashboard'), 'admin', true);
<div class="col-lg-4">
<div class="panel shadow-sm border-0 h-100 rounded-4" style="background-color: #fafbfc;">
<div class="panel-heading">
<h2 class="h5 mb-0 fw-bold text-white"><i class="bi bi-lightning-charge text-warning me-2"></i>Quick Links</h2>
<h2 class="h5 mb-0 fw-bold text-white"><i class="bi bi-lightning-charge text-warning me-2"></i><?= e(t('quick_links')) ?></h2>
</div>
<div class="p-4">
<div class="list-group list-group-flush bg-transparent">
<a href="<?= e(url_with_lang('admin_countries.php')) ?>" class="list-group-item list-group-item-action bg-transparent border-bottom d-flex align-items-center py-3 px-0">
<div class="bg-white rounded p-3 shadow-sm me-3 text-primary d-flex align-items-center justify-content-center" style="width: 48px; height: 48px;"><i class="bi bi-globe2 fs-5"></i></div>
<div>
<h6 class="mb-1 fw-bold">Manage Countries</h6>
<small class="text-muted d-block line-height-sm">Add or remove supported countries</small>
<h6 class="mb-1 fw-bold"><?= e(t('manage_countries')) ?></h6>
<small class="text-muted d-block line-height-sm"><?= e(t('add_remove_countries')) ?></small>
</div>
<i class="bi bi-chevron-right ms-auto text-muted small"></i>
</a>
<a href="<?= e(url_with_lang('admin_cities.php')) ?>" class="list-group-item list-group-item-action bg-transparent border-bottom d-flex align-items-center py-3 px-0">
<div class="bg-white rounded p-3 shadow-sm me-3 text-primary d-flex align-items-center justify-content-center" style="width: 48px; height: 48px;"><i class="bi bi-pin-map fs-5"></i></div>
<div>
<h6 class="mb-1 fw-bold">Manage Cities</h6>
<small class="text-muted d-block line-height-sm">Configure cities for routing</small>
<h6 class="mb-1 fw-bold"><?= e(t('manage_cities')) ?></h6>
<small class="text-muted d-block line-height-sm"><?= e(t('configure_cities')) ?></small>
</div>
<i class="bi bi-chevron-right ms-auto text-muted small"></i>
</a>
<a href="<?= e(url_with_lang('register.php')) ?>" class="list-group-item list-group-item-action bg-transparent border-bottom d-flex align-items-center py-3 px-0">
<div class="bg-white rounded p-3 shadow-sm me-3 text-success d-flex align-items-center justify-content-center" style="width: 48px; height: 48px;"><i class="bi bi-person-plus fs-5"></i></div>
<div>
<h6 class="mb-1 fw-bold">Register User</h6>
<small class="text-muted d-block line-height-sm">Manually onboard a new user</small>
<h6 class="mb-1 fw-bold"><?= e(t('register_user')) ?></h6>
<small class="text-muted d-block line-height-sm"><?= e(t('manually_onboard')) ?></small>
</div>
<i class="bi bi-chevron-right ms-auto text-muted small"></i>
</a>
<a href="<?= e(url_with_lang('admin_company_profile.php')) ?>" class="list-group-item list-group-item-action bg-transparent border-bottom d-flex align-items-center py-3 px-0">
<div class="bg-white rounded p-3 shadow-sm me-3 text-secondary d-flex align-items-center justify-content-center" style="width: 48px; height: 48px;"><i class="bi bi-buildings fs-5"></i></div>
<div>
<h6 class="mb-1 fw-bold">Company Profile</h6>
<small class="text-muted d-block line-height-sm">Update platform branding</small>
<h6 class="mb-1 fw-bold"><?= e(t('company_profile')) ?></h6>
<small class="text-muted d-block line-height-sm"><?= e(t('update_branding')) ?></small>
</div>
<i class="bi bi-chevron-right ms-auto text-muted small"></i>
</a>
<a href="<?= e(url_with_lang('admin_landing_pages.php')) ?>" class="list-group-item list-group-item-action bg-transparent d-flex align-items-center py-3 px-0">
<div class="bg-white rounded p-3 shadow-sm me-3 text-info d-flex align-items-center justify-content-center" style="width: 48px; height: 48px;"><i class="bi bi-layout-text-window-reverse fs-5"></i></div>
<div>
<h6 class="mb-1 fw-bold">Landing Pages</h6>
<small class="text-muted d-block line-height-sm">Edit homepage content and sections</small>
<h6 class="mb-1 fw-bold"><?= e(t('landing_pages')) ?></h6>
<small class="text-muted d-block line-height-sm"><?= e(t('edit_homepage')) ?></small>
</div>
<i class="bi bi-chevron-right ms-auto text-muted small"></i>
</a>

View File

@ -5,7 +5,7 @@ require_once __DIR__ . '/includes/layout.php';
// Check permission
if (!has_permission('view_reports') && !has_permission('manage_shippers')) {
render_header(t('shippers_statements') ?: 'Shippers Statements', 'reports_shippers');
render_header(t('shippers_statements'), 'reports_shippers');
echo '<div class="container py-5"><div class="alert alert-danger">Access Denied. You do not have permission to view reports.</div></div>';
render_footer();
exit;
@ -72,7 +72,7 @@ if ($shipperId) {
}
}
render_header(t('shippers_statements') ?: 'Shippers Statements', 'reports_shippers', true);
render_header(t('shippers_statements'), 'reports_shippers', true);
?>
<!-- Select2 CSS -->
@ -132,12 +132,12 @@ render_header(t('shippers_statements') ?: 'Shippers Statements', 'reports_shippe
<!-- Screen Only Header -->
<div class="page-intro d-flex justify-content-between align-items-center mb-4 no-print">
<div>
<h1 class="section-title mb-1">Shipper Statements</h1>
<p class="muted mb-0">View and print financial statements for shippers.</p>
<h1 class="section-title mb-1"><?= e(t('shippers_statements')) ?></h1>
<p class="muted mb-0"><?= e(t('view_print_statements')) ?></p>
</div>
<?php if ($shipper): ?>
<button onclick="window.print()" class="btn btn-dark">
<i class="bi bi-printer me-2"></i>Print Formal Statement
<i class="bi bi-printer me-2"></i><?= e(t('print_formal_statement')) ?>
</button>
<?php endif; ?>
</div>
@ -146,9 +146,9 @@ render_header(t('shippers_statements') ?: 'Shippers Statements', 'reports_shippe
<div class="panel p-4 mb-4 no-print filter-form">
<form method="get" class="row g-3 align-items-end">
<div class="col-md-4">
<label class="form-label small text-muted">Select Shipper</label>
<label class="form-label small text-muted"><?= e(t('select_shipper')) ?></label>
<select name="shipper_id" id="shipperSelect" class="form-select" onchange="this.form.submit()">
<option value="">-- Choose a Shipper --</option>
<option value=""><?= e(t('choose_shipper')) ?></option>
<?php foreach ($allShippers as $s): ?>
<option value="<?= $s['id'] ?>" <?= $shipperId == $s['id'] ? 'selected' : '' ?>>
<?= e($s['full_name']) ?> (<?= e($s['company_name'] ?: 'No Company') ?>)
@ -157,21 +157,21 @@ render_header(t('shippers_statements') ?: 'Shippers Statements', 'reports_shippe
</select>
</div>
<div class="col-md-3">
<label class="form-label small text-muted">Start Date</label>
<label class="form-label small text-muted"><?= e(t('start_date')) ?></label>
<input type="date" name="start_date" class="form-control" value="<?= e($startDate) ?>">
</div>
<div class="col-md-3">
<label class="form-label small text-muted">End Date</label>
<label class="form-label small text-muted"><?= e(t('end_date')) ?></label>
<input type="date" name="end_date" class="form-control" value="<?= e($endDate) ?>">
</div>
<div class="col-md-2">
<button type="submit" class="btn btn-primary w-100">Filter</button>
<button type="submit" class="btn btn-primary w-100"><?= e(t('filter')) ?></button>
</div>
</form>
</div>
<?php if ($shipperId && !$shipper): ?>
<div class="alert alert-warning">Shipper not found.</div>
<div class="alert alert-warning"><?= e(t('shipper_not_found')) ?></div>
<?php elseif ($shipper): ?>
<div class="panel p-5 bg-white">
<!-- Print Header (Compact) -->
@ -181,7 +181,7 @@ render_header(t('shippers_statements') ?: 'Shippers Statements', 'reports_shippe
<p class="mt-1"><?= date('F j, Y') ?></p>
</div>
<div class="print-header-right">
<h1>Statement of Account</h1>
<h1><?= e(t('statement_of_account')) ?></h1>
<h2 style="font-size: 12pt; margin: 0; font-weight: normal;">كشف حساب</h2>
</div>
</div>
@ -189,7 +189,7 @@ render_header(t('shippers_statements') ?: 'Shippers Statements', 'reports_shippe
<!-- Info Section (Compact) -->
<div class="statement-info row">
<div class="col-6">
<h5>Billed To / إلى السيد</h5>
<h5><?= e(t('billed_to')) ?> / إلى السيد</h5>
<h4><?= e($shipper['full_name']) ?></h4>
<div class="small text-muted">
<?= e($shipper['company_name'] ?: '-') ?><br>
@ -199,17 +199,17 @@ render_header(t('shippers_statements') ?: 'Shippers Statements', 'reports_shippe
</div>
</div>
<div class="col-6 text-end">
<h5>Summary / ملخص</h5>
<h5><?= e(t('summary')) ?> / ملخص</h5>
<div class="small">
<div><strong>Date:</strong> <?= date('Y-m-d') ?></div>
<?php if ($startDate || $endDate): ?>
<div><strong>Period:</strong> <?= e($startDate ?: 'Start') ?> to <?= e($endDate ?: 'Now') ?></div>
<div><strong><?= e(t('period')) ?>:</strong> <?= e($startDate ?: 'Start') ?> to <?= e($endDate ?: 'Now') ?></div>
<?php else: ?>
<div><strong>Period:</strong> All Time</div>
<div><strong><?= e(t('period')) ?>:</strong> <?= e(t('all_time')) ?></div>
<?php endif; ?>
<div><strong>Count:</strong> <?= count($shipments) ?></div>
<div><strong><?= e(t('total_count')) ?>:</strong> <?= count($shipments) ?></div>
<div class="fs-5 fw-bold text-primary mt-1">
<?= number_format($totalAmount, 2) ?> OMR
<?= format_currency($totalAmount) ?>
</div>
</div>
</div>
@ -218,18 +218,18 @@ render_header(t('shippers_statements') ?: 'Shippers Statements', 'reports_shippe
<!-- Table -->
<div class="table-responsive">
<table class="table table-bordered align-middle">
<thead class="table-light">
<thead>
<tr>
<th>Date <br> <span class="fw-normal text-muted">التاريخ</span></th>
<th>Ref # <br> <span class="fw-normal text-muted">رقم الشحنة</span></th>
<th>Route <br> <span class="fw-normal text-muted">المسار</span></th>
<th>Status <br> <span class="fw-normal text-muted">الحالة</span></th>
<th class="text-end">Amount (OMR) <br> <span class="fw-normal text-muted">المبلغ</span></th>
<th><?= e(t('route')) ?> <br> <span class="fw-normal text-muted">المسار</span></th>
<th><?= e(t('status')) ?> <br> <span class="fw-normal text-muted">الحالة</span></th>
<th class="text-end"><?= e(t('amount')) ?> <br> <span class="fw-normal text-muted">المبلغ</span></th>
</tr>
</thead>
<tbody>
<?php if (empty($shipments)): ?>
<tr><td colspan="5" class="text-center py-4 text-muted">No completed shipments found for this period.</td></tr>
<tr><td colspan="5" class="text-center py-4 text-muted"><?= e(t('no_completed_shipments')) ?></td></tr>
<?php else: ?>
<?php foreach ($shipments as $row): ?>
<tr>
@ -240,10 +240,10 @@ render_header(t('shippers_statements') ?: 'Shippers Statements', 'reports_shippe
<div class="small text-muted"><?= e($row['cargo_description']) ?></div>
</td>
<td>
<?= e(ucfirst(str_replace('_', ' ', $row['status']))) ?>
<?= e(status_label($row['status'])) ?>
</td>
<td class="text-end fw-bold">
<?= number_format((float)$row['total_price'], 2) ?>
<?= format_currency((float)$row['total_price']) ?>
</td>
</tr>
<?php endforeach; ?>
@ -251,8 +251,8 @@ render_header(t('shippers_statements') ?: 'Shippers Statements', 'reports_shippe
</tbody>
<tfoot>
<tr class="total-row table-active">
<td colspan="4" class="text-end text-uppercase">Total Balance / الإجمالي</td>
<td class="text-end text-dark"><?= number_format($totalAmount, 2) ?> OMR</td>
<td colspan="4" class="text-end text-uppercase"><?= e(t('total_balance')) ?> / الإجمالي</td>
<td class="text-end text-dark"><?= format_currency($totalAmount) ?></td>
</tr>
</tfoot>
</table>
@ -262,12 +262,12 @@ render_header(t('shippers_statements') ?: 'Shippers Statements', 'reports_shippe
<div class="print-footer">
<div class="row">
<div class="col-6 text-start">
Authorized Signature<br>
<?= e(t('authorized_signature')) ?><br>
_______________________
</div>
<div class="col-6 text-end">
Printed on <?= date('Y-m-d H:i') ?><br>
This is a computer-generated document.
<?= e(t('printed_on')) ?> <?= date('Y-m-d H:i') ?><br>
<?= e(t('generated_doc')) ?>
</div>
</div>
</div>
@ -283,7 +283,7 @@ render_header(t('shippers_statements') ?: 'Shippers Statements', 'reports_shippe
$(document).ready(function() {
$('#shipperSelect').select2({
width: '100%',
placeholder: '-- Choose a Shipper --',
placeholder: '<?= e(t('choose_shipper')) ?>',
allowClear: true
});
});

View File

@ -26,13 +26,15 @@ $selectName = '';
$join = '';
$orderBy = 'total_amount DESC';
$pageTitle = t('shipments_by_origin_country');
switch ($reportType) {
case 'countries_origin':
$selectName = "COALESCE(co.name_en, 'Unknown') as name";
$join = "LEFT JOIN cities c ON s.origin_city = c.name_en
LEFT JOIN countries co ON c.country_id = co.id";
$groupBy = "co.name_en";
$pageTitle = "Shipments by Origin Country";
$pageTitle = t('shipments_by_origin_country');
break;
case 'countries_dest':
@ -40,25 +42,25 @@ switch ($reportType) {
$join = "LEFT JOIN cities c ON s.destination_city = c.name_en
LEFT JOIN countries co ON c.country_id = co.id";
$groupBy = "co.name_en";
$pageTitle = "Shipments by Destination Country";
$pageTitle = t('shipments_by_dest_country');
break;
case 'cities_origin':
$selectName = "s.origin_city as name";
$groupBy = "s.origin_city";
$pageTitle = "Shipments by Origin City";
$pageTitle = t('shipments_by_origin_city');
break;
case 'cities_dest':
$selectName = "s.destination_city as name";
$groupBy = "s.destination_city";
$pageTitle = "Shipments by Destination City";
$pageTitle = t('shipments_by_dest_city');
break;
case 'shippers':
$selectName = "s.shipper_name as name"; // simplified, could join users table
$groupBy = "s.shipper_name";
$pageTitle = "Shipments by Shipper";
$pageTitle = t('shipments_by_shipper');
break;
default:
@ -67,7 +69,7 @@ switch ($reportType) {
$join = "LEFT JOIN cities c ON s.origin_city = c.name_en
LEFT JOIN countries co ON c.country_id = co.id";
$groupBy = "co.name_en";
$pageTitle = "Shipments by Origin Country";
$pageTitle = t('shipments_by_origin_country');
break;
}
@ -104,54 +106,96 @@ foreach ($results as $row) {
$grandTotalProfit += $row['total_profit'];
}
render_header('Reports Summary', 'reports_summary', true);
render_header(t('summary_report'), 'reports_summary', true);
?>
<div class="row g-0">
<div class="col-md-2 bg-white border-end min-vh-100">
<div class="col-md-2 bg-white border-end min-vh-100 d-print-none">
<?php render_admin_sidebar('reports_summary'); ?>
</div>
<div class="col-md-10 p-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<!-- Print Header -->
<div class="d-none d-print-block mb-4">
<div class="row align-items-center mb-4">
<div class="col-6">
<?php
$logoPath = get_setting('logo_path');
if ($logoPath): ?>
<img src="<?= e($logoPath) ?>" alt="Company Logo" style="max-height: 80px; width: auto;">
<?php else: ?>
<h2 class="fw-bold mb-0 text-dark"><?= e(get_setting('company_name', 'CargoLink')) ?></h2>
<?php endif; ?>
</div>
<div class="col-6 text-end">
<h3 class="mb-1 text-dark fw-bold"><?= e(t('summary_report')) ?></h3>
<p class="mb-0 text-muted small">
<?= e(get_setting('company_address')) ?><br>
<?= e(get_setting('company_email')) ?> | <?= e(get_setting('company_phone')) ?>
</p>
<p class="mb-0 text-muted small mt-2">
<?= e(t('generated')) ?>: <?= date('d M Y, H:i') ?>
</p>
</div>
</div>
<div class="row mb-4">
<div class="col-12">
<div class="border p-3 rounded bg-light">
<div class="row">
<div class="col-6">
<strong class="text-muted d-block small text-uppercase"><?= e(t('report_type')) ?></strong>
<span class="fs-5 fw-bold text-dark"><?= e($pageTitle) ?></span>
</div>
<div class="col-6 text-end">
<strong class="text-muted d-block small text-uppercase"><?= e(t('period')) ?></strong>
<span class="fs-5 fw-bold text-dark"><?= e($startDate) ?> &mdash; <?= e($endDate) ?></span>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="d-flex justify-content-between align-items-center mb-4 d-print-none">
<div>
<h1 class="section-title mb-1">Summary Reports</h1>
<p class="muted mb-0">Analyze shipment performance, revenue, and profits.</p>
<h1 class="section-title mb-1"><?= e(t('summary_report')) ?></h1>
<p class="muted mb-0"><?= e(t('analyze_performance')) ?></p>
</div>
<div>
<button class="btn btn-outline-secondary btn-sm" onclick="window.print()">
<i class="bi bi-printer me-2"></i>Print
<i class="bi bi-printer me-2"></i><?= e(t('print')) ?>
</button>
</div>
</div>
<div class="panel p-4 mb-4">
<div class="panel p-4 mb-4 d-print-none">
<form method="get" class="row g-3 align-items-end">
<div class="col-md-3">
<label class="form-label small text-muted">Report Type</label>
<label class="form-label small text-muted"><?= e(t('report_type')) ?></label>
<select name="type" class="form-select" onchange="this.form.submit()">
<option value="countries_origin" <?= $reportType === 'countries_origin' ? 'selected' : '' ?>>By Origin Country</option>
<option value="countries_dest" <?= $reportType === 'countries_dest' ? 'selected' : '' ?>>By Destination Country</option>
<option value="cities_origin" <?= $reportType === 'cities_origin' ? 'selected' : '' ?>>By Origin City</option>
<option value="cities_dest" <?= $reportType === 'cities_dest' ? 'selected' : '' ?>>By Destination City</option>
<option value="shippers" <?= $reportType === 'shippers' ? 'selected' : '' ?>>By Shipper</option>
<option value="countries_origin" <?= $reportType === 'countries_origin' ? 'selected' : '' ?>><?= e(t('shipments_by_origin_country')) ?></option>
<option value="countries_dest" <?= $reportType === 'countries_dest' ? 'selected' : '' ?>><?= e(t('shipments_by_dest_country')) ?></option>
<option value="cities_origin" <?= $reportType === 'cities_origin' ? 'selected' : '' ?>><?= e(t('shipments_by_origin_city')) ?></option>
<option value="cities_dest" <?= $reportType === 'cities_dest' ? 'selected' : '' ?>><?= e(t('shipments_by_dest_city')) ?></option>
<option value="shippers" <?= $reportType === 'shippers' ? 'selected' : '' ?>><?= e(t('shipments_by_shipper')) ?></option>
</select>
</div>
<div class="col-md-3">
<label class="form-label small text-muted">Start Date</label>
<label class="form-label small text-muted"><?= e(t('start_date')) ?></label>
<input type="date" name="start_date" class="form-control" value="<?= e($startDate) ?>">
</div>
<div class="col-md-3">
<label class="form-label small text-muted">End Date</label>
<label class="form-label small text-muted"><?= e(t('end_date')) ?></label>
<input type="date" name="end_date" class="form-control" value="<?= e($endDate) ?>">
</div>
<div class="col-md-2">
<button type="submit" class="btn btn-primary w-100">Apply Filter</button>
<button type="submit" class="btn btn-primary w-100"><?= e(t('apply_filter')) ?></button>
</div>
</form>
</div>
<div class="panel p-0">
<div class="p-3 border-bottom bg-light d-flex justify-content-between align-items-center">
<div class="panel p-0 print-no-shadow">
<div class="p-3 border-bottom bg-light d-flex justify-content-between align-items-center d-print-none">
<h5 class="mb-0 fw-bold"><?= e($pageTitle) ?></h5>
<span class="badge bg-secondary"><?= e($startDate) ?> to <?= e($endDate) ?></span>
</div>
@ -159,17 +203,17 @@ render_header('Reports Summary', 'reports_summary', true);
<?php if (empty($results)): ?>
<div class="p-5 text-center text-muted">
<i class="bi bi-bar-chart fs-1 mb-3 d-block"></i>
<p class="mb-0">No paid shipments found for this period.</p>
<p class="mb-0"><?= e(t('no_paid_shipments')) ?></p>
</div>
<?php else: ?>
<div class="table-responsive">
<table class="table table-hover mb-0 align-middle">
<thead class="table-light">
<thead>
<tr>
<th class="ps-4">Name</th>
<th class="text-center">Shipments</th>
<th class="text-end">Total Amount</th>
<th class="text-end pe-4">Profit</th>
<th class="ps-4"><?= e(t('name')) ?></th>
<th class="text-center"><?= e(t('stats_shipments')) ?></th>
<th class="text-end"><?= e(t('total_amount')) ?></th>
<th class="text-end pe-4"><?= e(t('profit')) ?></th>
</tr>
</thead>
<tbody>
@ -177,32 +221,36 @@ render_header('Reports Summary', 'reports_summary', true);
<tr>
<td class="ps-4 fw-medium"><?= e($row['name']) ?></td>
<td class="text-center"><?= number_format((int)$row['shipment_count']) ?></td>
<td class="text-end text-dark">$<?= number_format((float)$row['total_amount'], 2) ?></td>
<td class="text-end pe-4 text-success fw-bold">$<?= number_format((float)$row['total_profit'], 2) ?></td>
<td class="text-end text-dark"><?= format_currency((float)$row['total_amount']) ?></td>
<td class="text-end pe-4 text-success fw-bold"><?= format_currency((float)$row['total_profit']) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
<tfoot class="table-light fw-bold border-top">
<tr>
<td class="ps-4">TOTAL</td>
<td class="ps-4"><?= e(t('total_label')) ?></td>
<td class="text-center"><?= number_format($totalShipments) ?></td>
<td class="text-end">$<?= number_format($grandTotalAmount, 2) ?></td>
<td class="text-end pe-4 text-success">$<?= number_format($grandTotalProfit, 2) ?></td>
<td class="text-end"><?= format_currency($grandTotalAmount) ?></td>
<td class="text-end pe-4 text-success"><?= format_currency($grandTotalProfit) ?></td>
</tr>
</tfoot>
</table>
</div>
<?php endif; ?>
<!-- Print Footer -->
<div class="d-none d-print-block print-footer border-top pt-2">
<div class="row text-muted small">
<div class="col-6">
<?= e(t('printed_by')) ?>: <?= e($_SESSION['user_name'] ?? 'Admin') ?>
</div>
<div class="col-6 text-end">
<?= e(t('generated')) ?>: <?= date('d M Y H:i') ?>
</div>
</div>
</div>
</div>
</div>
</div>
<style>
@media print {
.admin-sidebar, .btn, form { display: none !important; }
.col-md-10 { width: 100% !important; padding: 0 !important; }
.panel { border: none !important; box-shadow: none !important; }
}
</style>
<?php render_footer(); ?>

View File

@ -5,7 +5,7 @@ require_once __DIR__ . '/includes/layout.php';
// Check permission
if (!has_permission('view_reports') && !has_permission('manage_truck_owners')) {
render_header(t('truck_owners_statements') ?: 'Truck Owner Statements', 'reports_truck_owners');
render_header(t('truck_owners_statements'), 'reports_truck_owners');
echo '<div class="container py-5"><div class="alert alert-danger">Access Denied. You do not have permission to view reports.</div></div>';
render_footer();
exit;
@ -72,7 +72,7 @@ if ($ownerId) {
}
}
render_header(t('truck_owners_statements') ?: 'Truck Owner Statements', 'reports_truck_owners', true);
render_header(t('truck_owners_statements'), 'reports_truck_owners', true);
?>
<!-- Select2 CSS -->
@ -132,12 +132,12 @@ render_header(t('truck_owners_statements') ?: 'Truck Owner Statements', 'reports
<!-- Screen Only Header -->
<div class="page-intro d-flex justify-content-between align-items-center mb-4 no-print">
<div>
<h1 class="section-title mb-1">Truck Owner Statements</h1>
<p class="muted mb-0">View and print financial statements for truck owners.</p>
<h1 class="section-title mb-1"><?= e(t('truck_owners_statements')) ?></h1>
<p class="muted mb-0"><?= e(t('view_print_owner_statements')) ?></p>
</div>
<?php if ($owner): ?>
<button onclick="window.print()" class="btn btn-dark">
<i class="bi bi-printer me-2"></i>Print Formal Statement
<i class="bi bi-printer me-2"></i><?= e(t('print_formal_statement')) ?>
</button>
<?php endif; ?>
</div>
@ -146,9 +146,9 @@ render_header(t('truck_owners_statements') ?: 'Truck Owner Statements', 'reports
<div class="panel p-4 mb-4 no-print filter-form">
<form method="get" class="row g-3 align-items-end">
<div class="col-md-4">
<label class="form-label small text-muted">Select Truck Owner</label>
<label class="form-label small text-muted"><?= e(t('select_truck_owner')) ?></label>
<select name="owner_id" id="ownerSelect" class="form-select" onchange="this.form.submit()">
<option value="">-- Choose a Truck Owner --</option>
<option value=""><?= e(t('choose_truck_owner')) ?></option>
<?php foreach ($allOwners as $o): ?>
<option value="<?= $o['id'] ?>" <?= $ownerId == $o['id'] ? 'selected' : '' ?>>
<?= e($o['full_name']) ?> (Plate: <?= e($o['plate_no'] ?: '-') ?>)
@ -157,21 +157,21 @@ render_header(t('truck_owners_statements') ?: 'Truck Owner Statements', 'reports
</select>
</div>
<div class="col-md-3">
<label class="form-label small text-muted">Start Date</label>
<label class="form-label small text-muted"><?= e(t('start_date')) ?></label>
<input type="date" name="start_date" class="form-control" value="<?= e($startDate) ?>">
</div>
<div class="col-md-3">
<label class="form-label small text-muted">End Date</label>
<label class="form-label small text-muted"><?= e(t('end_date')) ?></label>
<input type="date" name="end_date" class="form-control" value="<?= e($endDate) ?>">
</div>
<div class="col-md-2">
<button type="submit" class="btn btn-primary w-100">Filter</button>
<button type="submit" class="btn btn-primary w-100"><?= e(t('filter')) ?></button>
</div>
</form>
</div>
<?php if ($ownerId && !$owner): ?>
<div class="alert alert-warning">Truck Owner not found.</div>
<div class="alert alert-warning"><?= e(t('owner_not_found')) ?></div>
<?php elseif ($owner): ?>
<div class="panel p-5 bg-white">
<!-- Print Header (Compact) -->
@ -181,7 +181,7 @@ render_header(t('truck_owners_statements') ?: 'Truck Owner Statements', 'reports
<p class="mt-1"><?= date('F j, Y') ?></p>
</div>
<div class="print-header-right">
<h1>Payment Statement</h1>
<h1><?= e(t('payment_statement')) ?></h1>
<h2 style="font-size: 12pt; margin: 0; font-weight: normal;">كشف مدفوعات</h2>
</div>
</div>
@ -189,9 +189,9 @@ render_header(t('truck_owners_statements') ?: 'Truck Owner Statements', 'reports
<!-- Info Section (Compact) -->
<div class="statement-info row">
<div class="col-6">
<h5>Pay To / إلى السيد</h5>
<h5><?= e(t('pay_to')) ?> / إلى السيد</h5>
<h4><?= e($owner['full_name']) ?></h4>
<div class="text-muted small">Truck Plate: <?= e($owner['plate_no'] ?: '-') ?></div>
<div class="text-muted small"><?= e(t('truck_plate')) ?>: <?= e($owner['plate_no'] ?: '-') ?></div>
<div class="small text-muted">
<?= e($owner['truck_type'] ?: '') ?><br>
<?= e($owner['city'] ?: '') ?>, <?= e($owner['country'] ?: '') ?><br>
@ -199,17 +199,17 @@ render_header(t('truck_owners_statements') ?: 'Truck Owner Statements', 'reports
</div>
</div>
<div class="col-6 text-end">
<h5>Summary / ملخص</h5>
<h5><?= e(t('summary')) ?> / ملخص</h5>
<div class="small">
<div><strong>Date:</strong> <?= date('Y-m-d') ?></div>
<?php if ($startDate || $endDate): ?>
<div><strong>Period:</strong> <?= e($startDate ?: 'Start') ?> to <?= e($endDate ?: 'Now') ?></div>
<div><strong><?= e(t('period')) ?>:</strong> <?= e($startDate ?: 'Start') ?> to <?= e($endDate ?: 'Now') ?></div>
<?php else: ?>
<div><strong>Period:</strong> All Time</div>
<div><strong><?= e(t('period')) ?>:</strong> <?= e(t('all_time')) ?></div>
<?php endif; ?>
<div><strong>Total Trips:</strong> <?= count($shipments) ?></div>
<div><strong><?= e(t('total_trips')) ?>:</strong> <?= count($shipments) ?></div>
<div class="fs-5 fw-bold text-primary mt-1">
<?= number_format($totalEarnings, 2) ?> OMR
<?= format_currency($totalEarnings) ?>
</div>
</div>
</div>
@ -218,18 +218,18 @@ render_header(t('truck_owners_statements') ?: 'Truck Owner Statements', 'reports
<!-- Table -->
<div class="table-responsive">
<table class="table table-bordered align-middle">
<thead class="table-light">
<thead>
<tr>
<th>Date <br> <span class="fw-normal text-muted">التاريخ</span></th>
<th>Ref # <br> <span class="fw-normal text-muted">رقم الشحنة</span></th>
<th>Route <br> <span class="fw-normal text-muted">المسار</span></th>
<th>Status <br> <span class="fw-normal text-muted">الحالة</span></th>
<th class="text-end">Earnings (OMR) <br> <span class="fw-normal text-muted">المبلغ</span></th>
<th><?= e(t('route')) ?> <br> <span class="fw-normal text-muted">المسار</span></th>
<th><?= e(t('status')) ?> <br> <span class="fw-normal text-muted">الحالة</span></th>
<th class="text-end"><?= e(t('earnings')) ?> <br> <span class="fw-normal text-muted">المبلغ</span></th>
</tr>
</thead>
<tbody>
<?php if (empty($shipments)): ?>
<tr><td colspan="5" class="text-center py-4 text-muted">No completed shipments found for this period.</td></tr>
<tr><td colspan="5" class="text-center py-4 text-muted"><?= e(t('no_completed_shipments')) ?></td></tr>
<?php else: ?>
<?php foreach ($shipments as $row): ?>
<tr>
@ -240,10 +240,10 @@ render_header(t('truck_owners_statements') ?: 'Truck Owner Statements', 'reports
<div class="small text-muted"><?= e($row['cargo_description']) ?></div>
</td>
<td>
<?= e(ucfirst(str_replace('_', ' ', $row['status']))) ?>
<?= e(status_label($row['status'])) ?>
</td>
<td class="text-end fw-bold">
<?= number_format((float)$row['offer_price'], 2) ?>
<?= format_currency((float)$row['offer_price']) ?>
</td>
</tr>
<?php endforeach; ?>
@ -251,8 +251,8 @@ render_header(t('truck_owners_statements') ?: 'Truck Owner Statements', 'reports
</tbody>
<tfoot>
<tr class="total-row table-active">
<td colspan="4" class="text-end text-uppercase">Total Earnings / الإجمالي</td>
<td class="text-end text-dark"><?= number_format($totalEarnings, 2) ?> OMR</td>
<td colspan="4" class="text-end text-uppercase"><?= e(t('total_earnings')) ?> / الإجمالي</td>
<td class="text-end text-dark"><?= format_currency($totalEarnings) ?></td>
</tr>
</tfoot>
</table>
@ -262,12 +262,12 @@ render_header(t('truck_owners_statements') ?: 'Truck Owner Statements', 'reports
<div class="print-footer">
<div class="row">
<div class="col-6 text-start">
Authorized Signature<br>
<?= e(t('authorized_signature')) ?><br>
_______________________
</div>
<div class="col-6 text-end">
Printed on <?= date('Y-m-d H:i') ?><br>
This is a computer-generated document.
<?= e(t('printed_on')) ?> <?= date('Y-m-d H:i') ?><br>
<?= e(t('generated_doc')) ?>
</div>
</div>
</div>
@ -283,7 +283,7 @@ render_header(t('truck_owners_statements') ?: 'Truck Owner Statements', 'reports
$(document).ready(function() {
$('#ownerSelect').select2({
width: '100%',
placeholder: '-- Choose a Truck Owner --',
placeholder: '<?= e(t('choose_truck_owner')) ?>',
allowClear: true
});
});

View File

@ -8,7 +8,7 @@ $isAjax = isset($_GET['ajax']) && $_GET['ajax'] === '1';
if (!$id) {
if ($isAjax) {
echo json_encode(['success' => false, 'message' => 'Invalid ID']);
echo json_encode(['success' => false, 'message' => t('invalid_id')]);
exit;
}
header('Location: admin_shipments.php'); exit;
@ -23,7 +23,7 @@ $shipment = $stmt->fetch();
if (!$shipment) {
if ($isAjax) {
echo json_encode(['success' => false, 'message' => 'Shipment not found']);
echo json_encode(['success' => false, 'message' => t('shipment_not_found')]);
exit;
}
header('Location: admin_shipments.php'); exit;
@ -76,9 +76,9 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$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 ($shipper_name === '') $errors[] = t('error_required');
if ($origin_city === '') $errors[] = t('error_required');
if ($destination_city === '') $errors[] = t('error_required');
if (empty($errors)) {
$updateSql = "
@ -93,7 +93,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$cargo_description, $weight_tons, $pickup_date, $delivery_date,
$payment_method, $status, $id
]);
$flash = "Shipment updated successfully.";
$flash = t('shipment_updated_success');
if ($isAjax) {
header('Content-Type: application/json');
@ -133,7 +133,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// -- OUTPUT START --
if (!$isAjax):
render_header('Edit Shipment', 'admin', true);
render_header(t('edit_shipment_tooltip'), 'admin', true);
?>
<div class="row g-0">
@ -142,14 +142,14 @@ if (!$isAjax):
</div>
<div class="col-md-10 p-4">
<div class="d-flex align-items-center gap-3 mb-4">
<a href="admin_shipments.php" class="btn btn-light border text-secondary" title="Back">
<a href="admin_shipments.php" class="btn btn-light border text-secondary" title="<?= t('back') ?>">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-left" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M15 8a.5.5 0 0 0-.5-.5H2.707l3.147-3.146a.5.5 0 1 0-.708-.708l-4 4a.5.5 0 0 0 0 .708l4 4a.5.5 0 0 0 .708-.708L2.707 8.5H14.5A.5.5 0 0 0 15 8z"/>
</svg>
</a>
<div>
<h1 class="section-title mb-1">Edit Shipment #<?= e((string)$shipment['id']) ?></h1>
<p class="muted mb-0">Update shipment details and status.</p>
<h1 class="section-title mb-1"><?= t('edit_shipment_title') ?><?= e((string)$shipment['id']) ?></h1>
<p class="muted mb-0"><?= t('update_shipment_details') ?></p>
</div>
</div>
@ -168,14 +168,14 @@ if (!$isAjax):
<?php endif; ?>
<div class="panel">
<div class="panel-heading">Shipment Details</div>
<div class="panel-heading"><?= t('shipment_details') ?></div>
<div class="p-4">
<?php endif; // End non-ajax wrapper ?>
<form method="post" action="admin_shipment_edit.php?id=<?= $id ?><?= $isAjax ? '&ajax=1' : '' ?>" class="ajax-form">
<?php if ($isAjax): ?>
<div class="modal-header">
<h5 class="modal-title">Edit Shipment #<?= e((string)$shipment['id']) ?></h5>
<h5 class="modal-title"><?= t('edit_shipment_title') ?><?= e((string)$shipment['id']) ?></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
@ -184,19 +184,19 @@ if (!$isAjax):
<div class="row g-3">
<div class="col-md-6">
<label class="form-label">Shipper Name</label>
<label class="form-label"><?= t('shipper_name') ?></label>
<input type="text" name="shipper_name" class="form-control" value="<?= e($shipment['shipper_name']) ?>" required>
</div>
<div class="col-md-6">
<label class="form-label">Shipper Company</label>
<label class="form-label"><?= t('shipper_company') ?></label>
<input type="text" name="shipper_company" class="form-control" value="<?= e((string)$shipment['shipper_company']) ?>">
</div>
<!-- Origin Selection -->
<div class="col-md-6">
<label class="form-label">Origin Country</label>
<label class="form-label"><?= t('origin_country') ?></label>
<select class="form-select" id="origin_country">
<option value="">Select Country</option>
<option value=""><?= t('select_country_placeholder') ?></option>
<?php foreach ($countries as $c): ?>
<option value="<?= e($c['id']) ?>" <?= $c['id'] == $origin_country_id ? 'selected' : '' ?>>
<?= e($c['name_en']) ?>
@ -205,9 +205,9 @@ if (!$isAjax):
</select>
</div>
<div class="col-md-6">
<label class="form-label">Origin City</label>
<label class="form-label"><?= t('origin') ?></label>
<select class="form-select" name="origin_city" id="origin_city" required>
<option value="">Select City</option>
<option value=""><?= t('select_city_placeholder') ?></option>
<!-- If shipment has a city but we couldn't match a country, preserve the value as a fallback option -->
<?php if (!$origin_country_id && $shipment['origin_city']): ?>
<option value="<?= e($shipment['origin_city']) ?>" selected><?= e($shipment['origin_city']) ?></option>
@ -223,9 +223,9 @@ if (!$isAjax):
<!-- Destination Selection -->
<div class="col-md-6">
<label class="form-label">Destination Country</label>
<label class="form-label"><?= t('destination_country') ?></label>
<select class="form-select" id="destination_country">
<option value="">Select Country</option>
<option value=""><?= t('select_country_placeholder') ?></option>
<?php foreach ($countries as $c): ?>
<option value="<?= e($c['id']) ?>" <?= $c['id'] == $destination_country_id ? 'selected' : '' ?>>
<?= e($c['name_en']) ?>
@ -234,9 +234,9 @@ if (!$isAjax):
</select>
</div>
<div class="col-md-6">
<label class="form-label">Destination City</label>
<label class="form-label"><?= t('destination') ?></label>
<select class="form-select" name="destination_city" id="destination_city" required>
<option value="">Select City</option>
<option value=""><?= t('select_city_placeholder') ?></option>
<!-- Fallback for unmapped city -->
<?php if (!$destination_country_id && $shipment['destination_city']): ?>
<option value="<?= e($shipment['destination_city']) ?>" selected><?= e($shipment['destination_city']) ?></option>
@ -251,38 +251,38 @@ if (!$isAjax):
</div>
<div class="col-md-12">
<label class="form-label">Cargo Description</label>
<label class="form-label"><?= t('cargo') ?></label>
<input type="text" name="cargo_description" class="form-control" value="<?= e((string)$shipment['cargo_description']) ?>">
</div>
<div class="col-md-4">
<label class="form-label">Weight (Tons)</label>
<label class="form-label"><?= t('weight') ?></label>
<input type="number" step="0.1" name="weight_tons" class="form-control" value="<?= e((string)$shipment['weight_tons']) ?>">
</div>
<div class="col-md-4">
<label class="form-label">Pickup Date</label>
<label class="form-label"><?= t('pickup_date') ?></label>
<input type="date" name="pickup_date" class="form-control" value="<?= e((string)$shipment['pickup_date']) ?>">
</div>
<div class="col-md-4">
<label class="form-label">Delivery Date</label>
<label class="form-label"><?= t('delivery_date') ?></label>
<input type="date" name="delivery_date" class="form-control" value="<?= e((string)$shipment['delivery_date']) ?>">
</div>
<div class="col-md-6">
<label class="form-label">Payment Method</label>
<label class="form-label"><?= t('payment_method') ?></label>
<select name="payment_method" class="form-select">
<option value="thawani" <?= $shipment['payment_method'] === 'thawani' ? 'selected' : '' ?>>Thawani</option>
<option value="bank_transfer" <?= $shipment['payment_method'] === 'bank_transfer' ? 'selected' : '' ?>>Bank Transfer</option>
<option value="thawani" <?= $shipment['payment_method'] === 'thawani' ? 'selected' : '' ?>><?= t('payment_thawani') ?></option>
<option value="bank_transfer" <?= $shipment['payment_method'] === 'bank_transfer' ? 'selected' : '' ?>><?= t('payment_bank') ?></option>
</select>
</div>
<div class="col-md-6">
<label class="form-label">Status</label>
<label class="form-label"><?= t('status') ?></label>
<select name="status" class="form-select">
<option value="posted" <?= $shipment['status'] === 'posted' ? 'selected' : '' ?>>Posted</option>
<option value="offered" <?= $shipment['status'] === 'offered' ? 'selected' : '' ?>>Offered</option>
<option value="confirmed" <?= $shipment['status'] === 'confirmed' ? 'selected' : '' ?>>Confirmed</option>
<option value="in_transit" <?= $shipment['status'] === 'in_transit' ? 'selected' : '' ?>>In Transit</option>
<option value="delivered" <?= $shipment['status'] === 'delivered' ? 'selected' : '' ?>>Delivered</option>
<option value="posted" <?= $shipment['status'] === 'posted' ? 'selected' : '' ?>><?= t('status_posted') ?></option>
<option value="offered" <?= $shipment['status'] === 'offered' ? 'selected' : '' ?>><?= t('status_offered') ?></option>
<option value="confirmed" <?= $shipment['status'] === 'confirmed' ? 'selected' : '' ?>><?= t('status_confirmed') ?></option>
<option value="in_transit" <?= $shipment['status'] === 'in_transit' ? 'selected' : '' ?>><?= t('status_in_transit') ?></option>
<option value="delivered" <?= $shipment['status'] === 'delivered' ? 'selected' : '' ?>><?= t('status_delivered') ?></option>
</select>
</div>
</div>
@ -290,12 +290,12 @@ if (!$isAjax):
<?php if ($isAjax): ?>
</div> <!-- modal-body end -->
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-primary">Save Changes</button>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><?= t('cancel') ?></button>
<button type="submit" class="btn btn-primary"><?= t('save_changes') ?></button>
</div>
<?php else: ?>
<div class="mt-4 pt-3 border-top d-flex justify-content-end">
<button type="submit" class="btn btn-primary">Save Changes</button>
<button type="submit" class="btn btn-primary"><?= t('save_changes') ?></button>
</div>
<?php endif; ?>
</form>
@ -317,14 +317,14 @@ if (!$isAjax):
countrySelect.addEventListener('change', function() {
const countryId = this.value;
citySelect.innerHTML = '<option value="">Loading...</option>';
citySelect.innerHTML = '<option value=""><?= t('loading_cities') ?></option>';
citySelect.disabled = true;
if (countryId) {
fetch('api/get_cities.php?country_id=' + countryId)
.then(response => response.json())
.then(data => {
citySelect.innerHTML = '<option value="">Select City</option>';
citySelect.innerHTML = '<option value=""><?= t('select_city_placeholder') ?></option>';
data.forEach(city => {
const option = document.createElement('option');
option.value = city.name_en; // Using name as value for DB compatibility
@ -335,10 +335,10 @@ if (!$isAjax):
})
.catch(error => {
console.error('Error fetching cities:', error);
citySelect.innerHTML = '<option value="">Error loading cities</option>';
citySelect.innerHTML = '<option value=""><?= t('error_loading_cities') ?></option>';
});
} else {
citySelect.innerHTML = '<option value="">Select City</option>';
citySelect.innerHTML = '<option value=""><?= t('select_city_placeholder') ?></option>';
citySelect.disabled = true;
}
});

View File

@ -13,7 +13,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'], $_POST['shi
if ($action === 'delete') {
db()->prepare("DELETE FROM shipments WHERE id = ?")->execute([$shipmentId]);
$flash = 'Shipment deleted successfully.';
$flash = t('flash_shipment_deleted');
}
}
@ -66,7 +66,7 @@ $stmt = db()->prepare($sql);
$stmt->execute($params);
$shipments = $stmt->fetchAll();
render_header('Manage Shipments', 'admin', true);
render_header(t('manage_shipments'), 'admin', true);
?>
<div class="row g-0">
@ -76,8 +76,8 @@ render_header('Manage Shipments', 'admin', true);
<div class="col-md-10 p-4">
<div class="page-intro d-flex flex-column flex-md-row justify-content-between align-items-md-center mb-4">
<div>
<h1 class="section-title mb-1">Shipments</h1>
<p class="muted mb-0">Manage all shipments across the platform.</p>
<h1 class="section-title mb-1"><?= t('shipments_header') ?></h1>
<p class="muted mb-0"><?= t('shipments_subtitle') ?></p>
</div>
</div>
@ -88,51 +88,51 @@ render_header('Manage Shipments', 'admin', true);
<div class="panel p-4 mb-4">
<form method="get" class="row g-3">
<div class="col-md-5">
<label class="form-label small text-muted">Search</label>
<input type="text" name="q" class="form-control" placeholder="Search shipments..." value="<?= e($q) ?>">
<label class="form-label small text-muted"><?= t('search_label') ?></label>
<input type="text" name="q" class="form-control" placeholder="<?= t('search_shipments_placeholder') ?>" value="<?= e($q) ?>">
</div>
<div class="col-md-3">
<label class="form-label small text-muted">Status</label>
<label class="form-label small text-muted"><?= t('status') ?></label>
<select name="status" class="form-select">
<option value="">All Statuses</option>
<option value="posted" <?= $status === 'posted' ? 'selected' : '' ?>>Posted</option>
<option value="offered" <?= $status === 'offered' ? 'selected' : '' ?>>Offered</option>
<option value="confirmed" <?= $status === 'confirmed' ? 'selected' : '' ?>>Confirmed</option>
<option value="in_transit" <?= $status === 'in_transit' ? 'selected' : '' ?>>In Transit</option>
<option value="delivered" <?= $status === 'delivered' ? 'selected' : '' ?>>Delivered</option>
<option value=""><?= t('all_statuses') ?></option>
<option value="posted" <?= $status === 'posted' ? 'selected' : '' ?>><?= t('status_posted') ?></option>
<option value="offered" <?= $status === 'offered' ? 'selected' : '' ?>><?= t('status_offered') ?></option>
<option value="confirmed" <?= $status === 'confirmed' ? 'selected' : '' ?>><?= t('status_confirmed') ?></option>
<option value="in_transit" <?= $status === 'in_transit' ? 'selected' : '' ?>><?= t('status_in_transit') ?></option>
<option value="delivered" <?= $status === 'delivered' ? 'selected' : '' ?>><?= t('status_delivered') ?></option>
</select>
</div>
<div class="col-md-3">
<label class="form-label small text-muted">Sort By</label>
<label class="form-label small text-muted"><?= t('sort_by') ?></label>
<select name="sort" class="form-select">
<option value="newest" <?= $sort === 'newest' ? 'selected' : '' ?>>Newest First</option>
<option value="oldest" <?= $sort === 'oldest' ? 'selected' : '' ?>>Oldest First</option>
<option value="pickup_asc" <?= $sort === 'pickup_asc' ? 'selected' : '' ?>>Pickup Date (Soonest)</option>
<option value="pickup_desc" <?= $sort === 'pickup_desc' ? 'selected' : '' ?>>Pickup Date (Latest)</option>
<option value="newest" <?= $sort === 'newest' ? 'selected' : '' ?>><?= t('sort_newest') ?></option>
<option value="oldest" <?= $sort === 'oldest' ? 'selected' : '' ?>><?= t('sort_oldest') ?></option>
<option value="pickup_asc" <?= $sort === 'pickup_asc' ? 'selected' : '' ?>><?= t('sort_pickup_soonest') ?></option>
<option value="pickup_desc" <?= $sort === 'pickup_desc' ? 'selected' : '' ?>><?= t('sort_pickup_latest') ?></option>
</select>
</div>
<div class="col-md-1 d-flex align-items-end">
<button type="submit" class="btn btn-primary w-100">Filter</button>
<button type="submit" class="btn btn-primary w-100"><?= t('filter') ?></button>
</div>
</form>
</div>
<div class="panel p-0">
<?php if (!$shipments && ($q || $status)): ?>
<div class="p-4"><p class="muted mb-0">No shipments found matching your criteria.</p></div>
<div class="p-4"><p class="muted mb-0"><?= t('no_shipments_found_criteria') ?></p></div>
<?php elseif (!$shipments): ?>
<div class="p-4"><p class="muted mb-0">No shipments found on the platform yet.</p></div>
<div class="p-4"><p class="muted mb-0"><?= t('no_shipments_platform') ?></p></div>
<?php else: ?>
<div class="table-responsive">
<table class="table mb-0 align-middle table-hover">
<thead class="table-light">
<thead>
<tr>
<th class="ps-4">ID</th>
<th>Shipper</th>
<th>Route</th>
<th>Dates</th>
<th>Status</th>
<th class="text-end pe-4">Action</th>
<th class="ps-4"><?= t('id_col') ?></th>
<th><?= t('shipper') ?></th>
<th><?= t('route_label') ?></th>
<th><?= t('dates_col') ?></th>
<th><?= t('status') ?></th>
<th class="text-end pe-4"><?= t('action') ?></th>
</tr>
</thead>
<tbody>
@ -144,12 +144,12 @@ render_header('Manage Shipments', 'admin', true);
<div class="text-muted small"><?= e((string)$shipment['shipper_company']) ?></div>
</td>
<td>
<div><span class="text-muted small">From:</span> <?= e($shipment['origin_city']) ?></div>
<div><span class="text-muted small">To:</span> <?= e($shipment['destination_city']) ?></div>
<div><span class="text-muted small"><?= t('from_label') ?></span> <?= e($shipment['origin_city']) ?></div>
<div><span class="text-muted small"><?= t('to_label') ?></span> <?= e($shipment['destination_city']) ?></div>
</td>
<td>
<div class="small"><span class="text-muted">Pick:</span> <?= e($shipment['pickup_date']) ?></div>
<div class="small"><span class="text-muted">Drop:</span> <?= e($shipment['delivery_date']) ?></div>
<div class="small"><span class="text-muted"><?= t('pick_label') ?></span> <?= e($shipment['pickup_date']) ?></div>
<div class="small"><span class="text-muted"><?= t('drop_label') ?></span> <?= e($shipment['delivery_date']) ?></div>
</td>
<td>
<?php
@ -160,23 +160,23 @@ render_header('Manage Shipments', 'admin', true);
elseif ($shipment['status'] === 'in_transit') $statusClass = 'bg-warning-subtle text-warning';
elseif ($shipment['status'] === 'delivered') $statusClass = 'bg-dark-subtle text-dark';
?>
<span class="badge <?= $statusClass ?>"><?= e(ucfirst(str_replace('_', ' ', $shipment['status']))) ?></span>
<span class="badge <?= $statusClass ?>"><?= e(status_label($shipment['status'])) ?></span>
</td>
<td class="text-end pe-4">
<div class="d-inline-flex gap-1 align-items-center">
<a href="shipment_detail.php?id=<?= e((string)$shipment['id']) ?>" class="btn btn-sm p-1 border-0 bg-transparent text-primary" title="View Shipment">
<a href="shipment_detail.php?id=<?= e((string)$shipment['id']) ?>" class="btn btn-sm p-1 border-0 bg-transparent text-primary" title="<?= t('view_shipment') ?>">
<i class="bi bi-eye"></i>
</a>
<a href="admin_shipment_edit.php?id=<?= e((string)$shipment['id']) ?>"
class="btn btn-sm p-1 border-0 bg-transparent text-primary ajax-modal-trigger"
data-bs-toggle="modal"
data-bs-target="#editModal"
title="Edit Shipment">
title="<?= t('edit_shipment_tooltip') ?>">
<i class="bi bi-pencil"></i>
</a>
<form method="post" class="d-inline m-0 p-0">
<input type="hidden" name="shipment_id" value="<?= e((string)$shipment['id']) ?>">
<button type="submit" name="action" value="delete" class="btn btn-sm p-1 border-0 bg-transparent text-danger" onclick="return confirm('Delete this shipment?');" title="Delete">
<button type="submit" name="action" value="delete" class="btn btn-sm p-1 border-0 bg-transparent text-danger" onclick="return confirm('<?= t('confirm_delete_shipment') ?>');" title="<?= t('delete') ?>">
<i class="bi bi-trash"></i>
</button>
</form>
@ -190,10 +190,10 @@ render_header('Manage Shipments', 'admin', true);
<?php if ($totalPages > 1): ?>
<div class="px-4 py-3 border-top d-flex justify-content-between align-items-center">
<span class="text-muted small">Showing <?= count($shipments) ?> of <?= $total ?> shipments</span>
<span class="text-muted small"><?= t('showing') ?> <?= count($shipments) ?> <?= t('of') ?> <?= $total ?> <?= t('shipments_header') ?></span>
<ul class="pagination pagination-sm mb-0">
<li class="page-item <?= $page <= 1 ? 'disabled' : '' ?>">
<a class="page-link" href="?q=<?= urlencode($q) ?>&status=<?= urlencode($status) ?>&sort=<?= urlencode($sort) ?>&page=<?= $page - 1 ?>">Previous</a>
<a class="page-link" href="?q=<?= urlencode($q) ?>&status=<?= urlencode($status) ?>&sort=<?= urlencode($sort) ?>&page=<?= $page - 1 ?>"><?= t('previous') ?></a>
</li>
<?php for ($i = 1; $i <= $totalPages; $i++): ?>
<li class="page-item <?= $i === $page ? 'active' : '' ?>">
@ -201,7 +201,7 @@ render_header('Manage Shipments', 'admin', true);
</li>
<?php endfor; ?>
<li class="page-item <?= $page >= $totalPages ? 'disabled' : '' ?>">
<a class="page-link" href="?q=<?= urlencode($q) ?>&status=<?= urlencode($status) ?>&sort=<?= urlencode($sort) ?>&page=<?= $page + 1 ?>">Next</a>
<a class="page-link" href="?q=<?= urlencode($q) ?>&status=<?= urlencode($status) ?>&sort=<?= urlencode($sort) ?>&page=<?= $page + 1 ?>"><?= t('next') ?></a>
</li>
</ul>
</div>
@ -216,12 +216,12 @@ render_header('Manage Shipments', 'admin', true);
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="editModalLabel">Edit</h5>
<h5 class="modal-title" id="editModalLabel"><?= t('edit_shipment_tooltip') ?></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body text-center p-5">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading...</span>
<span class="visually-hidden"><?= t('loading') ?></span>
</div>
</div>
</div>
@ -242,7 +242,7 @@ document.addEventListener('DOMContentLoaded', function() {
modalContent.innerHTML = `
<div class="modal-header">
<h5 class="modal-title">Loading...</h5>
<h5 class="modal-title"><?= t('loading') ?></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body text-center p-5">
@ -275,7 +275,7 @@ document.addEventListener('DOMContentLoaded', function() {
const submitBtn = form.querySelector('button[type="submit"]');
if(submitBtn) {
submitBtn.disabled = true;
submitBtn.innerHTML = '<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> Saving...';
submitBtn.innerHTML = '<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> Loading...';
}
const formData = new FormData(form);
@ -287,14 +287,14 @@ document.addEventListener('DOMContentLoaded', function() {
} else {
if(submitBtn) {
submitBtn.disabled = false;
submitBtn.textContent = 'Save Changes';
submitBtn.textContent = '<?= t('save_changes') ?>';
}
const errDiv = form.querySelector('#form-errors');
if(errDiv) {
errDiv.classList.remove('d-none');
errDiv.innerHTML = data.message;
} else {
alert(data.message || 'An error occurred');
alert(data.message || '<?= t('error_occurred') ?>');
}
}
})
@ -302,15 +302,15 @@ document.addEventListener('DOMContentLoaded', function() {
console.error(err);
if(submitBtn) {
submitBtn.disabled = false;
submitBtn.textContent = 'Save Changes';
submitBtn.textContent = '<?= t('save_changes') ?>';
}
alert('An error occurred while saving.');
alert('<?= t('error_occurred') ?>');
});
});
}
})
.catch(err => {
modalContent.innerHTML = `<div class="modal-body text-danger">Failed to load form.</div>`;
modalContent.innerHTML = `<div class="modal-body text-danger"><?= t('failed_load_form') ?></div>`;
});
});
});

View File

@ -83,7 +83,7 @@ $stmt = db()->prepare($sql);
$stmt->execute($params);
$shippers = $stmt->fetchAll();
render_header('Manage Shippers', 'admin', true);
render_header(t('manage_shippers'), 'admin', true);
?>
<div class="row g-0">
@ -93,8 +93,8 @@ render_header('Manage Shippers', 'admin', true);
<div class="col-md-10 p-4">
<div class="page-intro d-flex flex-column flex-md-row justify-content-between align-items-md-center mb-4">
<div>
<h1 class="section-title mb-1">Shippers</h1>
<p class="muted mb-0">Manage registered shippers.</p>
<h1 class="section-title mb-1"><?= e(t('shippers')) ?></h1>
<p class="muted mb-0"><?= e(t('manage_registered_shippers')) ?></p>
</div>
</div>
@ -105,40 +105,40 @@ render_header('Manage Shippers', 'admin', true);
<div class="panel p-4 mb-4">
<form method="get" class="row g-3">
<div class="col-md-8">
<label class="form-label small text-muted">Search</label>
<input type="text" name="q" class="form-control" placeholder="Search name, email, company..." value="<?= e($q) ?>">
<label class="form-label small text-muted"><?= e(t('search_placeholder_shipper')) ?></label>
<input type="text" name="q" class="form-control" placeholder="<?= e(t('search_placeholder_shipper')) ?>" value="<?= e($q) ?>">
</div>
<div class="col-md-3">
<label class="form-label small text-muted">Status</label>
<label class="form-label small text-muted"><?= e(t('status')) ?></label>
<select name="status" class="form-select">
<option value="">All Statuses</option>
<option value="active" <?= $status === 'active' ? 'selected' : '' ?>>Active</option>
<option value="pending" <?= $status === 'pending' ? 'selected' : '' ?>>Pending</option>
<option value="rejected" <?= $status === 'rejected' ? 'selected' : '' ?>>Rejected</option>
<option value=""><?= e(t('all_statuses')) ?></option>
<option value="active" <?= $status === 'active' ? 'selected' : '' ?>><?= e(t('active')) ?></option>
<option value="pending" <?= $status === 'pending' ? 'selected' : '' ?>><?= e(t('pending')) ?></option>
<option value="rejected" <?= $status === 'rejected' ? 'selected' : '' ?>><?= e(t('rejected')) ?></option>
</select>
</div>
<div class="col-md-1 d-flex align-items-end">
<button type="submit" class="btn btn-primary w-100">Filter</button>
<button type="submit" class="btn btn-primary w-100"><?= e(t('filter')) ?></button>
</div>
</form>
</div>
<div class="panel p-0">
<?php if (!$shippers && ($q || $status)): ?>
<div class="p-4"><p class="muted mb-0">No shippers found matching your criteria.</p></div>
<div class="p-4"><p class="muted mb-0"><?= e(t('no_shippers_criteria')) ?></p></div>
<?php elseif (!$shippers): ?>
<div class="p-4"><p class="muted mb-0">No shippers registered yet.</p></div>
<div class="p-4"><p class="muted mb-0"><?= e(t('no_shippers_registered')) ?></p></div>
<?php else: ?>
<div class="table-responsive">
<table class="table mb-0 align-middle table-hover">
<thead class="table-light">
<thead>
<tr>
<th class="ps-4">ID</th>
<th>Name / Company</th>
<th>Contact</th>
<th>Location</th>
<th>Status</th>
<th class="text-end pe-4">Action</th>
<th><?= e(t('name_company')) ?></th>
<th><?= e(t('contact')) ?></th>
<th><?= e(t('location')) ?></th>
<th><?= e(t('status')) ?></th>
<th class="text-end pe-4"><?= e(t('action')) ?></th>
</tr>
</thead>
<tbody>
@ -158,9 +158,9 @@ render_header('Manage Shippers', 'admin', true);
</td>
<td>
<?php if ($shipper['status'] === 'active'): ?>
<span class="badge bg-success-subtle text-success">Active</span>
<span class="badge bg-success-subtle text-success"><?= e(t('active')) ?></span>
<?php elseif ($shipper['status'] === 'pending'): ?>
<span class="badge bg-warning-subtle text-warning">Pending</span>
<span class="badge bg-warning-subtle text-warning"><?= e(t('pending')) ?></span>
<?php else: ?>
<span class="badge bg-danger-subtle text-danger"><?= e(ucfirst($shipper['status'] ?? 'unknown')) ?></span>
<?php endif; ?>
@ -171,22 +171,22 @@ render_header('Manage Shippers', 'admin', true);
class="btn btn-sm p-1 border-0 bg-transparent text-primary ajax-modal-trigger"
data-bs-toggle="modal"
data-bs-target="#editModal"
title="Edit Shipper">
title="<?= e(t('edit_shipper')) ?>">
<i class="bi bi-pencil"></i>
</a>
<form method="post" class="d-inline m-0 p-0">
<input type="hidden" name="user_id" value="<?= e((string)$shipper['id']) ?>">
<?php if ($shipper['status'] !== 'active'): ?>
<button type="submit" name="action" value="approve" class="btn btn-sm p-1 border-0 bg-transparent text-success" title="Approve">
<button type="submit" name="action" value="approve" class="btn btn-sm p-1 border-0 bg-transparent text-success" title="<?= e(t('approve')) ?>">
<i class="bi bi-check-lg"></i>
</button>
<?php endif; ?>
<?php if ($shipper['status'] !== 'rejected'): ?>
<button type="submit" name="action" value="reject" class="btn btn-sm p-1 border-0 bg-transparent text-warning" title="Reject">
<button type="submit" name="action" value="reject" class="btn btn-sm p-1 border-0 bg-transparent text-warning" title="<?= e(t('reject')) ?>">
<i class="bi bi-x-lg"></i>
</button>
<?php endif; ?>
<button type="submit" name="action" value="delete" class="btn btn-sm p-1 border-0 bg-transparent text-danger" onclick="return confirm('Delete this shipper forever?');" title="Delete">
<button type="submit" name="action" value="delete" class="btn btn-sm p-1 border-0 bg-transparent text-danger" onclick="return confirm('<?= e(t('delete_confirm_shipper')) ?>');" title="<?= e(t('delete')) ?>">
<i class="bi bi-trash"></i>
</button>
</form>
@ -200,7 +200,7 @@ render_header('Manage Shippers', 'admin', true);
<?php if ($totalPages > 1): ?>
<div class="px-4 py-3 border-top d-flex justify-content-between align-items-center">
<span class="text-muted small">Showing <?= count($shippers) ?> of <?= $total ?> shippers</span>
<span class="text-muted small"><?= e(t('shown')) ?> <?= count($shippers) ?> of <?= $total ?> <?= e(t('shippers')) ?></span>
<ul class="pagination pagination-sm mb-0">
<li class="page-item <?= $page <= 1 ? 'disabled' : '' ?>">
<a class="page-link" href="?q=<?= urlencode($q) ?>&status=<?= urlencode($status) ?>&page=<?= $page - 1 ?>">Previous</a>
@ -226,12 +226,12 @@ render_header('Manage Shippers', 'admin', true);
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="editModalLabel">Edit</h5>
<h5 class="modal-title" id="editModalLabel"><?= e(t('edit_shipper')) ?></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body text-center p-5">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading...</span>
<span class="visually-hidden"><?= e(t('loading')) ?></span>
</div>
</div>
</div>
@ -252,7 +252,7 @@ document.addEventListener('DOMContentLoaded', function() {
modalContent.innerHTML = `
<div class="modal-header">
<h5 class="modal-title">Loading...</h5>
<h5 class="modal-title"><?= e(t('loading')) ?></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body text-center p-5">
@ -285,7 +285,7 @@ document.addEventListener('DOMContentLoaded', function() {
const submitBtn = form.querySelector('button[type="submit"]');
if(submitBtn) {
submitBtn.disabled = true;
submitBtn.innerHTML = '<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> Saving...';
submitBtn.innerHTML = '<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> <?= e(t('loading')) ?>';
}
const formData = new FormData(form);
@ -297,7 +297,7 @@ document.addEventListener('DOMContentLoaded', function() {
} else {
if(submitBtn) {
submitBtn.disabled = false;
submitBtn.textContent = 'Save Changes';
submitBtn.textContent = '<?= e(t('save_changes')) ?>';
}
const errDiv = form.querySelector('#form-errors');
if(errDiv) {
@ -312,7 +312,7 @@ document.addEventListener('DOMContentLoaded', function() {
console.error(err);
if(submitBtn) {
submitBtn.disabled = false;
submitBtn.textContent = 'Save Changes';
submitBtn.textContent = '<?= e(t('save_changes')) ?>';
}
alert('An error occurred while saving.');
});

View File

@ -83,7 +83,7 @@ $stmt = db()->prepare($sql);
$stmt->execute($params);
$owners = $stmt->fetchAll();
render_header('Manage Truck Owners', 'admin', true);
render_header(t('manage_truck_owners'), 'admin', true);
?>
<div class="row g-0">
@ -93,8 +93,8 @@ render_header('Manage Truck Owners', 'admin', true);
<div class="col-md-10 p-4">
<div class="page-intro d-flex flex-column flex-md-row justify-content-between align-items-md-center mb-4">
<div>
<h1 class="section-title mb-1">Truck Owners</h1>
<p class="muted mb-0">Review registrations and approve truck owners.</p>
<h1 class="section-title mb-1"><?= e(t('truck_owners')) ?></h1>
<p class="muted mb-0"><?= e(t('review_registrations')) ?></p>
</div>
</div>
@ -105,40 +105,40 @@ render_header('Manage Truck Owners', 'admin', true);
<div class="panel p-4 mb-4">
<form method="get" class="row g-3">
<div class="col-md-8">
<label class="form-label small text-muted">Search</label>
<input type="text" name="q" class="form-control" placeholder="Search name, email, plate..." value="<?= e($q) ?>">
<label class="form-label small text-muted"><?= e(t('search_placeholder_owner')) ?></label>
<input type="text" name="q" class="form-control" placeholder="<?= e(t('search_placeholder_owner')) ?>" value="<?= e($q) ?>">
</div>
<div class="col-md-3">
<label class="form-label small text-muted">Status</label>
<label class="form-label small text-muted"><?= e(t('status')) ?></label>
<select name="status" class="form-select">
<option value="">All Statuses</option>
<option value="active" <?= $status === 'active' ? 'selected' : '' ?>>Active</option>
<option value="pending" <?= $status === 'pending' ? 'selected' : '' ?>>Pending</option>
<option value="rejected" <?= $status === 'rejected' ? 'selected' : '' ?>>Rejected</option>
<option value=""><?= e(t('all_statuses')) ?></option>
<option value="active" <?= $status === 'active' ? 'selected' : '' ?>><?= e(t('active')) ?></option>
<option value="pending" <?= $status === 'pending' ? 'selected' : '' ?>><?= e(t('pending')) ?></option>
<option value="rejected" <?= $status === 'rejected' ? 'selected' : '' ?>><?= e(t('rejected')) ?></option>
</select>
</div>
<div class="col-md-1 d-flex align-items-end">
<button type="submit" class="btn btn-primary w-100">Filter</button>
<button type="submit" class="btn btn-primary w-100"><?= e(t('filter')) ?></button>
</div>
</form>
</div>
<div class="panel p-0">
<?php if (!$owners && ($q || $status)): ?>
<div class="p-4"><p class="muted mb-0">No truck owners found matching your criteria.</p></div>
<div class="p-4"><p class="muted mb-0"><?= e(t('no_owners_criteria')) ?></p></div>
<?php elseif (!$owners): ?>
<div class="p-4"><p class="muted mb-0">No truck owners registered yet.</p></div>
<div class="p-4"><p class="muted mb-0"><?= e(t('no_owners_registered')) ?></p></div>
<?php else: ?>
<div class="table-responsive">
<table class="table mb-0 align-middle table-hover">
<thead class="table-light">
<thead>
<tr>
<th class="ps-4">ID</th>
<th>Name / Email</th>
<th>Truck Info</th>
<th>Documents</th>
<th>Status</th>
<th class="text-end pe-4">Action</th>
<th><?= e(t('name_email')) ?></th>
<th><?= e(t('truck_info')) ?></th>
<th><?= e(t('documents')) ?></th>
<th><?= e(t('status')) ?></th>
<th class="text-end pe-4"><?= e(t('action')) ?></th>
</tr>
</thead>
<tbody>
@ -151,9 +151,9 @@ render_header('Manage Truck Owners', 'admin', true);
<div class="text-muted small"><?= e((string)$owner['phone']) ?></div>
</td>
<td>
<div><strong>Type:</strong> <?= e((string)$owner['truck_type']) ?></div>
<div><strong>Cap:</strong> <?= e((string)$owner['load_capacity']) ?>t</div>
<div><strong>Plate:</strong> <?= e((string)$owner['plate_no']) ?></div>
<div><strong><?= e(t('truck_type')) ?>:</strong> <?= e((string)$owner['truck_type']) ?></div>
<div><strong><?= e(t('cap')) ?>:</strong> <?= e((string)$owner['load_capacity']) ?>t</div>
<div><strong><?= e(t('truck_plate')) ?>:</strong> <?= e((string)$owner['plate_no']) ?></div>
</td>
<td>
<button type="button" class="btn btn-sm btn-outline-secondary d-flex align-items-center gap-1" data-bs-toggle="modal" data-bs-target="#docsModal<?= $owner['id'] ?>">
@ -161,14 +161,14 @@ render_header('Manage Truck Owners', 'admin', true);
<path d="M5.5 7a.5.5 0 0 0 0 1h5a.5.5 0 0 0 0-1zM5 9.5a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5m0 2a.5.5 0 0 1 .5-.5h2a.5.5 0 0 1 0 1h-2a.5.5 0 0 1-.5-.5"/>
<path d="M9.5 0H4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V4.5zm0 1v2A1.5 1.5 0 0 0 11 4.5h2V14a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1z"/>
</svg>
View Docs
<?= e(t('view_docs')) ?>
</button>
</td>
<td>
<?php if ($owner['status'] === 'active'): ?>
<span class="badge bg-success-subtle text-success">Active</span>
<span class="badge bg-success-subtle text-success"><?= e(t('active')) ?></span>
<?php elseif ($owner['status'] === 'pending'): ?>
<span class="badge bg-warning-subtle text-warning">Pending</span>
<span class="badge bg-warning-subtle text-warning"><?= e(t('pending')) ?></span>
<?php else: ?>
<span class="badge bg-danger-subtle text-danger"><?= e(ucfirst($owner['status'] ?? 'unknown')) ?></span>
<?php endif; ?>
@ -179,22 +179,22 @@ render_header('Manage Truck Owners', 'admin', true);
class="btn btn-sm p-1 border-0 bg-transparent text-primary ajax-modal-trigger"
data-bs-toggle="modal"
data-bs-target="#editModal"
title="Edit Owner">
title="<?= e(t('edit_owner')) ?>">
<i class="bi bi-pencil"></i>
</a>
<form method="post" class="d-inline m-0 p-0">
<input type="hidden" name="user_id" value="<?= e((string)$owner['id']) ?>">
<?php if ($owner['status'] !== 'active'): ?>
<button type="submit" name="action" value="approve" class="btn btn-sm p-1 border-0 bg-transparent text-success" title="Approve">
<button type="submit" name="action" value="approve" class="btn btn-sm p-1 border-0 bg-transparent text-success" title="<?= e(t('approve')) ?>">
<i class="bi bi-check-lg"></i>
</button>
<?php endif; ?>
<?php if ($owner['status'] !== 'rejected'): ?>
<button type="submit" name="action" value="reject" class="btn btn-sm p-1 border-0 bg-transparent text-warning" title="Reject">
<button type="submit" name="action" value="reject" class="btn btn-sm p-1 border-0 bg-transparent text-warning" title="<?= e(t('reject')) ?>">
<i class="bi bi-x-lg"></i>
</button>
<?php endif; ?>
<button type="submit" name="action" value="delete" class="btn btn-sm p-1 border-0 bg-transparent text-danger" onclick="return confirm('Delete this truck owner forever?');" title="Delete">
<button type="submit" name="action" value="delete" class="btn btn-sm p-1 border-0 bg-transparent text-danger" onclick="return confirm('<?= e(t('delete_confirm_owner')) ?>');" title="<?= e(t('delete')) ?>">
<i class="bi bi-trash"></i>
</button>
</form>
@ -208,7 +208,7 @@ render_header('Manage Truck Owners', 'admin', true);
<?php if ($totalPages > 1): ?>
<div class="px-4 py-3 border-top d-flex justify-content-between align-items-center">
<span class="text-muted small">Showing <?= count($owners) ?> of <?= $total ?> truck owners</span>
<span class="text-muted small"><?= e(t('shown')) ?> <?= count($owners) ?> of <?= $total ?> <?= e(t('truck_owners')) ?></span>
<ul class="pagination pagination-sm mb-0">
<li class="page-item <?= $page <= 1 ? 'disabled' : '' ?>">
<a class="page-link" href="?q=<?= urlencode($q) ?>&status=<?= urlencode($status) ?>&page=<?= $page - 1 ?>">Previous</a>
@ -234,12 +234,12 @@ render_header('Manage Truck Owners', 'admin', true);
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="editModalLabel">Edit</h5>
<h5 class="modal-title" id="editModalLabel"><?= e(t('edit_owner')) ?></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body text-center p-5">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading...</span>
<span class="visually-hidden"><?= e(t('loading')) ?></span>
</div>
</div>
</div>
@ -256,11 +256,11 @@ $pic = $owner['truck_pic_path'];
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Documents for <?= e($owner['full_name']) ?></h5>
<h5 class="modal-title"><?= e(t('docs_for')) ?> <?= e($owner['full_name']) ?></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<h6>ID Card</h6>
<h6><?= e(t('id_card_front')) ?> / <?= e(t('id_card_back')) ?></h6>
<div class="d-flex gap-2 mb-3 overflow-auto">
<?php foreach ($idCards as $path): ?>
<a href="<?= e('/' . $path) ?>" target="_blank">
@ -269,7 +269,7 @@ $pic = $owner['truck_pic_path'];
<?php endforeach; ?>
</div>
<h6>Truck Registration</h6>
<h6><?= e(t('truck_reg')) ?></h6>
<div class="d-flex gap-2 mb-3 overflow-auto">
<?php foreach ($regs as $path): ?>
<a href="<?= e('/' . $path) ?>" target="_blank">
@ -278,7 +278,7 @@ $pic = $owner['truck_pic_path'];
<?php endforeach; ?>
</div>
<h6>Truck Picture</h6>
<h6><?= e(t('truck_picture')) ?></h6>
<?php if ($pic): ?>
<div>
<a href="<?= e('/' . $pic) ?>" target="_blank">
@ -286,7 +286,7 @@ $pic = $owner['truck_pic_path'];
</a>
</div>
<?php else: ?>
<span class="text-muted">No picture uploaded.</span>
<span class="text-muted"><?= e(t('no_picture')) ?></span>
<?php endif; ?>
</div>
<div class="modal-footer">
@ -312,7 +312,7 @@ document.addEventListener('DOMContentLoaded', function() {
// Reset to loading state
modalContent.innerHTML = `
<div class="modal-header">
<h5 class="modal-title">Loading...</h5>
<h5 class="modal-title"><?= e(t('loading')) ?></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body text-center p-5">
@ -357,7 +357,7 @@ document.addEventListener('DOMContentLoaded', function() {
const submitBtn = form.querySelector('button[type="submit"]');
if(submitBtn) {
submitBtn.disabled = true;
submitBtn.innerHTML = '<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> Saving...';
submitBtn.innerHTML = '<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> <?= e(t('loading')) ?>';
}
const formData = new FormData(form);
@ -370,7 +370,7 @@ document.addEventListener('DOMContentLoaded', function() {
} else {
if(submitBtn) {
submitBtn.disabled = false;
submitBtn.textContent = 'Save Changes';
submitBtn.textContent = '<?= e(t('save_changes')) ?>';
}
const errDiv = form.querySelector('#form-errors');
if(errDiv) {
@ -385,7 +385,7 @@ document.addEventListener('DOMContentLoaded', function() {
console.error(err);
if(submitBtn) {
submitBtn.disabled = false;
submitBtn.textContent = 'Save Changes';
submitBtn.textContent = '<?= e(t('save_changes')) ?>';
}
alert('An error occurred while saving.');
});

View File

@ -311,6 +311,11 @@ body.app-body {
border-top-right-radius: 8px;
}
/* Fix text-muted in table headers */
.table thead th .text-muted {
color: var(--sidebar-muted) !important;
}
.table tbody td {
vertical-align: middle;
padding: 16px 8px;
@ -537,3 +542,124 @@ body.app-body {
min-height: 100vh;
}
}
/* Global Print Styles */
@media print {
/* Hide browser-added headers/footers (title, date, URL) */
@page {
margin-top: 1cm;
margin-bottom: 1cm;
size: auto;
}
/* Kill standard href expansion */
a[href]:after {
content: none !important;
}
body, [data-theme="dark"] body.app-body {
background: #ffffff !important;
color: #000000 !important;
/* Padding to emulate margin if @page fails */
margin: 0 !important;
}
/* Hide Sidebar, Nav, and Standard Footer */
.admin-sidebar,
.navbar,
.btn,
form,
.no-print,
footer {
display: none !important;
}
/* Expand main content */
.col-md-10, .col-lg-10, .col-xl-10 {
width: 100% !important;
flex: 0 0 100% !important;
max-width: 100% !important;
padding: 0 !important;
margin: 0 !important;
}
/* Reset Panels/Cards for print */
.panel, .card {
border: none !important;
box-shadow: none !important;
background: #ffffff !important;
}
/* Table Adjustments */
.table {
width: 100% !important;
color: #000000 !important;
}
.table thead th {
background-color: #f8f9fa !important;
color: #000000 !important;
border-bottom: 2px solid #000000 !important;
text-shadow: none !important;
}
/* Ensure muted text in headers is visible (dark gray/black) */
.table thead th .text-muted {
color: #333333 !important;
}
.table tbody td {
border-bottom: 1px solid #dee2e6 !important;
color: #000000 !important;
}
/* Typography Overrides */
h1, h2, h3, h4, h5, h6, p, span, div, td, th {
color: #000000 !important;
}
.text-muted {
color: #555555 !important;
}
.text-white {
color: #000000 !important;
}
/* Badges to outlines */
.badge {
border: 1px solid #000 !important;
background: transparent !important;
color: #000 !important;
}
a {
text-decoration: none !important;
color: #000 !important;
}
/* Ensure visibility utilities work in print */
.d-print-block {
display: block !important;
}
.d-print-none {
display: none !important;
}
.print-no-shadow {
box-shadow: none !important;
border: none !important;
}
/* Sticky Footer */
.print-footer {
position: fixed;
bottom: 0;
left: 0;
right: 0;
width: 100%;
background: white;
padding: 10px 0;
border-top: 1px solid #000 !important;
z-index: 999;
}
}

View File

@ -122,91 +122,82 @@ $translations = [
'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',
'nav_platform_users' => 'Platform Users',
'notification_templates' => 'Notification Templates',
'manage_permissions' => 'Manage Permissions',
'create_user' => 'Create User',
'edit_user' => 'Edit User',
'delete_user' => 'Delete User',
'confirm_delete' => 'Are you sure you want to delete this user?',
'permissions' => 'Permissions',
'no_users' => 'No platform users found.',
'user_created' => 'User created successfully.',
'user_updated' => 'User updated successfully.',
'user_deleted' => 'User deleted successfully.',
'error_email_exists' => 'Email already exists.',
'shipper_shipments' => 'Shipper Shipments',
'truck_owners_statements' => 'Truck Owner Statements'
'edit_homepage' => 'Edit homepage content and sections',
'view_details' => 'View Details',
'manage_shippers' => 'Manage Shippers',
'manage_registered_shippers' => 'Manage registered shippers.',
'search_placeholder_shipper' => 'Search name, email, company...',
'all_statuses' => 'All Statuses',
'pending' => 'Pending',
'rejected' => 'Rejected',
'active' => 'Active',
'no_shippers_criteria' => 'No shippers found matching your criteria.',
'no_shippers_registered' => 'No shippers registered yet.',
'name_company' => 'Name / Company',
'location' => 'Location',
'edit_shipper' => 'Edit Shipper',
'approve' => 'Approve',
'reject' => 'Reject',
'delete' => 'Delete',
'delete_confirm_shipper' => 'Delete this shipper forever?',
'loading' => 'Loading...',
'manage_truck_owners' => 'Manage Truck Owners',
'review_registrations' => 'Review registrations and approve truck owners.',
'search_placeholder_owner' => 'Search name, email, plate...',
'no_owners_criteria' => 'No truck owners found matching your criteria.',
'no_owners_registered' => 'No truck owners registered yet.',
'name_email' => 'Name / Email',
'truck_info' => 'Truck Info',
'documents' => 'Documents',
'view_docs' => 'View Docs',
'edit_owner' => 'Edit Owner',
'delete_confirm_owner' => 'Delete this truck owner forever?',
'docs_for' => 'Documents for',
'truck_reg' => 'Truck Registration',
'no_picture' => 'No picture uploaded.',
'cap' => 'Cap',
'manage_shipments' => 'Manage Shipments',
'shipments_header' => 'Shipments',
'shipments_subtitle' => 'Manage all shipments across the platform.',
'flash_shipment_deleted' => 'Shipment deleted successfully.',
'search_shipments_placeholder' => 'Search shipments...',
'search_label' => 'Search',
'sort_by' => 'Sort By',
'sort_newest' => 'Newest First',
'sort_oldest' => 'Oldest First',
'sort_pickup_soonest' => 'Pickup Date (Soonest)',
'sort_pickup_latest' => 'Pickup Date (Latest)',
'no_shipments_found_criteria' => 'No shipments found matching your criteria.',
'no_shipments_platform' => 'No shipments found on the platform yet.',
'id_col' => 'ID',
'dates_col' => 'Dates',
'from_label' => 'From:',
'to_label' => 'To:',
'pick_label' => 'Pick:',
'drop_label' => 'Drop:',
'view_shipment' => 'View Shipment',
'edit_shipment_tooltip' => 'Edit Shipment',
'confirm_delete_shipment' => 'Delete this shipment?',
'showing' => 'Showing',
'of' => 'of',
'previous' => 'Previous',
'next' => 'Next',
'error_occurred' => 'An error occurred',
'failed_load_form' => 'Failed to load form.',
'edit_shipment_title' => 'Edit Shipment #',
'update_shipment_details' => 'Update shipment details and status.',
'shipment_not_found' => 'Shipment not found',
'shipment_updated_success' => 'Shipment updated successfully.',
'invalid_id' => 'Invalid ID',
'back' => 'Back',
'shipment_details' => 'Shipment Details',
'origin_country' => 'Origin Country',
'destination_country' => 'Destination Country',
'select_country_placeholder' => 'Select Country',
'select_city_placeholder' => 'Select City',
'loading_cities' => 'Loading...',
'error_loading_cities' => 'Error loading cities',
'cancel' => 'Cancel'
),
"ar" => array (
'app_name' => 'CargoLink',
@ -317,91 +308,82 @@ $translations = [
'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' => 'الشحنات الفائزة',
'nav_platform_users' => 'مستخدمو المنصة',
'notification_templates' => 'قوالب الإشعارات',
'manage_permissions' => 'إدارة الصلاحيات',
'create_user' => 'إنشاء مستخدم',
'edit_user' => 'تعديل المستخدم',
'delete_user' => 'حذف المستخدم',
'confirm_delete' => 'هل أنت متأكد أنك تريد حذف هذا المستخدم؟',
'permissions' => 'الصلاحيات',
'no_users' => 'لم يتم العثور على مستخدمين.',
'user_created' => 'تم إنشاء المستخدم بنجاح.',
'user_updated' => 'تم تحديث المستخدم بنجاح.',
'user_deleted' => 'تم حذف المستخدم بنجاح.',
'error_email_exists' => 'البريد الإلكتروني موجود بالفعل.',
'shipper_shipments' => 'شحنات الشاحنين',
'truck_owners_statements' => 'كشوفات أصحاب الشاحنات'
'edit_homepage' => 'تعديل محتوى الصفحة الرئيسية والأقسام',
'view_details' => 'عرض التفاصيل',
'manage_shippers' => 'إدارة الشاحنين',
'manage_registered_shippers' => 'إدارة الشاحنين المسجلين.',
'search_placeholder_shipper' => 'ابحث بالاسم، البريد، الشركة...',
'all_statuses' => 'كل الحالات',
'pending' => 'قيد الانتظار',
'rejected' => 'مرفوض',
'active' => 'نشط',
'no_shippers_criteria' => 'لم يتم العثور على شاحنين مطابقين لمعاييرك.',
'no_shippers_registered' => 'لا يوجد شاحنين مسجلين بعد.',
'name_company' => 'الاسم / الشركة',
'location' => 'الموقع',
'edit_shipper' => 'تعديل الشاحن',
'approve' => 'موافقة',
'reject' => 'رفض',
'delete' => 'حذف',
'delete_confirm_shipper' => 'هل أنت متأكد من حذف هذا الشاحن نهائياً؟',
'loading' => 'جاري التحميل...',
'manage_truck_owners' => 'إدارة أصحاب الشاحنات',
'review_registrations' => 'مراجعة التسجيلات والموافقة على أصحاب الشاحنات.',
'search_placeholder_owner' => 'ابحث بالاسم، البريد، اللوحة...',
'no_owners_criteria' => 'لم يتم العثور على أصحاب شاحنات مطابقين لمعاييرك.',
'no_owners_registered' => 'لا يوجد أصحاب شاحنات مسجلين بعد.',
'name_email' => 'الاسم / البريد',
'truck_info' => 'معلومات الشاحنة',
'documents' => 'المستندات',
'view_docs' => 'عرض المستندات',
'edit_owner' => 'تعديل المالك',
'delete_confirm_owner' => 'هل أنت متأكد من حذف مالك الشاحنة هذا نهائياً؟',
'docs_for' => 'مستندات',
'truck_reg' => 'تسجيل الشاحنة',
'no_picture' => 'لا توجد صورة محملة.',
'cap' => 'السعة',
'manage_shipments' => 'إدارة الشحنات',
'shipments_header' => 'الشحنات',
'shipments_subtitle' => 'إدارة جميع الشحنات عبر المنصة.',
'flash_shipment_deleted' => 'تم حذف الشحنة بنجاح.',
'search_shipments_placeholder' => 'البحث في الشحنات...',
'search_label' => 'بحث',
'sort_by' => 'ترتيب حسب',
'sort_newest' => 'الأحدث أولاً',
'sort_oldest' => 'الأقدم أولاً',
'sort_pickup_soonest' => 'تاريخ الاستلام (الأقرب)',
'sort_pickup_latest' => 'تاريخ الاستلام (الأبعد)',
'no_shipments_found_criteria' => 'لم يتم العثور على شحنات مطابقة لمعايير البحث.',
'no_shipments_platform' => 'لا توجد شحنات على المنصة بعد.',
'id_col' => 'المعرف',
'dates_col' => 'التواريخ',
'from_label' => 'من:',
'to_label' => 'إلى:',
'pick_label' => 'استلام:',
'drop_label' => 'تسليم:',
'view_shipment' => 'عرض الشحنة',
'edit_shipment_tooltip' => 'تعديل الشحنة',
'confirm_delete_shipment' => 'حذف هذه الشحنة؟',
'showing' => 'عرض',
'of' => 'من',
'previous' => 'السابق',
'next' => 'التالي',
'error_occurred' => 'حدث خطأ',
'failed_load_form' => 'فشل تحميل النموذج.',
'edit_shipment_title' => 'تعديل الشحنة #',
'update_shipment_details' => 'تحديث تفاصيل الشحنة والحالة.',
'shipment_not_found' => 'الشحنة غير موجودة',
'shipment_updated_success' => 'تم تحديث الشحنة بنجاح.',
'invalid_id' => 'معرف غير صحيح',
'back' => 'رجوع',
'shipment_details' => 'تفاصيل الشحنة',
'origin_country' => 'بلد الانطلاق',
'destination_country' => 'بلد الوصول',
'select_country_placeholder' => 'اختر البلد',
'select_city_placeholder' => 'اختر المدينة',
'loading_cities' => 'جاري التحميل...',
'error_loading_cities' => 'خطأ في تحميل المدن',
'cancel' => 'إلغاء'
)
];
@ -610,4 +592,9 @@ function has_permission(string $permissionSlug, ?int $userId = null): bool
} catch (Throwable $e) {
return false;
}
}
}
function format_currency(float $amount): string
{
return number_format($amount, 3) . ' OMR';
}

View File

@ -259,23 +259,23 @@ function render_admin_sidebar(string $active = 'dashboard'): void
<i class="bi bi-speedometer2 me-2"></i><?= e(t('dashboard')) ?>
</a>
<a class="admin-nav-link <?= $active === 'shipments' ? 'active' : '' ?>" href="<?= e(url_with_lang('admin_shipments.php')) ?>">
<i class="bi bi-box2-fill me-2"></i><?= e(t('shipments') ?: 'Shipments') ?>
<i class="bi bi-box2-fill me-2"></i><?= e(t('shipments')) ?>
</a>
<a class="nav-link fw-bold text-muted text-uppercase mt-2 d-flex justify-content-between align-items-center p-2 rounded" style="cursor: pointer; font-size: 0.85rem;" data-bs-toggle="collapse" data-bs-target="#collapseReports" aria-expanded="<?= $reportsActive ? 'true' : 'false' ?>">
<span><i class="bi bi-file-earmark-bar-graph-fill me-2"></i><?= e(t('reports') ?: 'Reports') ?></span>
<span><i class="bi bi-file-earmark-bar-graph-fill me-2"></i><?= e(t('reports')) ?></span>
<i class="bi bi-chevron-down small"></i>
</a>
<div class="collapse <?= $reportsActive ? 'show' : '' ?>" id="collapseReports">
<div class="nav flex-column gap-1 ms-3 border-start ps-2 border-2">
<a class="admin-nav-link <?= $active === 'reports_summary' ? 'active' : '' ?>" href="<?= e(url_with_lang('admin_reports_summary.php')) ?>">
<i class="bi bi-pie-chart-fill me-2"></i>Analytics
<i class="bi bi-pie-chart-fill me-2"></i><?= e(t('analytics')) ?>
</a>
<a class="admin-nav-link <?= $active === 'reports_shippers' ? 'active' : '' ?>" href="<?= e(url_with_lang('admin_reports_shippers.php')) ?>">
<i class="bi bi-people me-2"></i><?= e(t('shipper_shipments') ?: 'Shipper Shipments') ?>
<i class="bi bi-people me-2"></i><?= e(t('shipper_shipments')) ?>
</a>
<a class="admin-nav-link <?= $active === 'reports_truck_owners' ? 'active' : '' ?>" href="<?= e(url_with_lang('admin_reports_truck_owners.php')) ?>">
<i class="bi bi-truck me-2"></i><?= e(t('truck_owners_statements') ?: 'Truck Owner Statements') ?>
<i class="bi bi-truck me-2"></i><?= e(t('truck_owners_statements')) ?>
</a>
</div>
</div>
@ -293,7 +293,7 @@ function render_admin_sidebar(string $active = 'dashboard'): void
<i class="bi bi-plug me-2"></i><?= e(t('integrations')) ?>
</a>
<a class="admin-nav-link <?= $active === 'notification_templates' ? 'active' : '' ?>" href="<?= e(url_with_lang('admin_notification_templates.php')) ?>">
<i class="bi bi-bell-fill me-2"></i><?= e(t('notification_templates') ?: 'Notifications') ?>
<i class="bi bi-bell-fill me-2"></i><?= e(t('notification_templates')) ?>
</a>
</div>
</div>

View File

@ -204,7 +204,7 @@ render_header(t('shipment_detail'));
<i class="bi bi-check-circle-fill fs-4 me-2"></i>
<div>
<strong>Payment Complete</strong><br>
Total Paid: $<?= e($shipment['total_price']) ?> (Includes $<?= e($shipment['platform_fee']) ?> platform fee)
Total Paid: <?= format_currency((float)$shipment['total_price']) ?> (Includes <?= format_currency((float)$shipment['platform_fee']) ?> platform fee)
</div>
</div>
</div>
@ -248,16 +248,16 @@ render_header(t('shipment_detail'));
<h5 class="card-title fw-bold mb-3">Payment Breakdown</h5>
<div class="d-flex justify-content-between mb-2">
<span class="text-muted">Truck Offer</span>
<span class="fw-medium">$<?= number_format($offerPrice, 2) ?></span>
<span class="fw-medium"><?= format_currency($offerPrice) ?></span>
</div>
<div class="d-flex justify-content-between mb-3">
<span class="text-muted">Platform Fee (<?= e($platformFeePercentage * 100) ?>%)</span>
<span class="fw-medium">$<?= number_format($fee, 2) ?></span>
<span class="fw-medium"><?= format_currency($fee) ?></span>
</div>
<hr>
<div class="d-flex justify-content-between align-items-center">
<span class="fw-bold fs-5">Total</span>
<span class="fw-bold fs-4 text-primary">$<?= number_format($total, 2) ?></span>
<span class="fw-bold fs-4 text-primary"><?= format_currency($total) ?></span>
</div>
</div>
</div>