updating trucks registration

This commit is contained in:
Flatlogic Bot 2026-03-24 03:07:19 +00:00
parent e222bcb8eb
commit b587241984
4 changed files with 119 additions and 220 deletions

View File

@ -22,8 +22,8 @@ $flash = null;
$stmt = db()->prepare("
SELECT u.id, u.email, u.full_name, u.status, u.role,
p.phone, p.address_line, p.country_id, p.city_id,
p.truck_type, p.load_capacity, p.plate_no, p.bank_account, p.bank_name, p.bank_branch,
p.id_card_path, p.truck_pic_path, p.registration_path
p.bank_account, p.bank_name, p.bank_branch,
p.id_card_path, p.is_company
FROM users u
LEFT JOIN truck_owner_profiles p ON u.id = p.user_id
WHERE u.id = ? AND u.role = 'truck_owner'
@ -31,6 +31,10 @@ $stmt = db()->prepare("
$stmt->execute([$userId]);
$owner = $stmt->fetch();
$trucks = db()->prepare("SELECT * FROM trucks WHERE user_id = ?");
$trucks->execute([$userId]);
$ownerTrucks = $trucks->fetchAll();
if (!$owner) {
if ($isAjax) {
echo json_encode(['success' => false, 'message' => 'Owner not found']);
@ -50,36 +54,21 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { validate_csrf_token();
$countryId = (int)($_POST['country_id'] ?? 0);
$cityId = (int)($_POST['city_id'] ?? 0);
$addressLine = trim($_POST['address_line'] ?? '');
$truckType = trim($_POST['truck_type'] ?? '');
$loadCapacity = trim($_POST['load_capacity'] ?? '');
$plateNo = trim($_POST['plate_no'] ?? '');
$status = trim($_POST['status'] ?? '');
$password = $_POST['password'] ?? '';
$bankAccount = trim($_POST['bank_account'] ?? '');
$bankName = trim($_POST['bank_name'] ?? '');
$bankBranch = trim($_POST['bank_branch'] ?? '');
$isCompany = isset($_POST['is_company']) ? 1 : 0;
if ($fullName === '') $errors[] = 'Full name is required.';
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) $errors[] = 'Valid email is required.';
if ($phone === '') $errors[] = 'Phone number is required.';
if (!in_array($status, ['pending', 'active', 'rejected'], true)) $errors[] = 'Invalid status.';
if ($truckType === '' || $loadCapacity === '' || $plateNo === '') {
$errors[] = 'Truck type, load capacity, and plate number are required.';
} elseif (!is_numeric($loadCapacity) || (float)$loadCapacity <= 0) {
$errors[] = 'Load capacity must be a positive number.';
}
if ($countryId <= 0 || $cityId <= 0) {
$errors[] = 'Please select country and city.';
} else {
$cityCheck = db()->prepare("SELECT COUNT(*) FROM cities WHERE id = ? AND country_id = ?");
$cityCheck->execute([$cityId, $countryId]);
if ((int)$cityCheck->fetchColumn() === 0) {
$errors[] = 'Selected city does not belong to selected country.';
}
}
if (!$errors) {
@ -97,57 +86,21 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { validate_csrf_token();
$stmtProfile = db()->prepare("
UPDATE truck_owner_profiles
SET phone = ?, address_line = ?, country_id = ?, city_id = ?,
truck_type = ?, load_capacity = ?, plate_no = ?,
bank_account = ?, bank_name = ?, bank_branch = ?
bank_account = ?, bank_name = ?, bank_branch = ?, is_company = ?
WHERE user_id = ?
");
$stmtProfile->execute([$phone, $addressLine, $countryId, $cityId, $truckType, $loadCapacity, $plateNo, $bankAccount, $bankName, $bankBranch, $userId]);
$stmtProfile->execute([$phone, $addressLine, $countryId, $cityId, $bankAccount, $bankName, $bankBranch, $isCompany, $userId]);
db()->commit();
$flash = 'Truck Owner profile updated successfully.';
// If AJAX, return success immediately
if ($isAjax) {
header('Content-Type: application/json');
echo json_encode(['success' => true, 'message' => $flash]);
exit;
}
// Refresh data for non-ajax
$owner['full_name'] = $fullName;
$owner['email'] = $email;
$owner['status'] = $status;
$owner['phone'] = $phone;
$owner['address_line'] = $addressLine;
$owner['country_id'] = $countryId;
$owner['city_id'] = $cityId;
$owner['truck_type'] = $truckType;
$owner['load_capacity'] = $loadCapacity;
$owner['plate_no'] = $plateNo;
$owner['bank_account'] = $bankAccount;
$owner['bank_name'] = $bankName;
$owner['bank_branch'] = $bankBranch;
} catch (Throwable $e) {
db()->rollBack();
if (stripos($e->getMessage(), 'Duplicate entry') !== false) {
$errors[] = 'This email is already in use by another account.';
} else {
$errors[] = 'Failed to update truck owner profile. Please try again.';
}
$errors[] = 'Failed to update truck owner profile. Please try again.';
}
}
if ($isAjax && $errors) {
header('Content-Type: application/json');
echo json_encode(['success' => false, 'message' => implode('<br>', $errors)]);
exit;
}
}
$idCards = json_decode($owner['id_card_path'] ?? '[]', true) ?: [];
$regs = json_decode($owner['registration_path'] ?? '[]', true) ?: [];
$pic = $owner['truck_pic_path'];
// -- OUTPUT START --
if (!$isAjax):
@ -159,12 +112,9 @@ if (!$isAjax):
<?php render_admin_sidebar('truck_owners'); ?>
</div>
<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>
<a href="admin_truck_owners.php" class="text-decoration-none small text-muted mb-2 d-inline-block">&larr; Back to Truck Owners</a>
<h1 class="section-title mb-1">Edit Truck Owner</h1>
<p class="muted mb-0">Update profile information for <?= e($owner['full_name']) ?>.</p>
</div>
<div class="page-intro mb-4">
<a href="admin_truck_owners.php" class="text-decoration-none small text-muted mb-2 d-inline-block">&larr; Back to Truck Owners</a>
<h1 class="section-title mb-1">Edit Truck Owner</h1>
</div>
<?php if ($flash): ?>
@ -175,20 +125,8 @@ if (!$isAjax):
<?php endif; ?>
<div class="panel p-4">
<?php endif; // End non-ajax wrapper ?>
<!-- The Form (Shared) -->
<form method="post" action="admin_truck_owner_edit.php?id=<?= $userId ?> <?= csrf_field() ?><?= $isAjax ? '&ajax=1' : '' ?>" class="ajax-form">
<?php if ($isAjax): ?>
<div class="modal-header">
<h5 class="modal-title">Edit Truck Owner: <?= e($owner['full_name']) ?></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div id="form-errors" class="alert alert-danger d-none"></div>
<?php endif; ?>
<h5 class="mb-3 <?= $isAjax ? 'd-none' : '' ?>">Personal Details</h5>
<form method="post" action="admin_truck_owner_edit.php?id=<?= $userId ?>" class="mb-5"> <?= csrf_field() ?>
<h5 class="mb-3">Personal Details</h5>
<div class="row g-3 mb-4">
<div class="col-md-6">
<label class="form-label" for="full_name">Full Name</label>
@ -216,6 +154,11 @@ if (!$isAjax):
</div>
</div>
<div class="form-check mb-4">
<input class="form-check-input" type="checkbox" name="is_company" id="is_company" value="1" <?= $owner['is_company'] ? 'checked' : '' ?>>
<label class="form-check-label" for="is_company">Register as a company</label>
</div>
<h5 class="mb-3">Location</h5>
<div class="row g-3 mb-4">
<div class="col-md-4">
@ -241,23 +184,7 @@ if (!$isAjax):
</div>
</div>
<h5 class="mb-3">Truck Details</h5>
<div class="row g-3 mb-4">
<div class="col-md-4">
<label class="form-label" for="truck_type">Truck Type</label>
<input type="text" name="truck_type" id="truck_type" class="form-control" value="<?= e((string)$owner['truck_type']) ?>" required>
</div>
<div class="col-md-4">
<label class="form-label" for="load_capacity">Load Capacity (tons)</label>
<input type="number" step="0.01" min="0.1" name="load_capacity" id="load_capacity" class="form-control" value="<?= e((string)$owner['load_capacity']) ?>" required>
</div>
<div class="col-md-4">
<label class="form-label" for="plate_no">Plate Number</label>
<input type="text" name="plate_no" id="plate_no" class="form-control" value="<?= e((string)$owner['plate_no']) ?>" required>
</div>
</div>
<h5 class="mb-3 mt-4 border-top pt-3">Bank Details</h5>
<h5 class="mb-3 border-top pt-3">Bank Details</h5>
<div class="row g-3 mb-4">
<div class="col-md-4">
<label class="form-label" for="bank_account">Bank Account / IBAN</label>
@ -272,107 +199,49 @@ if (!$isAjax):
<input type="text" name="bank_branch" id="bank_branch" class="form-control" value="<?= e((string)($owner['bank_branch'] ?? '')) ?>">
</div>
</div>
<?php if (!$isAjax): // Hide heavy images in modal edit to keep it clean, or keep them? User said "big and long". Let's keep them but maybe minimized. Actually let's keep them, they are important. ?>
<h5 class="mb-3 mt-4 border-top pt-3">Uploaded Documents</h5>
<div class="row g-4 mb-4">
<div class="col-md-4">
<h6 class="text-muted mb-2">ID Card</h6>
<?php if ($idCards): ?>
<div class="d-flex flex-wrap gap-2">
<?php foreach ($idCards as $path): ?>
<a href="<?= e('/' . $path) ?>" target="_blank" class="d-block border rounded overflow-hidden" style="width: 100px; height: 100px;">
<img src="<?= e('/' . $path) ?>" alt="ID Card" class="w-100 h-100 object-fit-cover" style="object-fit: cover;">
</a>
<?php endforeach; ?>
</div>
<?php else: ?>
<p class="small text-muted">No ID card uploaded.</p>
<?php endif; ?>
</div>
<div class="col-md-4">
<h6 class="text-muted mb-2">Truck Picture</h6>
<?php if ($pic): ?>
<a href="<?= e('/' . $pic) ?>" target="_blank" class="d-block border rounded overflow-hidden" style="width: 100px; height: 100px;">
<img src="<?= e('/' . $pic) ?>" alt="Truck Picture" class="w-100 h-100 object-fit-cover" style="object-fit: cover;">
</a>
<?php else: ?>
<p class="small text-muted">No picture uploaded.</p>
<?php endif; ?>
</div>
<div class="col-md-4">
<h6 class="text-muted mb-2">Registration</h6>
<?php if ($regs): ?>
<div class="d-flex flex-wrap gap-2">
<?php foreach ($regs as $path): ?>
<a href="<?= e('/' . $path) ?>" target="_blank" class="d-block border rounded overflow-hidden" style="width: 100px; height: 100px;">
<img src="<?= e('/' . $path) ?>" alt="Registration" class="w-100 h-100 object-fit-cover" style="object-fit: cover;">
</a>
<?php endforeach; ?>
</div>
<?php else: ?>
<p class="small text-muted">No registration uploaded.</p>
<?php endif; ?>
</div>
</div>
<?php endif; ?>
<?php if ($isAjax): ?>
</div> <!-- modal-body -->
<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>
</div>
<?php else: ?>
<div class="mt-4">
<button type="submit" class="btn btn-primary">Save Changes</button>
<a href="admin_truck_owners.php" class="btn btn-outline-dark ms-2">Cancel</a>
</div>
<?php endif; ?>
<button type="submit" class="btn btn-primary">Save Changes</button>
</form>
<?php if (!$isAjax): ?>
<h5 class="mb-3 border-top pt-3">Registered Trucks</h5>
<table class="table table-bordered">
<thead>
<tr>
<th>Truck Type</th>
<th>Load Capacity (T)</th>
<th>Plate No</th>
</tr>
</thead>
<tbody>
<?php foreach ($ownerTrucks as $truck): ?>
<tr>
<td><?= e($truck['truck_type']) ?></td>
<td><?= e($truck['load_capacity']) ?></td>
<td><?= e($truck['plate_no']) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
<?php endif; ?>
<script>
(function() {
const allCities = <?= json_encode($cities, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?>;
const countrySelect = document.querySelector('#country_id'); // Use querySelector to scope? No, IDs are unique.
const citySelect = document.querySelector('#city_id');
const lang = '<?= $lang ?>';
window.syncCities = function() { // Expose globally for onchange
if (!countrySelect || !citySelect) return;
const countryId = countrySelect.value;
const selectedValue = citySelect.dataset.selected || '';
citySelect.innerHTML = '<option value="">Select city</option>';
allCities.forEach((city) => {
if (String(city.country_id) !== String(countryId)) {
return;
}
const option = document.createElement('option');
option.value = city.id;
option.textContent = lang === 'ar' && city.name_ar ? city.name_ar : (city.name_en || city.name_ar);
if (String(city.id) === String(selectedValue)) {
option.selected = true;
}
citySelect.appendChild(option);
});
citySelect.dataset.selected = '';
};
// Initialize
if (countrySelect && citySelect) {
syncCities();
// Re-bind change event if needed, but onchange in HTML handles it.
}
})();
const allCities = <?= json_encode($cities, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?>;
function syncCities() {
const countryId = document.getElementById('country_id').value;
const citySelect = document.getElementById('city_id');
const selectedValue = citySelect.dataset.selected || '';
citySelect.innerHTML = '<option value="">Select city</option>';
allCities.forEach((city) => {
if (String(city.country_id) !== String(countryId)) return;
const option = document.createElement('option');
option.value = city.id;
option.textContent = '<?= $lang ?>' === 'ar' && city.name_ar ? city.name_ar : (city.name_en || city.name_ar);
if (String(city.id) === String(selectedValue)) option.selected = true;
citySelect.appendChild(option);
});
citySelect.dataset.selected = '';
}
syncCities();
</script>
<?php if (!$isAjax) render_footer(); ?>
<?php render_footer(); endif; ?>

View File

@ -0,0 +1,28 @@
<?php
// db/migrations/add_trucks_table.php
$sql = "
CREATE TABLE IF NOT EXISTS trucks (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
truck_type VARCHAR(120) NOT NULL,
load_capacity DECIMAL(10,2) NOT NULL,
plate_no VARCHAR(80) NOT NULL,
truck_pic_path VARCHAR(255) NULL,
registration_path VARCHAR(255) NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT fk_truck_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- Add is_company flag to truck_owner_profiles
ALTER TABLE truck_owner_profiles ADD COLUMN IF NOT EXISTS is_company BOOLEAN DEFAULT FALSE;
";
require_once __DIR__ . '/../config.php';
try {
$db = db();
$db->exec($sql);
echo "Migration applied successfully.";
} catch (Exception $e) {
echo "Error applying migration: " . $e->getMessage();
}

View File

@ -312,6 +312,7 @@ $translations = [
'event_name' => 'Event Name',
'subject_en' => 'Subject (EN)',
'subject_ar' => 'Subject (AR)',
'is_company_checkbox' => 'Register as a company?',
),
"ar" => array (
'app_name' => 'CargoLink',
@ -612,6 +613,7 @@ $translations = [
'event_name' => 'اسم الحدث',
'subject_en' => 'الموضوع (إنجليزي)',
'subject_ar' => 'الموضوع (عربي)',
'is_company_checkbox' => 'هل التسجيل كشركة؟',
)
];
@ -875,4 +877,4 @@ try {
if ($tz && in_array($tz, DateTimeZone::listIdentifiers())) {
date_default_timezone_set($tz);
}
} catch (Throwable $e) {}
} catch (Throwable $e) {}

View File

@ -22,6 +22,7 @@ $values = [
'bank_account' => '',
'bank_name' => '',
'bank_branch' => '',
'is_company' => '0',
];
$countries = db()->query("SELECT id, name_en, name_ar FROM countries ORDER BY name_en ASC")->fetchAll();
@ -50,6 +51,10 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { validate_csrf_token();
'truck_type' => trim($_POST['truck_type'] ?? ''),
'load_capacity' => trim($_POST['load_capacity'] ?? ''),
'plate_no' => trim($_POST['plate_no'] ?? ''),
'bank_account' => trim($_POST['bank_account'] ?? ''),
'bank_name' => trim($_POST['bank_name'] ?? ''),
'bank_branch' => trim($_POST['bank_branch'] ?? ''),
'is_company' => isset($_POST['is_company']) ? '1' : '0',
];
if (!in_array($role, ['shipper', 'truck_owner'], true)) {
@ -168,8 +173,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { validate_csrf_token();
if (!$errors) {
$ownerStmt = $pdo->prepare(
"INSERT INTO truck_owner_profiles (user_id, phone, country_id, city_id, address_line, truck_type, load_capacity, plate_no, bank_account, bank_name, bank_branch, id_card_path, truck_pic_path, registration_path)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
"INSERT INTO truck_owner_profiles (user_id, phone, country_id, city_id, address_line, bank_account, bank_name, bank_branch, id_card_path, is_company)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
);
$ownerStmt->execute([
$userId,
@ -177,15 +182,24 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { validate_csrf_token();
$countryId,
$cityId,
$addressLine,
$values['bank_account'],
$values['bank_name'],
$values['bank_branch'],
json_encode($idCardPaths, JSON_UNESCAPED_SLASHES),
$values['is_company']
]);
$truckStmt = $pdo->prepare(
"INSERT INTO trucks (user_id, truck_type, load_capacity, plate_no, truck_pic_path, registration_path)
VALUES (?, ?, ?, ?, ?, ?)"
);
$truckStmt->execute([
$userId,
$truckType,
$loadCapacity,
$plateNo,
$bankAccount,
$bankName,
$bankBranch,
json_encode($idCardPaths, JSON_UNESCAPED_SLASHES),
$truckPic,
json_encode($regPaths, JSON_UNESCAPED_SLASHES),
json_encode($regPaths, JSON_UNESCAPED_SLASHES)
]);
}
}
@ -195,7 +209,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { validate_csrf_token();
} else {
$pdo->commit();
// Send Welcome Notification
$user = [
'id' => $userId,
'email' => $email,
@ -213,22 +226,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { validate_csrf_token();
$saved = true;
$saved_role = $role;
$values = [
'role' => $_GET['role'] ?? 'shipper',
'full_name' => '',
'email' => '',
'phone' => '',
'country_id' => '',
'city_id' => '',
'address_line' => '',
'company_name' => '',
'truck_type' => '',
'load_capacity' => '',
'plate_no' => '',
'bank_account' => '',
'bank_name' => '',
'bank_branch' => '',
];
}
} catch (Throwable $e) {
if ($pdo->inTransaction()) {
@ -324,6 +321,12 @@ render_header('Shipper & Truck Owner Registration');
<div id="truckFields" class="mt-4" style="display:none;">
<h2 class="h5 mb-3"><?= e(t('truck_details')) ?></h2>
<div class="row g-3">
<div class="col-md-12 mb-3">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="is_company" id="is_company" value="1" <?= $values['is_company'] === '1' ? 'checked' : '' ?>>
<label class="form-check-label" for="is_company"><?= e(t('is_company_checkbox')) ?></label>
</div>
</div>
<div class="col-md-4">
<label class="form-label" for="truck_type"><?= e(t('truck_type')) ?></label>
<input type="text" name="truck_type" id="truck_type" class="form-control" value="<?= e($values['truck_type']) ?>">
@ -337,7 +340,7 @@ render_header('Shipper & Truck Owner Registration');
<input type="text" name="plate_no" id="plate_no" class="form-control" value="<?= e($values['plate_no']) ?>">
</div>
<div class="col-md-4 mt-3">
<div class="col-md-4 mt-3">
<label class="form-label" for="bank_account"><?= e(t('bank_account')) ?></label>
<input type="text" name="bank_account" id="bank_account" class="form-control" value="<?= e($values['bank_account']) ?>">
</div>
@ -414,12 +417,9 @@ function toggleFields() {
truckFields.style.display = isOwner ? 'block' : 'none';
companyInput.required = !isOwner;
truckFields.querySelectorAll('input[type="text"], input[type="number"]').forEach((input) => {
input.required = isOwner;
});
}
syncCities();
toggleFields();
</script>
<?php render_footer(); ?>
<?php render_footer(); ?>