update sidebar

This commit is contained in:
Flatlogic Bot 2026-03-07 18:00:15 +00:00
parent 8bc413c26a
commit 890ce0acd2
11 changed files with 483 additions and 31 deletions

155
admin_company_profile.php Normal file
View File

@ -0,0 +1,155 @@
<?php
declare(strict_types=1);
require_once __DIR__ . '/includes/layout.php';
ensure_schema();
$errors = [];
$success = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$companyName = trim($_POST['company_name'] ?? '');
$companyEmail = trim($_POST['company_email'] ?? '');
$companyPhone = trim($_POST['company_phone'] ?? '');
$companyAddress = trim($_POST['company_address'] ?? '');
$updates = [
'company_name' => $companyName,
'company_email' => $companyEmail,
'company_phone' => $companyPhone,
'company_address' => $companyAddress,
];
// Handle file uploads
$uploadDir = __DIR__ . '/uploads/logos/';
if (!is_dir($uploadDir)) {
mkdir($uploadDir, 0775, true);
}
if (isset($_FILES['logo_file']) && $_FILES['logo_file']['error'] === UPLOAD_ERR_OK) {
$tmpName = $_FILES['logo_file']['tmp_name'];
$ext = strtolower(pathinfo($_FILES['logo_file']['name'], PATHINFO_EXTENSION));
$allowedExt = ['jpg', 'jpeg', 'png', 'gif', 'svg', 'webp'];
if (in_array($ext, $allowedExt, true)) {
$logoName = 'logo_' . time() . '.' . $ext;
$dest = $uploadDir . $logoName;
if (move_uploaded_file($tmpName, $dest)) {
$updates['logo_path'] = '/uploads/logos/' . $logoName;
}
} else {
$errors[] = "Invalid logo format.";
}
}
if (isset($_FILES['favicon_file']) && $_FILES['favicon_file']['error'] === UPLOAD_ERR_OK) {
$tmpName = $_FILES['favicon_file']['tmp_name'];
$ext = strtolower(pathinfo($_FILES['favicon_file']['name'], PATHINFO_EXTENSION));
$allowedExt = ['ico', 'png', 'svg', 'gif'];
if (in_array($ext, $allowedExt, true)) {
$faviconName = 'favicon_' . time() . '.' . $ext;
$dest = $uploadDir . $faviconName;
if (move_uploaded_file($tmpName, $dest)) {
$updates['favicon_path'] = '/uploads/logos/' . $faviconName;
}
} else {
$errors[] = "Invalid favicon format.";
}
}
if (empty($errors)) {
$pdo = db();
foreach ($updates as $key => $val) {
$stmt = $pdo->prepare("INSERT INTO settings (setting_key, setting_value) VALUES (:k, :v) ON DUPLICATE KEY UPDATE setting_value = :v2");
$stmt->execute([':k' => $key, ':v' => $val, ':v2' => $val]);
}
$success = "Company profile updated successfully.";
}
}
// Fetch current settings
$settings = get_settings();
$currentName = $settings['company_name'] ?? t('app_name');
$currentEmail = $settings['company_email'] ?? '';
$currentPhone = $settings['company_phone'] ?? '';
$currentAddress = $settings['company_address'] ?? '';
$currentLogo = $settings['logo_path'] ?? '';
$currentFavicon = $settings['favicon_path'] ?? '';
render_header('Company Profile', 'admin');
?>
<div class="row g-4">
<div class="col-lg-3">
<?php render_admin_sidebar('company_profile'); ?>
</div>
<div class="col-lg-9">
<div class="page-intro mb-4">
<h1 class="section-title mb-1">Company Profile</h1>
<p class="muted mb-0">Update your app name, logo, favicon, and contact details.</p>
</div>
<?php if ($success): ?>
<div class="alert alert-success"><?= e($success) ?></div>
<?php endif; ?>
<?php if ($errors): ?>
<div class="alert alert-danger"><?= e(implode('<br>', $errors)) ?></div>
<?php endif; ?>
<div class="panel p-4">
<form method="post" enctype="multipart/form-data">
<div class="row g-4">
<div class="col-md-6">
<label class="form-label fw-bold">Company / App Name</label>
<input type="text" name="company_name" class="form-control" value="<?= e($currentName) ?>" required>
</div>
<div class="col-md-6">
<label class="form-label fw-bold">Contact Email</label>
<input type="email" name="company_email" class="form-control" value="<?= e($currentEmail) ?>">
<div class="form-text">Displayed in the footer.</div>
</div>
<div class="col-md-6">
<label class="form-label fw-bold">Contact Phone</label>
<input type="text" name="company_phone" class="form-control" value="<?= e($currentPhone) ?>">
<div class="form-text">Displayed in the footer.</div>
</div>
<div class="col-md-6">
<label class="form-label fw-bold">Address</label>
<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-6">
<label class="form-label fw-bold">Company Logo</label>
<?php if ($currentLogo): ?>
<div class="mb-2">
<img src="<?= e($currentLogo) ?>" alt="Logo" height="40" class="border rounded p-1">
</div>
<?php endif; ?>
<input type="file" name="logo_file" class="form-control" accept="image/*">
<div class="form-text">Recommended size: 150x40px (PNG, JPG, SVG). Leave empty to keep current.</div>
</div>
<div class="col-md-6">
<label class="form-label fw-bold">Favicon</label>
<?php if ($currentFavicon): ?>
<div class="mb-2">
<img src="<?= e($currentFavicon) ?>" alt="Favicon" height="32" class="border rounded p-1">
</div>
<?php endif; ?>
<input type="file" name="favicon_file" class="form-control" accept="image/png, image/x-icon, image/svg+xml">
<div class="form-text">Recommended size: 32x32px (ICO, PNG, SVG). Leave empty to keep current.</div>
</div>
</div>
<hr class="my-4">
<button type="submit" class="btn btn-primary px-4">Save Changes</button>
</form>
</div>
</div>
</div>
<?php render_footer(); ?>

130
admin_integrations.php Normal file
View File

@ -0,0 +1,130 @@
<?php
declare(strict_types=1);
require_once __DIR__ . '/includes/layout.php';
ensure_schema();
$errors = [];
$success = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$updates = [
'thawani_publishable_key' => trim($_POST['thawani_publishable_key'] ?? ''),
'thawani_secret_key' => trim($_POST['thawani_secret_key'] ?? ''),
'thawani_environment' => trim($_POST['thawani_environment'] ?? 'test'),
'wablas_domain' => trim($_POST['wablas_domain'] ?? ''),
'wablas_api_token' => trim($_POST['wablas_api_token'] ?? ''),
'wablas_secret_key' => trim($_POST['wablas_secret_key'] ?? ''),
];
if (empty($errors)) {
$pdo = db();
foreach ($updates as $key => $val) {
$stmt = $pdo->prepare("INSERT INTO settings (setting_key, setting_value) VALUES (:k, :v) ON DUPLICATE KEY UPDATE setting_value = :v2");
$stmt->execute([':k' => $key, ':v' => $val, ':v2' => $val]);
}
$success = "Integrations settings updated successfully.";
}
}
$settings = get_settings();
$thawaniPub = $settings['thawani_publishable_key'] ?? '';
$thawaniSec = $settings['thawani_secret_key'] ?? '';
$thawaniEnv = $settings['thawani_environment'] ?? 'test';
$wablasDomain = $settings['wablas_domain'] ?? '';
$wablasToken = $settings['wablas_api_token'] ?? '';
$wablasSecret = $settings['wablas_secret_key'] ?? '';
render_header('Integrations', 'admin');
?>
<div class="row g-4">
<div class="col-lg-3">
<?php render_admin_sidebar('integrations'); ?>
</div>
<div class="col-lg-9">
<div class="page-intro mb-4">
<h1 class="section-title mb-1">Integrations</h1>
<p class="muted mb-0">Manage your payment gateway and communication APIs.</p>
</div>
<?php if ($success): ?>
<div class="alert alert-success"><?= e($success) ?></div>
<?php endif; ?>
<?php if ($errors): ?>
<div class="alert alert-danger"><?= e(implode('<br>', $errors)) ?></div>
<?php endif; ?>
<form method="post">
<!-- Thawani Payments Panel -->
<div class="panel p-4 mb-4">
<h3 class="h5 fw-bold mb-3 d-flex align-items-center">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-credit-card me-2 text-primary" viewBox="0 0 16 16">
<path d="M0 4a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2zm2-1a1 1 0 0 0-1 1v1h14V4a1 1 0 0 0-1-1zm13 4H1v5a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1z"/>
<path d="M2 10a1 1 0 0 1 1-1h1a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1z"/>
</svg>
Thawani Payments Gateway
</h3>
<p class="text-muted small mb-4">Configure your Oman-based Thawani Pay integration to process shipment payments.</p>
<div class="row g-4">
<div class="col-md-6">
<label class="form-label fw-bold">Environment</label>
<select name="thawani_environment" class="form-select">
<option value="test" <?= $thawaniEnv === 'test' ? 'selected' : '' ?>>Test / Sandbox</option>
<option value="live" <?= $thawaniEnv === 'live' ? 'selected' : '' ?>>Live / Production</option>
</select>
</div>
<div class="col-md-6"></div>
<div class="col-md-6">
<label class="form-label fw-bold">Publishable Key</label>
<input type="text" name="thawani_publishable_key" class="form-control" value="<?= e($thawaniPub) ?>" placeholder="pk_test_...">
</div>
<div class="col-md-6">
<label class="form-label fw-bold">Secret Key</label>
<input type="password" name="thawani_secret_key" class="form-control" value="<?= e($thawaniSec) ?>" placeholder="sk_test_...">
</div>
</div>
</div>
<!-- Wablas WhatsApp Gateway Panel -->
<div class="panel p-4 mb-4">
<h3 class="h5 fw-bold mb-3 d-flex align-items-center">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-whatsapp me-2 text-success" viewBox="0 0 16 16">
<path d="M13.601 2.326A7.85 7.85 0 0 0 7.994 0C3.627 0 .068 3.558.064 7.926c0 1.399.366 2.76 1.057 3.965L0 16l4.204-1.102a7.9 7.9 0 0 0 3.79.965h.004c4.368 0 7.926-3.558 7.93-7.93A7.9 7.9 0 0 0 13.6 2.326zM7.994 14.521a6.6 6.6 0 0 1-3.356-.92l-.24-.144-2.494.654.666-2.433-.156-.251a6.56 6.56 0 0 1-1.007-3.505c0-3.626 2.957-6.584 6.591-6.584a6.56 6.56 0 0 1 4.66 1.931 6.56 6.56 0 0 1 1.928 4.66c-.004 3.639-2.961 6.592-6.592 6.592m3.615-4.934c-.197-.099-1.17-.578-1.353-.646-.182-.065-.315-.099-.445.099-.133.197-.513.646-.627.775-.114.133-.232.148-.43.05-.197-.1-.836-.308-1.592-.985-.59-.525-.985-1.175-1.103-1.372-.114-.198-.011-.304.088-.403.087-.088.197-.232.296-.346.1-.114.133-.198.198-.33.065-.134.034-.248-.015-.347-.05-.099-.445-1.076-.612-1.47-.16-.389-.323-.335-.445-.34-.114-.007-.247-.007-.38-.007a.73.73 0 0 0-.529.247c-.182.198-.691.677-.691 1.654s.71 1.916.81 2.049c.098.133 1.394 2.132 3.383 2.992.47.205.84.326 1.129.418.475.152.904.129 1.246.08.38-.058 1.171-.48 1.338-.943.164-.464.164-.86.114-.943-.049-.084-.182-.133-.38-.232"/>
</svg>
Wablas WhatsApp Gateway
</h3>
<p class="text-muted small mb-4">Connect Wablas to automatically send WhatsApp notifications to Shippers and Truck Owners.</p>
<div class="row g-4">
<div class="col-md-6">
<label class="form-label fw-bold">Wablas Server Domain</label>
<input type="text" name="wablas_domain" class="form-control" value="<?= e($wablasDomain) ?>" placeholder="e.g. https://solo.wablas.com">
<div class="form-text">Your assigned server node from the Wablas dashboard.</div>
</div>
<div class="col-md-6">
<label class="form-label fw-bold">API Token</label>
<input type="password" name="wablas_api_token" class="form-control" value="<?= e($wablasToken) ?>" placeholder="API Token">
</div>
<div class="col-md-6">
<label class="form-label fw-bold">Secret Key</label>
<input type="password" name="wablas_secret_key" class="form-control" value="<?= e($wablasSecret) ?>" placeholder="Secret Key">
<div class="form-text">Optional. Provide if your Wablas webhooks require signature verification.</div>
</div>
</div>
</div>
<div class="d-flex justify-content-end">
<button type="submit" class="btn btn-primary px-5">Save Integrations</button>
</div>
</form>
</div>
</div>
<?php render_footer(); ?>

View File

@ -140,7 +140,7 @@ render_header('Manage Shippers', 'admin');
</td>
<td class="text-end pe-4">
<div class="d-inline-flex gap-1 align-items-center">
<a href="admin_shipper_edit.php?id=<?= e((string)$shipper[id]) ?>" class="btn btn-sm btn-light border text-primary" title="Edit Shipper">
<a href="admin_shipper_edit.php?id=<?= e((string)$shipper['id']) ?>" class="btn btn-sm btn-light border text-primary" title="Edit Shipper">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" class="bi bi-pencil" viewBox="0 0 16 16">
<path d="M12.146.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1 0 .708l-10 10a.5.5 0 0 1-.168.11l-5 2a.5.5 0 0 1-.65-.65l2-5a.5.5 0 0 1 .11-.168zM11.207 2.5 13.5 4.793 14.793 3.5 12.5 1.207zm1.586 3L10.5 3.207 4 9.707V10h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.293zm-9.761 5.175-.106.106-1.528 3.821 3.821-1.528.106-.106A.5.5 0 0 1 5 12.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.468-.325"/>
</svg>

View File

@ -16,7 +16,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.truck_type, p.load_capacity, p.plate_no,
p.id_card_path, p.truck_pic_path, p.registration_path
FROM users u
LEFT JOIN truck_owner_profiles p ON u.id = p.user_id
WHERE u.id = ? AND u.role = 'truck_owner'
@ -107,6 +108,10 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
}
}
$idCards = json_decode($owner['id_card_path'] ?? '[]', true) ?: [];
$regs = json_decode($owner['registration_path'] ?? '[]', true) ?: [];
$pic = $owner['truck_pic_path'];
render_header('Edit Truck Owner', 'admin');
?>
@ -197,6 +202,48 @@ render_header('Edit Truck Owner', 'admin');
</div>
</div>
<h5 class="mb-3 mt-5 border-top pt-4">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>
<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>

View File

@ -148,7 +148,7 @@ render_header('Manage Truck Owners', 'admin');
</td>
<td class="text-end pe-4">
<div class="d-inline-flex gap-1 align-items-center">
<a href="admin_truck_owner_edit.php?id=<?= e((string)$owner[id]) ?>" class="btn btn-sm btn-light border text-primary" title="Edit Owner">
<a href="admin_truck_owner_edit.php?id=<?= e((string)$owner['id']) ?>" class="btn btn-sm btn-light border text-primary" title="Edit Owner">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" class="bi bi-pencil" viewBox="0 0 16 16">
<path d="M12.146.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1 0 .708l-10 10a.5.5 0 0 1-.168.11l-5 2a.5.5 0 0 1-.65-.65l2-5a.5.5 0 0 1 .11-.168zM11.207 2.5 13.5 4.793 14.793 3.5 12.5 1.207zm1.586 3L10.5 3.207 4 9.707V10h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.293zm-9.761 5.175-.106.106-1.528 3.821 3.821-1.528.106-.106A.5.5 0 0 1 5 12.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.468-.325"/>
</svg>

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 286 KiB

View File

@ -0,0 +1,22 @@
<?php
require_once __DIR__ . '/../config.php';
$pdo = db();
try {
$pdo->exec("
CREATE TABLE IF NOT EXISTS settings (
setting_key VARCHAR(50) PRIMARY KEY,
setting_value TEXT
);
INSERT IGNORE INTO settings (setting_key, setting_value) VALUES
('company_name', 'My Transport Company'),
('company_email', 'info@example.com'),
('company_phone', '+1234567890'),
('company_address', '123 Transport St, City, Country'),
('logo_path', ''),
('favicon_path', '');
");
echo "Settings table created.\n";
} catch (Exception $e) {
echo "Error: " . $e->getMessage() . "\n";
}

View File

@ -273,3 +273,26 @@ function status_label(string $status): string
];
return $map[$status] ?? $status;
}
function get_settings(): array
{
static $settings = null;
if ($settings !== null) {
return $settings;
}
$settings = [];
try {
$stmt = db()->query("SELECT setting_key, setting_value FROM settings");
while ($row = $stmt->fetch()) {
$settings[$row['setting_key']] = $row['setting_value'];
}
} catch (Throwable $e) {
}
return $settings;
}
function get_setting(string $key, $default = ''): string
{
$settings = get_settings();
return $settings[$key] ?? $default;
}

View File

@ -8,13 +8,20 @@ function render_header(string $title, string $active = ''): void
$projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
$toggleLang = $lang === 'ar' ? 'en' : 'ar';
$toggleLabel = $lang === 'ar' ? 'EN' : 'AR';
$appName = get_setting('company_name', t('app_name'));
$logoPath = get_setting('logo_path');
$faviconPath = get_setting('favicon_path');
?>
<!doctype html>
<html lang="<?= e($lang) ?>" dir="<?= e($dir) ?>">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title><?= e($title) ?></title>
<title><?= e($title) ?> | <?= e($appName) ?></title>
<?php if ($faviconPath): ?>
<link rel="icon" href="<?= e($faviconPath) ?>">
<?php endif; ?>
<?php if ($projectDescription): ?>
<meta name="description" content="<?= e($projectDescription) ?>" />
<meta property="og:description" content="<?= e($projectDescription) ?>" />
@ -25,16 +32,21 @@ function render_header(string $title, string $active = ''): void
<meta property="twitter:image" content="<?= e($projectImageUrl) ?>" />
<?php endif; ?>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
<link rel="stylesheet" href="/assets/css/custom.css?v=<?= time() ?>">
</head>
<body class="app-body">
<nav class="navbar navbar-expand-lg navbar-light bg-white border-bottom sticky-top shadow-sm py-3">
<div class="container">
<a class="navbar-brand fs-4" href="<?= e(url_with_lang('index.php')) ?>">
<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" fill="currentColor" class="bi bi-box-seam me-1 text-primary" viewBox="0 0 16 16">
<path d="M8.186 1.113a.5.5 0 0 0-.372 0L1.846 3.5l2.404.961L10.404 2zm3.564 1.426L5.596 5 8 5.961 14.154 3.5zm3.25 1.7-6.5 2.6v7.922l6.5-2.6V4.24zM7.5 14.762V6.84L1 4.239v7.923zM7.443.184a1.5 1.5 0 0 1 1.114 0l7.129 2.852A.5.5 0 0 1 16 3.5v8.662a1 1 0 0 1-.629.928l-7.185 2.874a.5.5 0 0 1-.372 0L.63 13.09a1 1 0 0 1-.63-.928V3.5a.5.5 0 0 1 .314-.464z"/>
</svg>
<?= e(t('app_name')) ?>
<a class="navbar-brand fs-4 d-flex align-items-center" href="<?= e(url_with_lang('index.php')) ?>">
<?php if ($logoPath): ?>
<img src="<?= e($logoPath) ?>" alt="<?= e($appName) ?> Logo" height="32" class="me-2 rounded">
<?php else: ?>
<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" fill="currentColor" class="bi bi-box-seam me-1 text-primary" viewBox="0 0 16 16">
<path d="M8.186 1.113a.5.5 0 0 0-.372 0L1.846 3.5l2.404.961L10.404 2zm3.564 1.426L5.596 5 8 5.961 14.154 3.5zm3.25 1.7-6.5 2.6v7.922l6.5-2.6V4.24zM7.5 14.762V6.84L1 4.239v7.923zM7.443.184a1.5 1.5 0 0 1 1.114 0l7.129 2.852A.5.5 0 0 1 16 3.5v8.662a1 1 0 0 1-.629.928l-7.185 2.874a.5.5 0 0 1-.372 0L.63 13.09a1 1 0 0 1-.63-.928V3.5a.5.5 0 0 1 .314-.464z"/>
</svg>
<?php endif; ?>
<?= e($appName) ?>
</a>
<button class="navbar-toggler border-0" type="button" data-bs-toggle="collapse" data-bs-target="#mainNav">
<span class="navbar-toggler-icon"></span>
@ -90,6 +102,11 @@ function render_header(string $title, string $active = ''): void
function render_footer(): void
{
global $lang;
$appName = get_setting('company_name', t('app_name'));
$logoPath = get_setting('logo_path');
$companyEmail = get_setting('company_email', '');
$companyPhone = get_setting('company_phone', '');
$companyAddress = get_setting('company_address', '');
?>
</main>
<footer class="bg-white border-top py-5 mt-5">
@ -97,14 +114,31 @@ function render_footer(): void
<div class="row g-4 mb-4">
<div class="col-md-4">
<div class="d-flex align-items-center mb-3">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" class="bi bi-box-seam me-2 text-primary" viewBox="0 0 16 16">
<path d="M8.186 1.113a.5.5 0 0 0-.372 0L1.846 3.5l2.404.961L10.404 2zm3.564 1.426L5.596 5 8 5.961 14.154 3.5zm3.25 1.7-6.5 2.6v7.922l6.5-2.6V4.24zM7.5 14.762V6.84L1 4.239v7.923zM7.443.184a1.5 1.5 0 0 1 1.114 0l7.129 2.852A.5.5 0 0 1 16 3.5v8.662a1 1 0 0 1-.629.928l-7.185 2.874a.5.5 0 0 1-.372 0L.63 13.09a1 1 0 0 1-.63-.928V3.5a.5.5 0 0 1 .314-.464z"/>
</svg>
<h5 class="fw-bold mb-0 text-dark"><?= e(t('app_name')) ?></h5>
<?php if ($logoPath): ?>
<img src="<?= e($logoPath) ?>" alt="<?= e($appName) ?> Logo" height="28" class="me-2 rounded">
<?php else: ?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" class="bi bi-box-seam me-2 text-primary" viewBox="0 0 16 16">
<path d="M8.186 1.113a.5.5 0 0 0-.372 0L1.846 3.5l2.404.961L10.404 2zm3.564 1.426L5.596 5 8 5.961 14.154 3.5zm3.25 1.7-6.5 2.6v7.922l6.5-2.6V4.24zM7.5 14.762V6.84L1 4.239v7.923zM7.443.184a1.5 1.5 0 0 1 1.114 0l7.129 2.852A.5.5 0 0 1 16 3.5v8.662a1 1 0 0 1-.629.928l-7.185 2.874a.5.5 0 0 1-.372 0L.63 13.09a1 1 0 0 1-.63-.928V3.5a.5.5 0 0 1 .314-.464z"/>
</svg>
<?php endif; ?>
<h5 class="fw-bold mb-0 text-dark"><?= e($appName) ?></h5>
</div>
<p class="text-muted small pe-md-4">
<?= e(t('motivation_phrase')) ?>
</p>
<?php if ($companyEmail || $companyPhone || $companyAddress): ?>
<div class="small text-muted mt-3">
<?php if ($companyAddress): ?>
<div class="mb-1"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" class="bi bi-geo-alt me-1" viewBox="0 0 16 16"><path d="M12.166 8.94c-.524 1.062-1.234 2.12-1.96 3.07A32 32 0 0 1 8 14.58a32 32 0 0 1-2.206-2.57c-.726-.95-1.436-2.008-1.96-3.07C3.304 7.867 3 6.862 3 6a5 5 0 0 1 10 0c0 .862-.305 1.867-.834 2.94M8 16s6-5.686 6-10A6 6 0 0 0 2 6c0 4.314 6 10 6 10"/><path d="M8 8a2 2 0 1 1 0-4 2 2 0 0 1 0 4m0 1a3 3 0 1 0 0-6 3 3 0 0 0 0 6"/></svg><?= e($companyAddress) ?></div>
<?php endif; ?>
<?php if ($companyPhone): ?>
<div class="mb-1"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" class="bi bi-telephone me-1" viewBox="0 0 16 16"><path d="M3.654 1.328a.678.678 0 0 0-1.015-.063L1.605 2.3c-.483.484-.661 1.169-.45 1.77a17.6 17.6 0 0 0 4.168 6.608 17.6 17.6 0 0 0 6.608 4.168c.601.211 1.286.033 1.77-.45l1.034-1.034a.678.678 0 0 0-.063-1.015l-2.307-1.794a.68.68 0 0 0-.58-.122l-2.19.547a1.75 1.75 0 0 1-1.657-.459L5.482 8.062a1.75 1.75 0 0 1-.46-1.657l.548-2.19a.68.68 0 0 0-.122-.58z"/></svg><a href="tel:<?= e($companyPhone) ?>" class="text-muted text-decoration-none"><?= e($companyPhone) ?></a></div>
<?php endif; ?>
<?php if ($companyEmail): ?>
<div class="mb-1"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" class="bi bi-envelope me-1" viewBox="0 0 16 16"><path d="M0 4a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2zm2-1a1 1 0 0 0-1 1v.217l7 4.2 7-4.2V4a1 1 0 0 0-1-1zm13 2.383-4.708 2.825L15 11.105zm-.034 6.876-5.64-3.471L8 9.583l-1.326-.795-5.64 3.47A1 1 0 0 0 2 13h12a1 1 0 0 0 .966-.741M1 11.105l4.708-2.897L1 5.383z"/></svg><a href="mailto:<?= e($companyEmail) ?>" class="text-muted text-decoration-none"><?= e($companyEmail) ?></a></div>
<?php endif; ?>
</div>
<?php endif; ?>
</div>
<div class="col-md-2 offset-md-2">
<h6 class="fw-bold mb-3">Company</h6>
@ -133,7 +167,7 @@ function render_footer(): void
</div>
<div class="d-flex flex-column flex-md-row justify-content-between align-items-center pt-4 border-top small text-muted">
<span>&copy; <?= date('Y') ?> <?= e(t('app_name')) ?>. All rights reserved.</span>
<span>&copy; <?= date('Y') ?> <?= e($appName) ?>. All rights reserved.</span>
<span class="mt-2 mt-md-0"><?= e(t('footer_note')) ?></span>
</div>
</div>
@ -147,24 +181,65 @@ function render_footer(): void
function render_admin_sidebar(string $active = 'dashboard'): void
{
$items = [
'dashboard' => ['label' => 'Dashboard', 'href' => url_with_lang('admin_dashboard.php')],
'countries' => ['label' => 'Countries', 'href' => url_with_lang('admin_countries.php')],
'cities' => ['label' => 'Cities', 'href' => url_with_lang('admin_cities.php')],
'shippers' => ['label' => 'Shippers', 'href' => url_with_lang('admin_shippers.php')],
'truck_owners' => ['label' => 'Truck Owners', 'href' => url_with_lang('admin_truck_owners.php')],
'register' => ['label' => 'User Registration', 'href' => url_with_lang('register.php')],
];
$settingsActive = in_array($active, ['company_profile', 'integrations']);
$locationsActive = in_array($active, ['countries', 'cities']);
$usersActive = in_array($active, ['shippers', 'truck_owners', 'register']);
?>
<aside class="admin-sidebar panel p-4 shadow-sm border-0">
<h2 class="h5 fw-bold mb-4">Admin Panel</h2>
<h2 class="h5 fw-bold mb-4"><i class="bi bi-shield-lock me-2 text-primary"></i>Admin Panel</h2>
<nav class="nav flex-column gap-2">
<?php foreach ($items as $key => $item): ?>
<a class="admin-nav-link <?= $active === $key ? 'active' : '' ?>" href="<?= e($item['href']) ?>">
<?= e($item['label']) ?>
</a>
<?php endforeach; ?>
<a class="admin-nav-link <?= $active === 'dashboard' ? 'active' : '' ?>" href="<?= e(url_with_lang('admin_dashboard.php')) ?>">
<i class="bi bi-speedometer2 me-2"></i>Dashboard
</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="#collapseSettings" aria-expanded="<?= $settingsActive ? 'true' : 'false' ?>">
<span><i class="bi bi-gear-fill me-2"></i>Settings</span>
<i class="bi bi-chevron-down small"></i>
</a>
<div class="collapse <?= $settingsActive ? 'show' : '' ?>" id="collapseSettings">
<div class="nav flex-column gap-1 ms-3 border-start ps-2 border-2">
<a class="admin-nav-link <?= $active === 'company_profile' ? 'active' : '' ?>" href="<?= e(url_with_lang('admin_company_profile.php')) ?>">
<i class="bi bi-building me-2"></i>Company Setting
</a>
<a class="admin-nav-link <?= $active === 'integrations' ? 'active' : '' ?>" href="<?= e(url_with_lang('admin_integrations.php')) ?>">
<i class="bi bi-plug me-2"></i>Integrations
</a>
</div>
</div>
<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="#collapseLocations" aria-expanded="<?= $locationsActive ? 'true' : 'false' ?>">
<span><i class="bi bi-geo-alt-fill me-2"></i>Locations</span>
<i class="bi bi-chevron-down small"></i>
</a>
<div class="collapse <?= $locationsActive ? 'show' : '' ?>" id="collapseLocations">
<div class="nav flex-column gap-1 ms-3 border-start ps-2 border-2">
<a class="admin-nav-link <?= $active === 'countries' ? 'active' : '' ?>" href="<?= e(url_with_lang('admin_countries.php')) ?>">
<i class="bi bi-globe-americas me-2"></i>Countries
</a>
<a class="admin-nav-link <?= $active === 'cities' ? 'active' : '' ?>" href="<?= e(url_with_lang('admin_cities.php')) ?>">
<i class="bi bi-pin-map me-2"></i>Cities
</a>
</div>
</div>
<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="#collapseUsers" aria-expanded="<?= $usersActive ? 'true' : 'false' ?>">
<span><i class="bi bi-people-fill me-2"></i>Users</span>
<i class="bi bi-chevron-down small"></i>
</a>
<div class="collapse <?= $usersActive ? 'show' : '' ?>" id="collapseUsers">
<div class="nav flex-column gap-1 ms-3 border-start ps-2 border-2">
<a class="admin-nav-link <?= $active === 'shippers' ? 'active' : '' ?>" href="<?= e(url_with_lang('admin_shippers.php')) ?>">
<i class="bi bi-box-seam me-2"></i>Shippers
</a>
<a class="admin-nav-link <?= $active === 'truck_owners' ? 'active' : '' ?>" href="<?= e(url_with_lang('admin_truck_owners.php')) ?>">
<i class="bi bi-truck me-2"></i>Truck Owners
</a>
<a class="admin-nav-link <?= $active === 'register' ? 'active' : '' ?>" href="<?= e(url_with_lang('register.php')) ?>">
<i class="bi bi-person-plus me-2"></i>User Registration
</a>
</div>
</div>
</nav>
</aside>
<?php
}
}

View File

@ -61,7 +61,7 @@ render_header(t('app_name'), 'home');
</div>
</div>
<div class="col-lg-6">
<div class="hero-img-container" style="background-image: url('https://picsum.photos/id/1073/800/600');"></div>
<div class="hero-img-container" style="background-image: url('assets/images/hero_trucks.jpg');"></div>
</div>
</div>
</div>
@ -134,7 +134,7 @@ render_header(t('app_name'), 'home');
<section class="mb-5">
<div class="row g-4 align-items-center">
<div class="col-md-6 order-md-2">
<img src="https://picsum.photos/id/1015/600/400" alt="Logistics" class="img-fluid rounded-4 shadow-sm" style="width: 100%; object-fit: cover; height: 350px;">
<img src="assets/images/workflow_trucks.jpg" alt="Logistics" class="img-fluid rounded-4 shadow-sm" style="width: 100%; object-fit: cover; height: 350px;">
</div>
<div class="col-md-6 order-md-1">
<div class="p-lg-4">