updating shipments fee

This commit is contained in:
Flatlogic Bot 2026-03-24 06:27:15 +00:00
parent c1349af904
commit c51c984fbc
10 changed files with 331 additions and 80 deletions

View File

@ -14,6 +14,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { validate_csrf_token();
$companyPhone = trim($_POST['company_phone'] ?? '');
$companyAddress = trim($_POST['company_address'] ?? '');
$platformCharge = trim($_POST['platform_charge_percentage'] ?? '0');
$pricingModel = trim($_POST['pricing_model'] ?? 'percentage');
$timezone = trim($_POST['timezone'] ?? 'UTC');
$updates = [
@ -22,6 +23,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { validate_csrf_token();
'company_phone' => $companyPhone,
'company_address' => $companyAddress,
'platform_charge_percentage' => $platformCharge,
'pricing_model' => $pricingModel,
'timezone' => $timezone,
'terms_en' => trim($_POST['terms_en'] ?? ''),
'terms_ar' => trim($_POST['terms_ar'] ?? ''),
@ -82,6 +84,7 @@ $currentEmail = $settings['company_email'] ?? '';
$currentPhone = $settings['company_phone'] ?? '';
$currentAddress = $settings['company_address'] ?? '';
$currentPlatformCharge = $settings['platform_charge_percentage'] ?? '0';
$currentPricingModel = $settings['pricing_model'] ?? 'percentage';
$currentTimezone = $settings['timezone'] ?? 'UTC';
$currentLogo = $settings['logo_path'] ?? '';
$currentFavicon = $settings['favicon_path'] ?? '';
@ -156,6 +159,26 @@ render_header('Company Profile', 'admin', true);
<input type="text" name="company_address" class="form-control" value="<?= e($currentAddress) ?>">
<div class="form-text">Displayed in the footer.</div>
</div>
<div class="col-md-12">
<label class="form-label fw-bold">Pricing Model</label>
<div class="card p-3 bg-light border-0">
<div class="form-check mb-2">
<input class="form-check-input" type="radio" name="pricing_model" id="model_percentage" value="percentage" <?= $currentPricingModel === 'percentage' ? 'checked' : '' ?>>
<label class="form-check-label" for="model_percentage">
<strong>Percentage Fee Model</strong> (Default)<br>
<span class="text-muted small">Shipper posts details. Truck Owners make offers. Platform adds fee on top of offer.</span>
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="pricing_model" id="model_fixed" value="fixed_price" <?= $currentPricingModel === 'fixed_price' ? 'checked' : '' ?>>
<label class="form-check-label" for="model_fixed">
<strong>Shipper Offer & Confirmation</strong><br>
<span class="text-muted small">Shipper sets price. Admin confirms. Truck Owner accepts fixed price.</span>
</label>
</div>
</div>
</div>
<div class="col-md-6">
<label class="form-label fw-bold">Platform Charge (%)</label>
@ -163,7 +186,7 @@ render_header('Company Profile', 'admin', true);
<input type="number" step="0.01" min="0" max="100" name="platform_charge_percentage" class="form-control" value="<?= e($currentPlatformCharge) ?>">
<span class="input-group-text">%</span>
</div>
<div class="form-text">Percentage applied as a platform fee.</div>
<div class="form-text">Percentage applied as a platform fee (only for Percentage Model).</div>
</div>
<div class="col-md-6">

View File

@ -145,7 +145,7 @@ if (!$isAjax):
<div class="d-flex align-items-center gap-3 mb-4">
<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"/>
<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 .708l4 4a.5.5 0 0 0 .708-.708L2.707 8.5H14.5A.5.5 0 0 0 15 8z"/>
</svg>
</a>
<div>
@ -289,6 +289,7 @@ if (!$isAjax):
<div class="col-md-6">
<label class="form-label"><?= t('status') ?></label>
<select name="status" class="form-select">
<option value="pending_approval" <?= $shipment['status'] === 'pending_approval' ? 'selected' : '' ?>><?= t('status_pending_approval') ?></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>

View File

@ -6,7 +6,7 @@ require_once __DIR__ . '/includes/layout.php'; require_role('admin');
$errors = [];
$flash = null;
// Handle action (Delete)
// Handle action (Delete / Approve)
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'], $_POST['shipment_id'])) {
$shipmentId = (int)$_POST['shipment_id'];
$action = $_POST['action'];
@ -14,6 +14,9 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'], $_POST['shi
if ($action === 'delete') {
db()->prepare("DELETE FROM shipments WHERE id = ?")->execute([$shipmentId]);
$flash = t('flash_shipment_deleted');
} elseif ($action === 'approve') {
db()->prepare("UPDATE shipments SET status = 'posted' WHERE id = ?")->execute([$shipmentId]);
$flash = t('success_status');
}
}
@ -34,7 +37,7 @@ if ($q !== '') {
$params = array_merge($params, array_fill(0, 5, $likeQ));
}
if ($status !== '' && in_array($status, ['posted', 'offered', 'confirmed', 'in_transit', 'delivered'])) {
if ($status !== '' && in_array($status, ['posted', 'offered', 'confirmed', 'in_transit', 'delivered', 'pending_approval'])) {
$whereClause .= " AND status = ?";
$params[] = $status;
}
@ -95,6 +98,7 @@ render_header(t('manage_shipments'), 'admin', true);
<label class="form-label small text-muted"><?= t('status') ?></label>
<select name="status" class="form-select">
<option value=""><?= t('all_statuses') ?></option>
<option value="pending_approval" <?= $status === 'pending_approval' ? 'selected' : '' ?>><?= t('status_pending_approval') ?></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>
@ -149,6 +153,9 @@ render_header(t('manage_shipments'), 'admin', true);
<?php if (!empty($shipment['shipment_type'])): ?>
<div class="mt-1"><span class="badge bg-light text-secondary border"><?= e(t('type_' . strtolower($shipment['shipment_type']))) ?></span></div>
<?php endif; ?>
<?php if (!empty($shipment['target_price'])): ?>
<div class="text-info small fw-bold mt-1"><?= t('target_price') ?>: $<?= e($shipment['target_price']) ?></div>
<?php endif; ?>
</td>
<td>
<div class="small"><span class="text-muted"><?= t('pick_label') ?></span> <?= e($shipment['pickup_date']) ?></div>
@ -162,11 +169,20 @@ render_header(t('manage_shipments'), 'admin', true);
elseif ($shipment['status'] === 'confirmed') $statusClass = 'bg-success-subtle text-success';
elseif ($shipment['status'] === 'in_transit') $statusClass = 'bg-warning-subtle text-warning';
elseif ($shipment['status'] === 'delivered') $statusClass = 'bg-dark-subtle text-dark';
elseif ($shipment['status'] === 'pending_approval') $statusClass = 'bg-warning text-dark';
?>
<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">
<?php if ($shipment['status'] === 'pending_approval'): ?>
<form method="post" class="d-inline m-0 p-0"> <?= csrf_field() ?>
<input type="hidden" name="shipment_id" value="<?= e((string)$shipment['id']) ?>">
<button type="submit" name="action" value="approve" class="btn btn-sm p-1 border-0 bg-transparent text-success" title="<?= t('approve') ?>">
<i class="bi bi-check-circle-fill"></i>
</button>
</form>
<?php endif; ?>
<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>

11
check_status_enum.php Normal file
View File

@ -0,0 +1,11 @@
<?php
require_once __DIR__ . '/db/config.php';
try {
$stmt = db()->query("SHOW COLUMNS FROM shipments LIKE 'status'");
$row = $stmt->fetch();
echo "Type: " . $row['Type'] . "\n";
} catch (Throwable $e) {
echo "Error: " . $e->getMessage() . "\n";
}

View File

@ -0,0 +1,13 @@
<?php
require_once __DIR__ . '/../config.php';
try {
echo "Adding 'pending_approval' to shipments status enum...\n";
// MariaDB/MySQL ALTER TABLE to modify column
$sql = "ALTER TABLE shipments MODIFY COLUMN status ENUM('pending_approval', 'posted','offered','confirmed','in_transit','delivered') NOT NULL DEFAULT 'posted'";
db()->exec($sql);
echo "Migration successful.\n";
} catch (PDOException $e) {
echo "Migration failed: " . $e->getMessage() . "\n";
}

View File

@ -0,0 +1,37 @@
<?php
require_once __DIR__ . '/../config.php';
$pdo = db();
try {
// Add target_price column to shipments if it doesn't exist
$pdo->exec("
SET @dbname = DATABASE();
SET @tablename = 'shipments';
SET @columnname = 'target_price';
SET @preparedStatement = (SELECT IF(
(
SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
WHERE
(table_name = @tablename)
AND (table_schema = @dbname)
AND (column_name = @columnname)
) > 0,
'SELECT 1',
'ALTER TABLE shipments ADD COLUMN target_price DECIMAL(10,2) DEFAULT NULL AFTER weight_tons'
));
PREPARE alterIfNotExists FROM @preparedStatement;
EXECUTE alterIfNotExists;
DEALLOCATE PREPARE alterIfNotExists;
");
echo "Added target_price column to shipments.\n";
// Insert default pricing_model setting
$pdo->exec("
INSERT IGNORE INTO settings (setting_key, setting_value) VALUES ('pricing_model', 'percentage');
");
echo "Added pricing_model setting.\n";
} catch (PDOException $e) {
echo "Error: " . $e->getMessage() . "\n";
}

View File

@ -282,7 +282,7 @@ $translations = [
'address' => 'Address',
'shipper_details' => 'Shipper Details',
'company_name' => 'Company Name',
'truck_details' => 'Truck Details',
'truck_details' => 'تفاصيل الشاحنة',
'truck_type' => 'Truck Type',
'load_capacity' => 'Load Capacity (Tons)',
'plate_no' => 'Plate Number',
@ -333,6 +333,9 @@ $translations = [
'type_frozen' => 'Frozen',
'type_cold' => 'Cold',
'type_dry' => 'Dry',
'target_price' => 'Target Price',
'status_pending_approval' => 'Pending Approval',
'pending_approval_msg' => 'Your shipment is pending admin approval.',
),
"ar" => array (
'app_name' => 'CargoLink',
@ -654,6 +657,9 @@ $translations = [
'type_frozen' => 'مجمد',
'type_cold' => 'مبرد',
'type_dry' => 'جاف',
'target_price' => 'السعر المستهدف',
'status_pending_approval' => 'بانتظار الموافقة',
'pending_approval_msg' => 'شحنتك بانتظار موافقة الإدارة.',
)
];
@ -806,6 +812,7 @@ function status_label(string $status): string
'confirmed' => t('status_confirmed'),
'in_transit' => t('status_in_transit'),
'delivered' => t('status_delivered'),
'pending_approval' => t('status_pending_approval'),
];
return $map[$status] ?? $status;
}
@ -916,4 +923,4 @@ try {
if ($tz && in_array($tz, DateTimeZone::listIdentifiers())) {
date_default_timezone_set($tz);
}
} catch (Throwable $e) {}
} catch (Throwable $e) {}

View File

@ -27,6 +27,7 @@ $isAssignedTruckOwner = $shipment && $shipment['truck_owner_id'] == $currentUser
// Platform Fee Configuration
$settings = get_settings();
$platformFeePercentage = (float)($settings['platform_charge_percentage'] ?? 0) / 100;
$pricingModel = $settings['pricing_model'] ?? 'percentage';
// Handle POST actions
if ($_SERVER['REQUEST_METHOD'] === 'POST') { validate_csrf_token();
@ -35,6 +36,12 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { validate_csrf_token();
if ($action === 'submit_offer') { if (!$isTruckOwner && !$isAdmin) { $errors[] = 'Only truck owners can submit offers.'; }
$offerOwner = trim($_POST['offer_owner'] ?? '');
$offerPrice = trim($_POST['offer_price'] ?? '');
// Enforce fixed price logic if applicable
if ($pricingModel === 'fixed_price' && !empty($shipment['target_price'])) {
$offerPrice = $shipment['target_price'];
}
if ($offerOwner === '' || $offerPrice === '') {
$errors[] = t('error_required');
} elseif (!is_numeric($offerPrice)) {
@ -196,7 +203,10 @@ render_header(t('shipment_detail'));
<h2 class="section-title mb-1"><?= e(t('shipment_detail')) ?> #<?= e($shipment['id']) ?></h2>
<p class="muted mb-0"><?= e(t('created_at')) ?>: <?= e($shipment['created_at']) ?></p>
</div>
<span class="badge-status <?= e($shipment['status']) ?>"><?= e(status_label($shipment['status'])) ?></span>
<?php
$statusBadgeClass = ($shipment['status'] === 'pending_approval') ? 'bg-warning text-dark' : $shipment['status'];
?>
<span class="badge-status <?= e($statusBadgeClass) ?>"><?= e(status_label($shipment['status'])) ?></span>
</div>
<div class="row g-3">
<div class="col-md-6">
@ -243,6 +253,14 @@ render_header(t('shipment_detail'));
<div class="small text-muted"><?= e(t('best_offer')) ?></div>
<div class="fw-semibold"><?= $shipment['offer_price'] ? e($shipment['offer_price'] . ' / ' . ($shipment['offer_owner'] ?? '')) : e(t('no_offers')) ?></div>
</div>
<?php if (!empty($shipment['target_price'])): ?>
<div class="col-md-6">
<div class="small text-muted"><?= e(t('target_price')) ?></div>
<div class="fw-semibold text-info">$<?= e($shipment['target_price']) ?></div>
</div>
<?php endif; ?>
<?php if ($shipment['payment_status'] === 'paid'): ?>
<div class="col-12">
<div class="alert alert-success d-flex align-items-center mb-0">
@ -329,6 +347,11 @@ render_header(t('shipment_detail'));
<i class="bi bi-hourglass-split fs-1 text-muted mb-3 d-block"></i>
<p class="mb-0 text-muted">Waiting for truck owners to submit offers.</p>
</div>
<?php elseif ($shipment['status'] === 'pending_approval'): ?>
<div class="text-center py-5">
<i class="bi bi-clipboard-check fs-1 text-warning mb-3 d-block"></i>
<p class="mb-0 text-muted"><?= t('pending_approval_msg') ?></p>
</div>
<?php elseif ($shipment['status'] === 'confirmed' || $shipment['status'] === 'in_transit' || $shipment['status'] === 'delivered'): ?>
<div class="text-center py-5">
<i class="bi bi-check-circle-fill fs-1 text-success mb-3 d-block"></i>
@ -373,15 +396,31 @@ render_header(t('shipment_detail'));
<label class="form-label"><?= e(t('offer_owner')) ?></label>
<input class="form-control" name="offer_owner" value="<?= e($shipment['offer_owner'] ?? '') ?>" required>
</div>
<div class="mb-3">
<label class="form-label"><?= e(t('offer_price')) ?></label>
<input class="form-control" name="offer_price" type="number" step="0.01" min="0.1" value="<?= e($shipment['offer_price'] ?? '') ?>" required>
</div>
<button class="btn btn-primary w-100" type="submit"><?= e(t('submit_offer')) ?></button>
<?php if ($pricingModel === 'fixed_price' && !empty($shipment['target_price'])): ?>
<div class="mb-3">
<label class="form-label"><?= e(t('target_price')) ?></label>
<div class="input-group">
<span class="input-group-text">$</span>
<input class="form-control bg-light" value="<?= e($shipment['target_price']) ?>" readonly>
<input type="hidden" name="offer_price" value="<?= e($shipment['target_price']) ?>">
</div>
<div class="form-text text-success fw-bold"><i class="bi bi-check-circle me-1"></i> Fixed Price Offer</div>
</div>
<button class="btn btn-success w-100 fw-bold shadow-sm" type="submit">
Accept Load ($<?= e($shipment['target_price']) ?>)
</button>
<?php else: ?>
<div class="mb-3">
<label class="form-label"><?= e(t('offer_price')) ?></label>
<input class="form-control" name="offer_price" type="number" step="0.01" min="0.1" value="<?= e($shipment['offer_price'] ?? '') ?>" required>
</div>
<button class="btn btn-primary w-100" type="submit"><?= e(t('submit_offer')) ?></button>
<?php endif; ?>
</form>
<?php else: ?>
<div class="alert alert-info">
This shipment is already confirmed/processed.
This shipment is already confirmed/processed or pending approval.
</div>
<?php endif; ?>

View File

@ -7,6 +7,8 @@ require_once __DIR__ . '/includes/NotificationService.php';
ensure_schema();
$errors = [];
$settings = get_settings();
$pricingModel = $settings['pricing_model'] ?? 'percentage';
// Try to pre-fill from profile if logged in
$prefillName = $_SESSION['shipper_name'] ?? '';
@ -34,19 +36,26 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'creat
$pickupDate = trim($_POST['pickup_date'] ?? '');
$deliveryDate = trim($_POST['delivery_date'] ?? '');
$payment = $_POST['payment_method'] ?? 'thawani';
$targetPrice = ($pricingModel === 'fixed_price') ? trim($_POST['target_price'] ?? '') : null;
$initialStatus = ($pricingModel === 'fixed_price') ? 'pending_approval' : 'posted';
if ($shipperName === '' || $shipperCompany === '' || $origin === '' || $destination === '' || $cargo === '' || $weight === '' || $pickupDate === '' || $deliveryDate === '') {
$errors[] = t('error_required');
} elseif (!is_numeric($weight)) {
$errors[] = t('error_invalid');
}
if ($pricingModel === 'fixed_price' && (!is_numeric($targetPrice) || $targetPrice <= 0)) {
$errors[] = t('error_invalid');
}
if (!$errors) {
$shipperId = isset($_SESSION['user_id']) ? (int)$_SESSION['user_id'] : null;
$stmt = db()->prepare(
"INSERT INTO shipments (shipper_id, shipper_name, shipper_company, origin_city, destination_city, shipment_type, cargo_description, weight_tons, pickup_date, delivery_date, payment_method)
VALUES (:shipper_id, :shipper_name, :shipper_company, :origin_city, :destination_city, :shipment_type, :cargo_description, :weight_tons, :pickup_date, :delivery_date, :payment_method)"
"INSERT INTO shipments (shipper_id, shipper_name, shipper_company, origin_city, destination_city, shipment_type, cargo_description, weight_tons, pickup_date, delivery_date, payment_method, status, target_price)
VALUES (:shipper_id, :shipper_name, :shipper_company, :origin_city, :destination_city, :shipment_type, :cargo_description, :weight_tons, :pickup_date, :delivery_date, :payment_method, :status, :target_price)"
);
$stmt->execute([
':shipper_id' => $shipperId,
@ -60,6 +69,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'creat
':pickup_date' => $pickupDate,
':delivery_date' => $deliveryDate,
':payment_method' => $payment,
':status' => $initialStatus,
':target_price' => $targetPrice,
]);
$newShipmentId = db()->lastInsertId();
@ -78,7 +89,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'creat
}
}
set_flash('success', t('success_shipment'));
$msg = ($initialStatus === 'pending_approval') ? t('pending_approval_msg') : t('success_shipment');
set_flash('success', $msg);
header('Location: ' . url_with_lang('shipper_dashboard.php'));
exit;
}
@ -107,9 +119,17 @@ $stats = [
try {
if ($filterCompany) {
$stats['total'] = (int)db()->prepare("SELECT COUNT(*) FROM shipments WHERE shipper_company = ?")->execute([$filterCompany]) ? (int)db()->query("SELECT COUNT(*) FROM shipments WHERE shipper_company = " . db()->quote($filterCompany))->fetchColumn() : 0;
$stats['active'] = (int)db()->query("SELECT COUNT(*) FROM shipments WHERE shipper_company = " . db()->quote($filterCompany) . " AND status != 'delivered'")->fetchColumn();
$stats['delivered'] = (int)db()->query("SELECT COUNT(*) FROM shipments WHERE shipper_company = " . db()->quote($filterCompany) . " AND status = 'delivered'")->fetchColumn();
$stmt = db()->prepare("SELECT COUNT(*) FROM shipments WHERE shipper_company = ?");
$stmt->execute([$filterCompany]);
$stats['total'] = (int)$stmt->fetchColumn();
$stmt = db()->prepare("SELECT COUNT(*) FROM shipments WHERE shipper_company = ? AND status != 'delivered'");
$stmt->execute([$filterCompany]);
$stats['active'] = (int)$stmt->fetchColumn();
$stmt = db()->prepare("SELECT COUNT(*) FROM shipments WHERE shipper_company = ? AND status = 'delivered'");
$stmt->execute([$filterCompany]);
$stats['delivered'] = (int)$stmt->fetchColumn();
} else {
$stats['total'] = (int)db()->query("SELECT COUNT(*) FROM shipments")->fetchColumn();
$stats['active'] = (int)db()->query("SELECT COUNT(*) FROM shipments WHERE status != 'delivered'")->fetchColumn();
@ -230,6 +250,17 @@ $flash = get_flash();
<label class="form-label text-muted small fw-bold"><?= e(t('cargo')) ?></label>
<input class="form-control" name="cargo_description" placeholder="<?= e(t('cargo_placeholder') ?? 'e.g. 20 Pallets of Electronics') ?>" required>
</div>
<?php if ($pricingModel === 'fixed_price'): ?>
<div class="mb-3">
<label class="form-label text-muted small fw-bold"><?= e(t('target_price')) ?></label>
<div class="input-group">
<span class="input-group-text">$</span>
<input class="form-control" name="target_price" type="number" step="0.01" min="0.1" required>
</div>
<div class="form-text small text-info"><i class="bi bi-info-circle me-1"></i><?= e(t('pending_approval_msg')) ?></div>
</div>
<?php endif; ?>
<div class="row g-3 mb-3">
<div class="col-md-6">
@ -296,8 +327,13 @@ $flash = get_flash();
<span class="badge bg-light text-secondary border"><?= e(t('type_' . strtolower($row['shipment_type']))) ?></span>
</div>
<?php endif; ?>
<?php if (!empty($row['target_price'])): ?>
<div class="text-xs text-info mt-1 fw-bold">
<?= e(t('target_price')) ?>: $<?= e($row['target_price']) ?>
</div>
<?php endif; ?>
</td>
<td><span class="badge <?= e($row['status']) ?> rounded-pill px-3 py-2"><?= e(status_label($row['status'])) ?></span></td>
<td><span class="badge <?= e($row['status'] === 'pending_approval' ? 'bg-warning text-dark' : $row['status']) ?> rounded-pill px-3 py-2"><?= e(status_label($row['status'])) ?></span></td>
<td>
<?php if ($row['offer_price']): ?>
<div class="fw-bold text-success">$<?= e($row['offer_price']) ?></div>

View File

@ -4,6 +4,8 @@ declare(strict_types=1);
require_once __DIR__ . '/includes/layout.php'; require_role('truck_owner');
$userId = $_SESSION['user_id'];
$settings = get_settings();
$pricingModel = $settings['pricing_model'] ?? 'percentage';
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'add_truck') {
$truckType = trim($_POST['truck_type'] ?? '');
@ -29,81 +31,147 @@ $trucks = db()->prepare("SELECT * FROM trucks WHERE user_id = ?");
$trucks->execute([$userId]);
$myTrucks = $trucks->fetchAll();
// Fetch Available Shipments
$availShipments = [];
try {
$stmt = db()->query("SELECT * FROM shipments WHERE status = 'posted' ORDER BY created_at DESC");
$availShipments = $stmt->fetchAll();
} catch (Throwable $e) {}
render_header('Truck Owner Dashboard', 'owner');
$flash = get_flash();
?>
<div class="page-intro mb-4">
<h1 class="section-title mb-1">Truck Owner Dashboard</h1>
<p class="muted mb-0">Manage your trucks and view their approval status.</p>
<p class="muted mb-0">Manage your trucks and view available shipments.</p>
</div>
<?php if ($flash): ?>
<div class="alert alert-<?= $flash['type'] ?>" data-auto-dismiss="true"><?= e($flash['message']) ?></div>
<?php endif; ?>
<div class="panel p-4 mb-4">
<h5 class="mb-3">Add New Truck</h5>
<form method="post" class="row g-3"> <?= csrf_field() ?>
<input type="hidden" name="action" value="add_truck">
<div class="col-md-2">
<input type="text" name="truck_type" class="form-control" placeholder="Truck Type" required>
<div class="row g-4">
<div class="col-lg-4">
<div class="panel p-4 mb-4">
<h5 class="mb-3">Add New Truck</h5>
<form method="post" class="row g-3"> <?= csrf_field() ?>
<input type="hidden" name="action" value="add_truck">
<div class="col-12">
<label class="form-label small text-muted">Truck Type</label>
<input type="text" name="truck_type" class="form-control" placeholder="e.g. Refrigerated" required>
</div>
<div class="col-6">
<label class="form-label small text-muted">Capacity (T)</label>
<input type="number" name="load_capacity" class="form-control" step="0.01" required>
</div>
<div class="col-6">
<label class="form-label small text-muted">Plate No</label>
<input type="text" name="plate_no" class="form-control" required>
</div>
<div class="col-6">
<label class="form-label small text-muted">Reg. Expiry</label>
<input type="date" name="registration_expiry_date" class="form-control" required>
</div>
<div class="col-6">
<label class="form-label small text-muted">Ins. Expiry</label>
<input type="date" name="insurance_expiry_date" class="form-control" required>
</div>
<div class="col-12 pt-2">
<button type="submit" class="btn btn-primary w-100">Add Truck</button>
</div>
</form>
</div>
<div class="col-md-2">
<input type="number" name="load_capacity" class="form-control" placeholder="Capacity (T)" step="0.01" required>
<div class="panel p-4">
<h5 class="mb-3">My Trucks</h5>
<?php if (!$myTrucks): ?>
<p class="text-muted small">No trucks registered yet.</p>
<?php else: ?>
<div class="list-group list-group-flush">
<?php foreach ($myTrucks as $truck): ?>
<?php
$isExpired = (strtotime($truck['registration_expiry_date']) < time()) || (strtotime($truck['insurance_expiry_date']) < time());
?>
<div class="list-group-item px-0 py-3">
<div class="d-flex justify-content-between align-items-center mb-1">
<strong class="text-dark"><?= e($truck['plate_no']) ?></strong>
<?php if ($isExpired): ?>
<span class="badge bg-danger">Expired</span>
<?php elseif ($truck['is_approved']): ?>
<span class="badge bg-success">Approved</span>
<?php else: ?>
<span class="badge bg-warning text-dark">Pending</span>
<?php endif; ?>
</div>
<div class="small text-muted"><?= e($truck['truck_type']) ?> • <?= e($truck['load_capacity']) ?> Tons</div>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
<div class="col-md-2">
<input type="text" name="plate_no" class="form-control" placeholder="Plate No" required>
</div>
<div class="col-lg-8">
<div class="panel p-4 h-100">
<h5 class="mb-3">Available Shipments</h5>
<?php if (!$availShipments): ?>
<div class="text-center p-5 text-muted">
<i class="bi bi-inbox fs-1 mb-3 d-block opacity-50"></i>
<p class="mb-0">No shipments available at the moment.</p>
</div>
<?php else: ?>
<div class="table-responsive">
<table class="table align-middle mb-0">
<thead>
<tr>
<th class="text-uppercase small text-muted border-top-0">Route</th>
<th class="text-uppercase small text-muted border-top-0">Details</th>
<th class="text-uppercase small text-muted border-top-0">Dates</th>
<th class="text-uppercase small text-muted border-top-0 text-end">Action</th>
</tr>
</thead>
<tbody>
<?php foreach ($availShipments as $row): ?>
<tr>
<td>
<div class="d-flex align-items-center gap-2">
<span class="fw-medium"><?= e($row['origin_city']) ?></span>
<i class="bi bi-arrow-right text-muted small"></i>
<span class="fw-medium"><?= e($row['destination_city']) ?></span>
</div>
<?php if (!empty($row['shipment_type'])): ?>
<div class="text-xs text-muted mt-1">
<span class="badge bg-light text-secondary border"><?= e(t('type_' . strtolower($row['shipment_type']))) ?></span>
</div>
<?php endif; ?>
<?php if (!empty($row['target_price'])): ?>
<div class="text-success small fw-bold mt-1">
Price: $<?= e($row['target_price']) ?>
</div>
<?php endif; ?>
</td>
<td>
<div class="small text-dark fw-bold"><?= e($row['cargo_description']) ?></div>
<div class="small text-muted"><?= e($row['weight_tons']) ?> Tons • <?= e($row['payment_method']) ?></div>
</td>
<td>
<div class="small"><span class="text-muted">Pick:</span> <?= e(date('M d', strtotime($row['pickup_date']))) ?></div>
<div class="small"><span class="text-muted">Drop:</span> <?= e(date('M d', strtotime($row['delivery_date']))) ?></div>
</td>
<td class="text-end">
<a href="<?= e(url_with_lang('shipment_detail.php', ['id' => $row['id']])) ?>" class="btn btn-sm btn-outline-primary rounded-pill px-3">
View
</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</div>
<div class="col-md-2">
<input type="date" name="registration_expiry_date" class="form-control" required title="Registration Expiry Date">
</div>
<div class="col-md-2">
<input type="date" name="insurance_expiry_date" class="form-control" required title="Insurance Expiry Date">
</div>
<div class="col-md-2">
<button type="submit" class="btn btn-primary w-100">Add Truck</button>
</div>
</form>
</div>
<div class="panel p-4">
<h5 class="mb-3">My Trucks</h5>
<table class="table table-bordered">
<thead>
<tr>
<th>Truck Type</th>
<th>Capacity (T)</th>
<th>Plate No</th>
<th>Reg Expiry</th>
<th>Ins Expiry</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<?php foreach ($myTrucks as $truck): ?>
<?php
$isExpired = (strtotime($truck['registration_expiry_date']) < time()) || (strtotime($truck['insurance_expiry_date']) < time());
?>
<tr class="<?= $isExpired ? 'table-danger' : '' ?>">
<td><?= e($truck['truck_type']) ?></td>
<td><?= e($truck['load_capacity']) ?></td>
<td><?= e($truck['plate_no']) ?></td>
<td><?= e($truck['registration_expiry_date']) ?></td>
<td><?= e($truck['insurance_expiry_date']) ?></td>
<td>
<?php if ($isExpired): ?>
<span class="badge bg-danger">Expired</span>
<?php elseif ($truck['is_approved']): ?>
<span class="badge bg-success">Approved</span>
<?php else: ?>
<span class="badge bg-warning text-dark">Pending</span>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<?php render_footer(); ?>