Autosave: 20260218-083249

This commit is contained in:
Flatlogic Bot 2026-02-18 08:32:50 +00:00
parent b2346417d7
commit ea25e1e6ca
53 changed files with 1090 additions and 2695 deletions

View File

@ -1,59 +1,58 @@
<?php
declare(strict_types=1);
require_once __DIR__ . '/includes/header.php';
// about.php
require_once 'includes/auth.php';
require_once 'includes/header.php';
?>
<section class="container" style="padding-top: 6rem;">
<div class="section-grid">
<div class="container mt-5">
<div class="grid" style="grid-template-columns: 1fr 1fr; gap: 50px; align-items: center;">
<div>
<div class="section-title" style="display: block; margin-bottom: 2rem;">
<h1>About AFG_CARS</h1>
<p style="color: var(--accent-color); font-weight: 800; text-transform: uppercase; letter-spacing: 2px;">Establishing Excellence Since 2014</p>
</div>
<p style="color: var(--text-secondary); margin-bottom: 2rem; font-size: 1.1rem; line-height: 2;">
AFG_CARS is Afghanistan's premier destination for high-end automotive solutions. We specialize in sourcing the world's most desired luxury and performance vehicles, ensuring each one meets our strict criteria for quality and history.
</p>
<p style="color: var(--text-secondary); margin-bottom: 3rem; line-height: 1.8;">
Our revolutionary installment programs have made luxury ownership possible for thousands of Afghan citizens, providing a transparent and secure path to vehicle ownership without the burden of immediate full-capital expenditure.
</p>
<div class="grid" style="grid-template-columns: 1fr 1fr; gap: 2rem;">
<div class="feature-box" style="padding: 1.5rem; text-align: left;">
<h4 style="color: var(--accent-color); margin-bottom: 0.5rem;"><i class="fas fa-eye" style="font-size: 1.2rem; margin-bottom: 0;"></i> Our Vision</h4>
<p style="font-size: 0.85rem;">To modernize the Afghan automotive market through technology and transparency.</p>
</div>
<div class="feature-box" style="padding: 1.5rem; text-align: left;">
<h4 style="color: var(--accent-color); margin-bottom: 0.5rem;"><i class="fas fa-bullseye" style="font-size: 1.2rem; margin-bottom: 0;"></i> Our Mission</h4>
<p style="font-size: 0.85rem;">Providing quality vehicles for every road and every budget with absolute integrity.</p>
</div>
</div>
<h1>About AFG CARS</h1>
<p class="mb-5" style="color: var(--primary); font-weight: bold;">Your trusted partner for premium automotive solutions in Afghanistan.</p>
<p style="margin-bottom: 20px;">Founded in 2010, AFG CARS has established itself as the leading car dealership in Afghanistan. We specialize in importing and selling high-quality vehicles from top global manufacturers.</p>
<p>Our mission is to provide our customers with reliable, luxury vehicles at competitive prices, backed by exceptional customer service and flexible financing options.</p>
</div>
<div style="background: var(--surface-color); padding: 4rem; border-radius: var(--border-radius); border: 1px solid var(--border-color); box-shadow: 0 30px 60px rgba(0,0,0,0.5); display: flex; flex-direction: column; justify-content: center;">
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 4rem;">
<div style="text-align: center;">
<div style="font-size: 3.5rem; font-weight: 900; color: #fff;">2K+</div>
<div style="color: var(--accent-color); font-size: 0.75rem; font-weight: 800; text-transform: uppercase; letter-spacing: 2px;">Cars Delivered</div>
<div>
<div class="card" style="padding: 40px; text-align: center; background: rgba(255,255,255,0.05);">
<div class="grid" style="grid-template-columns: 1fr 1fr; gap: 20px;">
<div>
<h3 style="color: var(--primary); font-size: 2.5rem;">10+</h3>
<p>Years Experience</p>
</div>
<div>
<h3 style="color: var(--primary); font-size: 2.5rem;">5000+</h3>
<p>Cars Sold</p>
</div>
<div>
<h3 style="color: var(--primary); font-size: 2.5rem;">4</h3>
<p>Major Branches</p>
</div>
<div>
<h3 style="color: var(--primary); font-size: 2.5rem;">100%</h3>
<p>Satisfaction</p>
</div>
</div>
<div style="text-align: center;">
<div style="font-size: 3.5rem; font-weight: 900; color: #fff;">04</div>
<div style="color: var(--accent-color); font-size: 0.75rem; font-weight: 800; text-transform: uppercase; letter-spacing: 2px;">Showrooms</div>
</div>
<div style="text-align: center;">
<div style="font-size: 3.5rem; font-weight: 900; color: #fff;">15+</div>
<div style="color: var(--accent-color); font-size: 0.75rem; font-weight: 800; text-transform: uppercase; letter-spacing: 2px;">Global Partners</div>
</div>
<div style="text-align: center;">
<div style="font-size: 3.5rem; font-weight: 900; color: #fff;">100%</div>
<div style="color: var(--accent-color); font-size: 0.75rem; font-weight: 800; text-transform: uppercase; letter-spacing: 2px;">Verified Stock</div>
</div>
</div>
<div style="margin-top: 4rem; text-align: center; border-top: 1px solid rgba(255,255,255,0.05); padding-top: 2rem;">
<p style="font-size: 0.9rem; color: var(--text-secondary);">Enterprise System Managed by <strong>Mohammad Sadiq</strong></p>
<p style="font-size: 0.7rem; color: var(--text-secondary); opacity: 0.4; margin-top: 0.5rem;">Lamp Stack | MariaDB | PHP 8.2 | Premium UI</p>
</div>
</div>
</div>
</section>
<div class="mt-5">
<h2 class="text-center mb-5">Our Core Values</h2>
<div class="grid" style="grid-template-columns: repeat(3, 1fr);">
<div class="card" style="padding: 20px; text-align: center;">
<h3 style="color: var(--primary);">Integrity</h3>
<p>We believe in transparent pricing and honest dealings with every customer.</p>
</div>
<div class="card" style="padding: 20px; text-align: center;">
<h3 style="color: var(--primary);">Quality</h3>
<p>Every vehicle undergoes a rigorous 150-point inspection before sale.</p>
</div>
<div class="card" style="padding: 20px; text-align: center;">
<h3 style="color: var(--primary);">Service</h3>
<p>Our relationship doesn't end at the sale; we provide ongoing support.</p>
</div>
</div>
</div>
</div>
<?php require_once __DIR__ . '/includes/footer.php'; ?>
<?php require_once 'includes/footer.php'; ?>

View File

@ -1,188 +1,106 @@
<?php
require_once 'includes/header.php';
// admin/cars.php
require_once '../includes/auth.php';
require_once '../includes/middleware.php';
requireAdmin();
require_once '../includes/header.php';
global $pdo;
$pdo = db();
$error = '';
$success = '';
$msg = '';
// Handle Delete
if (isset($_POST['delete_car'])) {
$id = $_POST['car_id'];
if (isset($_GET['delete'])) {
$stmt = $pdo->prepare("DELETE FROM cars WHERE id = ?");
$stmt->execute([$id]);
$success = "Car deleted successfully.";
$stmt->execute([$_GET['delete']]);
$msg = "Car deleted successfully.";
}
// Handle Add (Basic Implementation)
if (isset($_POST['add_car'])) {
try {
$image_url = 'assets/images/cars/default.jpg'; // Default
// Handle Image Upload
if (isset($_FILES['image']) && $_FILES['image']['error'] === UPLOAD_ERR_OK) {
$uploadDir = __DIR__ . '/../assets/images/cars/';
if (!is_dir($uploadDir)) mkdir($uploadDir, 0777, true);
$ext = pathinfo($_FILES['image']['name'], PATHINFO_EXTENSION);
$filename = uniqid('car_') . '.' . $ext;
$targetPath = $uploadDir . $filename;
if (move_uploaded_file($_FILES['image']['tmp_name'], $targetPath)) {
$image_url = 'assets/images/cars/' . $filename;
}
}
$stmt = $pdo->prepare("INSERT INTO cars (vin, brand, model, year, price, mileage, transmission, fuel_type, status, branch_id, dealer_id, installment_available, image_url) VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'Available', ?, ?, ?, ?)");
$stmt->execute([
$_POST['vin'], $_POST['brand'], $_POST['model'], $_POST['year'],
$_POST['price'], $_POST['mileage'], $_POST['transmission'],
$_POST['fuel_type'], $_POST['branch_id'], $_POST['dealer_id'] ?: null,
isset($_POST['installment_available']) ? 1 : 0,
$image_url
]);
// Log activity
$adminId = $_SESSION['user_id'];
$pdo->prepare("INSERT INTO activity_logs (user_id, action) VALUES (?, 'Added new car: ' . ?)")->execute([$adminId, $_POST['brand'] . ' ' . $_POST['model']]);
$success = "Car added successfully.";
} catch (PDOException $e) {
$error = "Error adding car: " . $e->getMessage();
}
// Handle Add
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$brand = $_POST['brand'];
$model = $_POST['model'];
$year = $_POST['year'];
$price = $_POST['price'];
$branch_id = $_POST['branch_id'];
// Use a random placeholder from the 20 generated ones for demo purposes
$random_img = rand(1, 20);
$image_path = "assets/images/cars/car{$random_img}.jpg";
$stmt = $pdo->prepare("INSERT INTO cars (brand, model, year, price, branch_id, status, image_path, is_featured) VALUES (?, ?, ?, ?, ?, 'available', ?, 0)");
$stmt->execute([$brand, $model, $year, $price, $branch_id, $image_path]);
$msg = "Car added successfully.";
}
// Fetch Cars
$cars = $pdo->query("SELECT cars.*, branches.city FROM cars LEFT JOIN branches ON cars.branch_id = branches.id ORDER BY created_at DESC")->fetchAll();
$branches = $pdo->query("SELECT * FROM branches")->fetchAll();
$dealers = $pdo->query("SELECT * FROM users WHERE role = 'Dealer'")->fetchAll();
$stmt = $pdo->query("SELECT cars.*, branches.name as branch_name FROM cars LEFT JOIN branches ON cars.branch_id = branches.id ORDER BY cars.created_at DESC");
$cars = $stmt->fetchAll();
?>
<div class="page-header">
<h1>Car Management</h1>
<button onclick="document.getElementById('addCarModal').style.display='block'" class="btn-sm btn-primary" style="background:var(--accent-color); color:var(--bg-color); border:none; padding:0.5rem 1rem; cursor:pointer;">Add New Car</button>
</div>
<div class="dashboard-container">
<div class="sidebar">
<h3 class="mb-5" style="color: var(--primary);">Admin Panel</h3>
<a href="index.php">Dashboard</a>
<a href="cars.php" class="active">Manage Cars</a>
<a href="users.php">Manage Users</a>
<a href="branches.php">Manage Branches</a>
<a href="sales.php">Sales & Installments</a>
<a href="../logout.php" class="mt-5" style="color: #e63946;">Logout</a>
</div>
<div class="main-content">
<h1>Manage Cars</h1>
<?php if ($msg): ?>
<div class="alert alert-success" style="background: rgba(42, 157, 143, 0.2); color: #2a9d8f; padding: 10px; margin-bottom: 20px;">
<?= htmlspecialchars($msg) ?>
</div>
<?php endif; ?>
<?php if ($error): ?><div style="color: #ff4444; margin-bottom: 1rem;"><?php echo htmlspecialchars($error); ?></div><?php endif; ?>
<?php if ($success): ?><div style="color: #00C851; margin-bottom: 1rem;"><?php echo htmlspecialchars($success); ?></div><?php endif; ?>
<div style="overflow-x: auto;">
<table class="data-table">
<thead>
<tr>
<th>ID</th>
<th>Brand/Model</th>
<th>Year</th>
<th>Price</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<?php foreach ($cars as $car): ?>
<tr>
<td>#<?php echo $car['id']; ?></td>
<td><?php echo htmlspecialchars($car['brand'] . ' ' . $car['model']); ?></td>
<td><?php echo $car['year']; ?></td>
<td>$<?php echo number_format($car['price']); ?></td>
<td><?php echo $car['status']; ?></td>
<td>
<form method="POST" onsubmit="return confirm('Delete this car?');" style="display: inline;">
<input type="hidden" name="car_id" value="<?php echo $car['id']; ?>">
<button type="submit" name="delete_car" class="btn-sm btn-danger">Delete</button>
</form>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<!-- Simple Add Car Modal -->
<div id="addCarModal" style="display:none; position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.8); z-index:2000; align-items:center; justify-content:center; display:none;">
<div style="background:var(--card-bg); margin:5% auto; padding:2rem; width:90%; max-width:500px; border-radius:12px; border:1px solid var(--border-color); position: relative; max-height: 90vh; overflow-y: auto;">
<h2 style="margin-bottom:1.5rem; text-align:center;">Add New Car</h2>
<form method="POST" enctype="multipart/form-data">
<div style="margin-bottom:1rem;">
<label style="display:block; margin-bottom:0.5rem;">Vehicle Image</label>
<input type="file" name="image" accept="image/*" required style="width:100%; padding:0.8rem; background:var(--bg-color); border:1px solid var(--border-color); color:white; border-radius:4px;">
</div>
<div style="margin-bottom:1rem;">
<input type="text" name="vin" placeholder="VIN Number" required style="width:100%; padding:0.8rem; background:var(--bg-color); border:1px solid var(--border-color); color:white; border-radius:4px;">
</div>
<div style="display:grid; grid-template-columns: 1fr 1fr; gap:1rem; margin-bottom:1rem;">
<input type="text" name="brand" placeholder="Brand" required style="width:100%; padding:0.8rem; background:var(--bg-color); border:1px solid var(--border-color); color:white; border-radius:4px;">
<input type="text" name="model" placeholder="Model" required style="width:100%; padding:0.8rem; background:var(--bg-color); border:1px solid var(--border-color); color:white; border-radius:4px;">
</div>
<div style="display:grid; grid-template-columns: 1fr 1fr; gap:1rem; margin-bottom:1rem;">
<input type="number" name="year" placeholder="Year" required style="width:100%; padding:0.8rem; background:var(--bg-color); border:1px solid var(--border-color); color:white; border-radius:4px;">
<input type="number" name="price" placeholder="Price ($)" required style="width:100%; padding:0.8rem; background:var(--bg-color); border:1px solid var(--border-color); color:white; border-radius:4px;">
</div>
<div style="margin-bottom:1rem;">
<input type="number" name="mileage" placeholder="Mileage" required style="width:100%; padding:0.8rem; background:var(--bg-color); border:1px solid var(--border-color); color:white; border-radius:4px;">
</div>
<div style="display:grid; grid-template-columns: 1fr 1fr; gap:1rem; margin-bottom:1.5rem;">
<select name="transmission" style="width:100%; padding:0.8rem; background:var(--bg-color); border:1px solid var(--border-color); color:white; border-radius:4px;">
<option value="Automatic">Automatic</option>
<option value="Manual">Manual</option>
</select>
<select name="fuel_type" style="width:100%; padding:0.8rem; background:var(--bg-color); border:1px solid var(--border-color); color:white; border-radius:4px;">
<option value="Petrol">Petrol</option>
<option value="Diesel">Diesel</option>
<option value="Electric">Electric</option>
<option value="Hybrid">Hybrid</option>
</select>
</div>
<div style="display:grid; grid-template-columns: 1fr 1fr; gap:1rem; margin-bottom:1rem;">
<select name="branch_id" required style="width:100%; padding:0.8rem; background:var(--bg-color); border:1px solid var(--border-color); color:white; border-radius:4px;">
<!-- Add Car Form -->
<div class="card mb-5" style="padding: 20px;">
<h3>Add New Car</h3>
<form method="POST" class="grid" style="grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px;">
<input type="text" name="brand" placeholder="Brand" class="form-control" required>
<input type="text" name="model" placeholder="Model" class="form-control" required>
<input type="number" name="year" placeholder="Year" class="form-control" required>
<input type="number" name="price" placeholder="Price" class="form-control" required>
<select name="branch_id" class="form-control" required>
<option value="">Select Branch</option>
<?php foreach ($branches as $branch): ?>
<option value="<?php echo $branch['id']; ?>"><?php echo htmlspecialchars($branch['name']); ?></option>
<?php foreach ($branches as $b): ?>
<option value="<?= $b['id'] ?>"><?= htmlspecialchars($b['city']) ?></option>
<?php endforeach; ?>
</select>
<select name="dealer_id" style="width:100%; padding:0.8rem; background:var(--bg-color); border:1px solid var(--border-color); color:white; border-radius:4px;">
<option value="">Select Dealer (Optional)</option>
<?php foreach ($dealers as $dealer): ?>
<option value="<?php echo $dealer['id']; ?>"><?php echo htmlspecialchars($dealer['username']); ?></option>
<?php endforeach; ?>
</select>
</div>
<div style="margin-bottom:1.5rem;">
<label style="color:var(--text-secondary); display:flex; align-items:center;">
<input type="checkbox" name="installment_available" value="1" style="width:auto; margin-right:0.5rem;">
Available for Installment Plan
</label>
</div>
<button type="submit" name="add_car" style="width:100%; padding:0.8rem; background:var(--accent-color); border:none; border-radius:4px; color:var(--bg-color); font-weight:bold; cursor:pointer;">Add Car</button>
<button type="button" onclick="document.getElementById('addCarModal').style.display='none'" style="width:100%; padding:0.8rem; margin-top:0.5rem; background:transparent; border:1px solid var(--border-color); color:var(--text-secondary); cursor:pointer; border-radius:4px;">Cancel</button>
</form>
<button type="submit" class="btn">Add Car</button>
</form>
</div>
<div class="card" style="padding: 20px;">
<h3>Inventory List</h3>
<table>
<tr>
<th>ID</th>
<th>Car</th>
<th>Price</th>
<th>Branch</th>
<th>Status</th>
<th>Actions</th>
</tr>
<?php foreach ($cars as $car): ?>
<tr>
<td><?= $car['id'] ?></td>
<td><?= htmlspecialchars($car['year'] . ' ' . $car['brand'] . ' ' . $car['model']) ?></td>
<td>$<?= number_format((float)$car['price']) ?></td>
<td><?= htmlspecialchars($car['city'] ?? 'N/A') ?></td>
<td><?= htmlspecialchars(ucfirst($car['status'])) ?></td>
<td>
<a href="?delete=<?= $car['id'] ?>" style="color: #e63946;" onclick="return confirm('Are you sure?')">Delete</a>
</td>
</tr>
<?php endforeach; ?>
</table>
</div>
</div>
</div>
<script>
// Simple script to handle modal visibility since inline style display:none might be overridden by flex in CSS if I used flex
// Actually the inline style 'display:none' on the wrapper div is correct.
// I'll add a script to ensure it works.
const modal = document.getElementById('addCarModal');
// Auto-open if action=add
const urlParams = new URLSearchParams(window.location.search);
if (urlParams.get('action') === 'add') {
modal.style.display = 'flex';
} else {
// Ensure it's hidden on load if not requested
modal.style.display = 'none';
}
// Override the button to show it as flex for centering
document.querySelector('.page-header button').onclick = function() {
modal.style.display = 'flex';
};
// Close on cancel
document.querySelector('#addCarModal button[type="button"]').onclick = function() {
modal.style.display = 'none';
};
</script>
<?php require_once 'includes/footer.php'; ?>
<?php require_once '../includes/footer.php'; ?>

78
admin/dashboard.php Normal file
View File

@ -0,0 +1,78 @@
<?php
// admin/index.php
require_once '../includes/auth.php';
require_once '../includes/middleware.php';
requireAdmin();
require_once '../includes/header.php';
global $pdo;
// Fetch Stats
$total_cars = $pdo->query("SELECT COUNT(*) FROM cars")->fetchColumn();
$total_users = $pdo->query("SELECT COUNT(*) FROM users")->fetchColumn();
$total_sales = $pdo->query("SELECT COUNT(*) FROM sales")->fetchColumn();
$pending_inquiries = $pdo->query("SELECT COUNT(*) FROM inquiries")->fetchColumn();
?>
<div class="dashboard-container">
<div class="sidebar">
<h3 class="mb-5" style="color: var(--primary);">Admin Panel</h3>
<a href="index.php" class="active">Dashboard</a>
<a href="cars.php">Manage Cars</a>
<a href="users.php">Manage Users</a>
<a href="branches.php">Manage Branches</a>
<a href="sales.php">Sales & Installments</a>
<a href="../logout.php" class="mt-5" style="color: #e63946;">Logout</a>
</div>
<div class="main-content">
<h1>Dashboard</h1>
<p class="mb-5">Welcome back, <?= htmlspecialchars(getUserName()) ?></p>
<div class="grid" style="grid-template-columns: repeat(4, 1fr); gap: 20px; margin-bottom: 40px;">
<div class="card" style="padding: 20px; text-align: center;">
<h3>Total Cars</h3>
<div class="stat-number" style="font-size: 2rem; color: var(--primary); font-weight: bold;"><?= $total_cars ?></div>
</div>
<div class="card" style="padding: 20px; text-align: center;">
<h3>Total Users</h3>
<div class="stat-number" style="font-size: 2rem; color: var(--primary); font-weight: bold;"><?= $total_users ?></div>
</div>
<div class="card" style="padding: 20px; text-align: center;">
<h3>Sales</h3>
<div class="stat-number" style="font-size: 2rem; color: var(--primary); font-weight: bold;"><?= $total_sales ?></div>
</div>
<div class="card" style="padding: 20px; text-align: center;">
<h3>Inquiries</h3>
<div class="stat-number" style="font-size: 2rem; color: var(--primary); font-weight: bold;"><?= $pending_inquiries ?></div>
</div>
</div>
<div class="card" style="padding: 20px;">
<h3>Recent Inquiries</h3>
<table>
<tr>
<th>Date</th>
<th>Name</th>
<th>Email</th>
<th>Message</th>
</tr>
<?php
try {
$stmt = $pdo->query("SELECT * FROM inquiries ORDER BY created_at DESC LIMIT 5");
while ($row = $stmt->fetch()):
?>
<tr>
<td><?= date('M d, Y', strtotime($row['created_at'])) ?></td>
<td><?= htmlspecialchars($row['name']) ?></td>
<td><?= htmlspecialchars($row['email']) ?></td>
<td><?= htmlspecialchars(substr($row['message'], 0, 50)) ?>...</td>
</tr>
<?php endwhile;
} catch(Exception $e) { echo "<tr><td colspan='4'>No data</td></tr>"; }
?>
</table>
</div>
</div>
</div>
<?php require_once '../includes/footer.php'; ?>

0
admin/employees.php Normal file
View File

View File

@ -108,9 +108,9 @@ requireAdmin();
<body>
<div class="admin-layout">
<aside class="sidebar">
<a href="/index.php" class="sidebar-brand">AFG_CARS ADMIN</a>
<a href="/admin/dashboard.php" class="sidebar-brand">AFG_CARS ADMIN</a>
<nav>
<a href="/admin/index.php" class="nav-link <?php echo basename($_SERVER['PHP_SELF']) == 'index.php' ? 'active' : ''; ?>">Dashboard</a>
<a href="/admin/dashboard.php" class="nav-link <?php echo basename($_SERVER['PHP_SELF']) == 'dashboard.php' ? 'active' : ''; ?>">Dashboard</a>
<a href="/admin/users.php" class="nav-link <?php echo basename($_SERVER['PHP_SELF']) == 'users.php' ? 'active' : ''; ?>">Users</a>
<a href="/admin/branches.php" class="nav-link <?php echo basename($_SERVER['PHP_SELF']) == 'branches.php' ? 'active' : ''; ?>">Branches</a>
<a href="/admin/dealers.php" class="nav-link <?php echo basename($_SERVER['PHP_SELF']) == 'dealers.php' ? 'active' : ''; ?>">Dealers</a>

View File

@ -1,80 +1 @@
<?php
require_once 'includes/header.php';
$pdo = db();
$usersCount = $pdo->query("SELECT COUNT(*) FROM users")->fetchColumn();
$carsCount = $pdo->query("SELECT COUNT(*) FROM cars")->fetchColumn();
$branchesCount = $pdo->query("SELECT COUNT(*) FROM branches")->fetchColumn();
$salesCount = $pdo->query("SELECT COUNT(*) FROM sales WHERE status = 'Completed'")->fetchColumn();
$revenue = $pdo->query("SELECT SUM(final_price) FROM sales WHERE status = 'Completed'")->fetchColumn() ?: 0;
$activeContracts = $pdo->query("SELECT COUNT(*) FROM installments WHERE status = 'Active'")->fetchColumn();
// Recent Activity
$activities = $pdo->query("SELECT * FROM activity_logs ORDER BY created_at DESC LIMIT 5")->fetchAll();
?>
<div class="page-header">
<div>
<h1>Enterprise Dashboard</h1>
<span style="color: var(--text-secondary);">Overview of AFG_CARS Operations</span>
</div>
<div style="background: rgba(255,255,255,0.1); padding: 0.5rem 1rem; border-radius: 4px;">
Date: <?php echo date('Y-m-d'); ?>
</div>
</div>
<div class="card-grid">
<div class="stat-card">
<div class="stat-value"><?php echo $usersCount; ?></div>
<div class="stat-label">Total Users</div>
</div>
<div class="stat-card">
<div class="stat-value"><?php echo $branchesCount; ?></div>
<div class="stat-label">Branches</div>
</div>
<div class="stat-card">
<div class="stat-value"><?php echo $carsCount; ?></div>
<div class="stat-label">Total Inventory</div>
</div>
<div class="stat-card" style="border-color: var(--accent-color);">
<div class="stat-value">$<?php echo number_format($revenue); ?></div>
<div class="stat-label">Total Revenue</div>
</div>
<div class="stat-card">
<div class="stat-value"><?php echo $salesCount; ?></div>
<div class="stat-label">Completed Sales</div>
</div>
<div class="stat-card">
<div class="stat-value"><?php echo $activeContracts; ?></div>
<div class="stat-label">Active Installments</div>
</div>
</div>
<div style="display: grid; grid-template-columns: 2fr 1fr; gap: 1.5rem;">
<div style="background: var(--card-bg); border-radius: var(--border-radius); padding: 1.5rem; border: 1px solid var(--border-color);">
<h3 style="margin-bottom: 1rem; color: var(--accent-color);">System Activity Log</h3>
<?php if ($activities): ?>
<ul style="list-style: none; padding: 0;">
<?php foreach ($activities as $log): ?>
<li style="border-bottom: 1px solid var(--border-color); padding: 0.8rem 0; display: flex; justify-content: space-between;">
<span><?php echo htmlspecialchars($log['action']); ?></span>
<small style="color: var(--text-secondary);"><?php echo $log['created_at']; ?></small>
</li>
<?php endforeach; ?>
</ul>
<?php else: ?>
<p style="color: var(--text-secondary);">No recent activity logged.</p>
<?php endif; ?>
</div>
<div style="background: var(--card-bg); border-radius: var(--border-radius); padding: 1.5rem; border: 1px solid var(--border-color);">
<h3 style="margin-bottom: 1rem; color: var(--accent-color);">Quick Actions</h3>
<div style="display: flex; flex-direction: column; gap: 0.8rem;">
<a href="cars.php?action=add" class="btn-sm btn-primary" style="text-align: center;">Add New Car</a>
<a href="branches.php?action=add" class="btn-sm" style="background: #444; color: white; text-align: center;">New Branch</a>
<a href="users.php?action=add" class="btn-sm" style="background: #444; color: white; text-align: center;">Add User</a>
</div>
</div>
</div>
<?php require_once 'includes/footer.php'; ?>
<?php header('Location: dashboard.php'); ?>

0
admin/installments.php Normal file
View File

0
admin/settings.php Normal file
View File

View File

@ -1,493 +0,0 @@
<?php
// LocalAIApi — proxy client for the Responses API.
// Usage (async: auto-polls status until ready):
// require_once __DIR__ . '/ai/LocalAIApi.php';
// $response = LocalAIApi::createResponse([
// 'input' => [
// ['role' => 'system', 'content' => 'You are a helpful assistant.'],
// ['role' => 'user', 'content' => 'Tell me a bedtime story.'],
// ],
// ]);
// if (!empty($response['success'])) {
// // response['data'] contains full payload, e.g.:
// // {
// // "id": "resp_xxx",
// // "status": "completed",
// // "output": [
// // {"type": "reasoning", "summary": []},
// // {"type": "message", "content": [{"type": "output_text", "text": "Your final answer here."}]}
// // ]
// // }
// $decoded = LocalAIApi::decodeJsonFromResponse($response); // or inspect $response['data'] / extractText(...)
// }
// Poll settings override:
// LocalAIApi::createResponse($payload, ['poll_interval' => 5, 'poll_timeout' => 300]);
class LocalAIApi
{
/** @var array<string,mixed>|null */
private static ?array $configCache = null;
/**
* Signature compatible with the OpenAI Responses API.
*
* @param array<string,mixed> $params Request body (model, input, text, reasoning, metadata, etc.).
* @param array<string,mixed> $options Extra options (timeout, verify_tls, headers, path, project_uuid).
* @return array{
* success:bool,
* status?:int,
* data?:mixed,
* error?:string,
* response?:mixed,
* message?:string
* }
*/
public static function createResponse(array $params, array $options = []): array
{
$cfg = self::config();
$payload = $params;
if (empty($payload['input']) || !is_array($payload['input'])) {
return [
'success' => false,
'error' => 'input_missing',
'message' => 'Parameter "input" is required and must be an array.',
];
}
if (!isset($payload['model']) || $payload['model'] === '') {
$payload['model'] = $cfg['default_model'];
}
$initial = self::request($options['path'] ?? null, $payload, $options);
if (empty($initial['success'])) {
return $initial;
}
// Async flow: if backend returns ai_request_id, poll status until ready
$data = $initial['data'] ?? null;
if (is_array($data) && isset($data['ai_request_id'])) {
$aiRequestId = $data['ai_request_id'];
$pollTimeout = isset($options['poll_timeout']) ? (int) $options['poll_timeout'] : 300; // seconds
$pollInterval = isset($options['poll_interval']) ? (int) $options['poll_interval'] : 5; // seconds
return self::awaitResponse($aiRequestId, [
'timeout' => $pollTimeout,
'interval' => $pollInterval,
'headers' => $options['headers'] ?? [],
'timeout_per_call' => $options['timeout'] ?? null,
]);
}
return $initial;
}
/**
* Snake_case alias for createResponse (matches the provided example).
*
* @param array<string,mixed> $params
* @param array<string,mixed> $options
* @return array<string,mixed>
*/
public static function create_response(array $params, array $options = []): array
{
return self::createResponse($params, $options);
}
/**
* Perform a raw request to the AI proxy.
*
* @param string $path Endpoint (may be an absolute URL).
* @param array<string,mixed> $payload JSON payload.
* @param array<string,mixed> $options Additional request options.
* @return array<string,mixed>
*/
public static function request(?string $path = null, array $payload = [], array $options = []): array
{
$cfg = self::config();
$projectUuid = $cfg['project_uuid'];
if (empty($projectUuid)) {
return [
'success' => false,
'error' => 'project_uuid_missing',
'message' => 'PROJECT_UUID is not defined; aborting AI request.',
];
}
$defaultPath = $cfg['responses_path'] ?? null;
$resolvedPath = $path ?? ($options['path'] ?? $defaultPath);
if (empty($resolvedPath)) {
return [
'success' => false,
'error' => 'project_id_missing',
'message' => 'PROJECT_ID is not defined; cannot resolve AI proxy endpoint.',
];
}
$url = self::buildUrl($resolvedPath, $cfg['base_url']);
$baseTimeout = isset($cfg['timeout']) ? (int) $cfg['timeout'] : 30;
$timeout = isset($options['timeout']) ? (int) $options['timeout'] : $baseTimeout;
if ($timeout <= 0) {
$timeout = 30;
}
$baseVerifyTls = array_key_exists('verify_tls', $cfg) ? (bool) $cfg['verify_tls'] : true;
$verifyTls = array_key_exists('verify_tls', $options)
? (bool) $options['verify_tls']
: $baseVerifyTls;
$projectHeader = $cfg['project_header'];
$headers = [
'Content-Type: application/json',
'Accept: application/json',
];
$headers[] = $projectHeader . ': ' . $projectUuid;
if (!empty($options['headers']) && is_array($options['headers'])) {
foreach ($options['headers'] as $header) {
if (is_string($header) && $header !== '') {
$headers[] = $header;
}
}
}
if (!empty($projectUuid) && !array_key_exists('project_uuid', $payload)) {
$payload['project_uuid'] = $projectUuid;
}
$body = json_encode($payload, JSON_UNESCAPED_UNICODE);
if ($body === false) {
return [
'success' => false,
'error' => 'json_encode_failed',
'message' => 'Failed to encode request body to JSON.',
];
}
return self::sendCurl($url, 'POST', $body, $headers, $timeout, $verifyTls);
}
/**
* Poll AI request status until ready or timeout.
*
* @param int|string $aiRequestId
* @param array<string,mixed> $options
* @return array<string,mixed>
*/
public static function awaitResponse($aiRequestId, array $options = []): array
{
$cfg = self::config();
$timeout = isset($options['timeout']) ? (int) $options['timeout'] : 300; // seconds
$interval = isset($options['interval']) ? (int) $options['interval'] : 5; // seconds
if ($interval <= 0) {
$interval = 5;
}
$perCallTimeout = isset($options['timeout_per_call']) ? (int) $options['timeout_per_call'] : null;
$deadline = time() + max($timeout, $interval);
$headers = $options['headers'] ?? [];
while (true) {
$statusResp = self::fetchStatus($aiRequestId, [
'headers' => $headers,
'timeout' => $perCallTimeout,
]);
if (!empty($statusResp['success'])) {
$data = $statusResp['data'] ?? [];
if (is_array($data)) {
$statusValue = $data['status'] ?? null;
if ($statusValue === 'success') {
return [
'success' => true,
'status' => 200,
'data' => $data['response'] ?? $data,
];
}
if ($statusValue === 'failed') {
return [
'success' => false,
'status' => 500,
'error' => isset($data['error']) ? (string)$data['error'] : 'AI request failed',
'data' => $data,
];
}
}
} else {
return $statusResp;
}
if (time() >= $deadline) {
return [
'success' => false,
'error' => 'timeout',
'message' => 'Timed out waiting for AI response.',
];
}
sleep($interval);
}
}
/**
* Fetch status for queued AI request.
*
* @param int|string $aiRequestId
* @param array<string,mixed> $options
* @return array<string,mixed>
*/
public static function fetchStatus($aiRequestId, array $options = []): array
{
$cfg = self::config();
$projectUuid = $cfg['project_uuid'];
if (empty($projectUuid)) {
return [
'success' => false,
'error' => 'project_uuid_missing',
'message' => 'PROJECT_UUID is not defined; aborting status check.',
];
}
$statusPath = self::resolveStatusPath($aiRequestId, $cfg);
$url = self::buildUrl($statusPath, $cfg['base_url']);
$baseTimeout = isset($cfg['timeout']) ? (int) $cfg['timeout'] : 30;
$timeout = isset($options['timeout']) ? (int) $options['timeout'] : $baseTimeout;
if ($timeout <= 0) {
$timeout = 30;
}
$baseVerifyTls = array_key_exists('verify_tls', $cfg) ? (bool) $cfg['verify_tls'] : true;
$verifyTls = array_key_exists('verify_tls', $options)
? (bool) $options['verify_tls']
: $baseVerifyTls;
$projectHeader = $cfg['project_header'];
$headers = [
'Accept: application/json',
$projectHeader . ': ' . $projectUuid,
];
if (!empty($options['headers']) && is_array($options['headers'])) {
foreach ($options['headers'] as $header) {
if (is_string($header) && $header !== '') {
$headers[] = $header;
}
}
}
return self::sendCurl($url, 'GET', null, $headers, $timeout, $verifyTls);
}
/**
* Extract plain text from a Responses API payload.
*
* @param array<string,mixed> $response Result of LocalAIApi::createResponse|request.
* @return string
*/
public static function extractText(array $response): string
{
$payload = $response['data'] ?? $response;
if (!is_array($payload)) {
return '';
}
if (!empty($payload['output']) && is_array($payload['output'])) {
$combined = '';
foreach ($payload['output'] as $item) {
if (!isset($item['content']) || !is_array($item['content'])) {
continue;
}
foreach ($item['content'] as $block) {
if (is_array($block) && ($block['type'] ?? '') === 'output_text' && !empty($block['text'])) {
$combined .= $block['text'];
}
}
}
if ($combined !== '') {
return $combined;
}
}
if (!empty($payload['choices'][0]['message']['content'])) {
return (string) $payload['choices'][0]['message']['content'];
}
return '';
}
/**
* Attempt to decode JSON emitted by the model (handles markdown fences).
*
* @param array<string,mixed> $response
* @return array<string,mixed>|null
*/
public static function decodeJsonFromResponse(array $response): ?array
{
$text = self::extractText($response);
if ($text === '') {
return null;
}
$decoded = json_decode($text, true);
if (is_array($decoded)) {
return $decoded;
}
$stripped = preg_replace('/^```json|```$/m', '', trim($text));
if ($stripped !== null && $stripped !== $text) {
$decoded = json_decode($stripped, true);
if (is_array($decoded)) {
return $decoded;
}
}
return null;
}
/**
* Load configuration from ai/config.php.
*
* @return array<string,mixed>
*/
private static function config(): array
{
if (self::$configCache === null) {
$configPath = __DIR__ . '/config.php';
if (!file_exists($configPath)) {
throw new RuntimeException('AI config file not found: ai/config.php');
}
$cfg = require $configPath;
if (!is_array($cfg)) {
throw new RuntimeException('Invalid AI config format: expected array');
}
self::$configCache = $cfg;
}
return self::$configCache;
}
/**
* Build an absolute URL from base_url and a path.
*/
private static function buildUrl(string $path, string $baseUrl): string
{
$trimmed = trim($path);
if ($trimmed === '') {
return $baseUrl;
}
if (str_starts_with($trimmed, 'http://') || str_starts_with($trimmed, 'https://')) {
return $trimmed;
}
if ($trimmed[0] === '/') {
return $baseUrl . $trimmed;
}
return $baseUrl . '/' . $trimmed;
}
/**
* Resolve status path based on configured responses_path and ai_request_id.
*
* @param int|string $aiRequestId
* @param array<string,mixed> $cfg
* @return string
*/
private static function resolveStatusPath($aiRequestId, array $cfg): string
{
$basePath = $cfg['responses_path'] ?? '';
$trimmed = rtrim($basePath, '/');
if ($trimmed === '') {
return '/ai-request/' . rawurlencode((string)$aiRequestId) . '/status';
}
if (substr($trimmed, -11) !== '/ai-request') {
$trimmed .= '/ai-request';
}
return $trimmed . '/' . rawurlencode((string)$aiRequestId) . '/status';
}
/**
* Shared CURL sender for GET/POST requests.
*
* @param string $url
* @param string $method
* @param string|null $body
* @param array<int,string> $headers
* @param int $timeout
* @param bool $verifyTls
* @return array<string,mixed>
*/
private static function sendCurl(string $url, string $method, ?string $body, array $headers, int $timeout, bool $verifyTls): array
{
if (!function_exists('curl_init')) {
return [
'success' => false,
'error' => 'curl_missing',
'message' => 'PHP cURL extension is missing. Install or enable it on the VM.',
];
}
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verifyTls);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $verifyTls ? 2 : 0);
curl_setopt($ch, CURLOPT_FAILONERROR, false);
$upper = strtoupper($method);
if ($upper === 'POST') {
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body ?? '');
} else {
curl_setopt($ch, CURLOPT_HTTPGET, true);
}
$responseBody = curl_exec($ch);
if ($responseBody === false) {
$error = curl_error($ch) ?: 'Unknown cURL error';
curl_close($ch);
return [
'success' => false,
'error' => 'curl_error',
'message' => $error,
];
}
$status = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$decoded = null;
if ($responseBody !== '' && $responseBody !== null) {
$decoded = json_decode($responseBody, true);
if (json_last_error() !== JSON_ERROR_NONE) {
$decoded = null;
}
}
if ($status >= 200 && $status < 300) {
return [
'success' => true,
'status' => $status,
'data' => $decoded ?? $responseBody,
];
}
$errorMessage = 'AI proxy request failed';
if (is_array($decoded)) {
$errorMessage = $decoded['error'] ?? $decoded['message'] ?? $errorMessage;
} elseif (is_string($responseBody) && $responseBody !== '') {
$errorMessage = $responseBody;
}
return [
'success' => false,
'status' => $status,
'error' => $errorMessage,
'response' => $decoded ?? $responseBody,
];
}
}
// Legacy alias for backward compatibility with the previous class name.
if (!class_exists('OpenAIService')) {
class_alias(LocalAIApi::class, 'OpenAIService');
}

View File

@ -1,52 +0,0 @@
<?php
// OpenAI proxy configuration (workspace scope).
// Reads values from environment variables or executor/.env.
$projectUuid = getenv('PROJECT_UUID');
$projectId = getenv('PROJECT_ID');
if (
($projectUuid === false || $projectUuid === null || $projectUuid === '') ||
($projectId === false || $projectId === null || $projectId === '')
) {
$envPath = realpath(__DIR__ . '/../../.env'); // executor/.env
if ($envPath && is_readable($envPath)) {
$lines = @file($envPath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) ?: [];
foreach ($lines as $line) {
$line = trim($line);
if ($line === '' || $line[0] === '#') {
continue;
}
if (!str_contains($line, '=')) {
continue;
}
[$key, $value] = array_map('trim', explode('=', $line, 2));
if ($key === '') {
continue;
}
$value = trim($value, "\"' ");
if (getenv($key) === false || getenv($key) === '') {
putenv("{$key}={$value}");
}
}
$projectUuid = getenv('PROJECT_UUID');
$projectId = getenv('PROJECT_ID');
}
}
$projectUuid = ($projectUuid === false) ? null : $projectUuid;
$projectId = ($projectId === false) ? null : $projectId;
$baseUrl = 'https://flatlogic.com';
$responsesPath = $projectId ? "/projects/{$projectId}/ai-request" : null;
return [
'base_url' => $baseUrl,
'responses_path' => $responsesPath,
'project_id' => $projectId,
'project_uuid' => $projectUuid,
'project_header' => 'project-uuid',
'default_model' => 'gpt-5-mini',
'timeout' => 30,
'verify_tls' => true,
];

View File

@ -1,491 +1,228 @@
/* AFG CARS Enterprise Style - 100% Offline */
:root {
--bg-color: #050505;
--surface-color: #111111;
--card-bg: #181818;
--accent-color: #d4af37; /* Supreme Gold */
--accent-hover: #f1c40f;
--text-primary: #ffffff;
--text-secondary: #a0a0a0;
--border-radius: 12px;
--glass-bg: rgba(5, 5, 5, 0.9);
--border-color: rgba(212, 175, 55, 0.15);
--primary: #e63946;
--secondary: #1d3557;
--accent: #457b9d;
--light: #f1faee;
--dark: #0f172a;
--glass-bg: rgba(255, 255, 255, 0.05);
--glass-border: rgba(255, 255, 255, 0.1);
--shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.37);
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Inter', system-ui, -apple-system, sans-serif;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
background-color: var(--bg-color);
color: var(--text-primary);
background-color: var(--dark);
color: var(--light);
line-height: 1.6;
overflow-x: hidden;
min-height: 100vh;
display: flex;
flex-direction: column;
}
/* Header */
header {
background: var(--glass-bg);
backdrop-filter: blur(15px);
border-bottom: 1px solid var(--border-color);
padding: 1rem 5%;
a { text-decoration: none; color: inherit; transition: 0.3s; }
ul { list-style: none; }
/* Components */
.btn {
display: inline-block;
padding: 10px 20px;
background: var(--primary);
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
font-weight: bold;
text-align: center;
}
.btn:hover { background: #c1121f; transform: translateY(-2px); }
.btn-outline { background: transparent; border: 2px solid var(--primary); }
.btn-outline:hover { background: var(--primary); }
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
}
/* Navbar */
.navbar {
background: rgba(15, 23, 42, 0.95);
backdrop-filter: blur(10px);
border-bottom: 1px solid var(--glass-border);
position: sticky;
top: 0;
z-index: 1000;
padding: 15px 0;
}
.navbar .container {
display: flex;
justify-content: space-between;
align-items: center;
}
.logo {
font-size: 1.6rem;
font-weight: 900;
color: var(--accent-color);
text-transform: uppercase;
letter-spacing: 2px;
cursor: pointer;
}
.logo span {
color: var(--text-primary);
}
nav ul {
display: flex;
list-style: none;
gap: 2.5rem;
align-items: center;
}
nav a {
text-decoration: none;
color: var(--text-secondary);
font-size: 0.85rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 1px;
transition: 0.3s;
}
nav a:hover, nav a.active {
color: var(--accent-color);
}
.admin-link {
background: rgba(212, 175, 55, 0.1);
padding: 0.6rem 1.2rem !important;
border-radius: 30px;
color: var(--accent-color) !important;
border: 1px solid var(--border-color);
}
.logo { font-size: 1.5rem; font-weight: bold; color: var(--primary); }
.nav-links { display: flex; gap: 20px; }
.nav-links a:hover { color: var(--primary); }
/* Hero */
.hero {
min-height: 95vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 5rem 5%;
text-align: center;
background: linear-gradient(rgba(0,0,0,0.75), rgba(0,0,0,0.75)), url('../images/hero/bg.jpg');
height: 80vh;
background: linear-gradient(rgba(0,0,0,0.6), rgba(0,0,0,0.6)), url('../images/hero.jpg');
background-size: cover;
background-position: center;
background-attachment: fixed;
}
.hero h1 {
font-size: 5rem;
font-weight: 900;
margin-bottom: 1.5rem;
line-height: 1;
max-width: 1000px;
}
.hero h1 span {
color: var(--accent-color);
}
.hero p {
font-size: 1.25rem;
color: var(--text-secondary);
max-width: 700px;
margin-bottom: 3rem;
}
.hero-btns {
display: flex;
gap: 2rem;
}
/* Sections */
.container {
max-width: 1400px;
margin: 0 auto;
padding: 8rem 5%;
}
.section-title {
margin-bottom: 4rem;
display: flex;
justify-content: space-between;
align-items: flex-end;
}
.section-title h1, .section-title h2 {
font-size: 3rem;
font-weight: 800;
letter-spacing: -1px;
}
.section-title p {
color: var(--text-secondary);
font-size: 1.1rem;
margin-top: 0.5rem;
}
/* Grid System */
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
gap: 3rem;
}
/* Cards */
.car-card {
background: var(--surface-color);
border-radius: var(--border-radius);
overflow: hidden;
border: 1px solid rgba(255,255,255,0.05);
transition: 0.4s cubic-bezier(0.165, 0.84, 0.44, 1);
}
.car-card:hover {
transform: translateY(-10px);
border-color: var(--accent-color);
}
.car-image {
position: relative;
height: 240px;
}
.car-image img {
width: 100%;
height: 100%;
object-fit: cover;
}
.car-badge {
position: absolute;
top: 1rem;
left: 1rem;
background: var(--accent-color);
color: #000;
padding: 0.5rem 1rem;
font-size: 0.7rem;
font-weight: 900;
border-radius: 4px;
}
.car-content {
padding: 2rem;
}
.car-title {
font-size: 1.4rem;
font-weight: 700;
margin-bottom: 0.5rem;
}
.car-price {
font-size: 1.8rem;
color: var(--accent-color);
font-weight: 800;
margin-bottom: 1.5rem;
}
.car-meta {
display: flex;
gap: 1.5rem;
color: var(--text-secondary);
font-size: 0.85rem;
margin-bottom: 1rem;
}
.car-meta i {
color: var(--accent-color);
}
.installment-box {
margin-top: 1.5rem;
padding: 1rem;
background: rgba(212, 175, 55, 0.05);
border: 1px dashed var(--accent-color);
border-radius: 8px;
font-size: 0.9rem;
}
.installment-box strong {
color: var(--accent-color);
}
/* Buttons */
.btn {
padding: 1.2rem 3rem;
background: var(--accent-color);
color: #000;
text-decoration: none;
font-weight: 800;
text-transform: uppercase;
letter-spacing: 1px;
border-radius: var(--border-radius);
border: 2px solid var(--accent-color);
transition: 0.3s;
cursor: pointer;
display: inline-block;
font-size: 0.9rem;
}
.btn:hover {
background: var(--accent-hover);
border-color: var(--accent-hover);
transform: scale(1.05);
}
.btn-outline {
background: transparent;
color: var(--accent-color);
}
.btn-outline:hover {
background: var(--accent-color);
color: #000;
}
/* Feature Boxes (Why Choose Us) */
.feature-box {
padding: 3rem;
background: var(--surface-color);
border-radius: var(--border-radius);
text-align: center;
border: 1px solid rgba(255,255,255,0.03);
transition: 0.3s;
}
.feature-box:hover {
border-color: var(--accent-color);
background: rgba(212, 175, 55, 0.02);
}
.feature-box i {
font-size: 3rem;
color: var(--accent-color);
margin-bottom: 2rem;
}
.feature-box h3 {
font-size: 1.5rem;
margin-bottom: 1rem;
}
.feature-box p {
color: var(--text-secondary);
}
/* Reviews */
.review-card {
background: var(--surface-color);
padding: 2.5rem;
border-radius: var(--border-radius);
border: 1px solid rgba(255,255,255,0.05);
transition: 0.3s;
}
.review-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 30px rgba(0,0,0,0.3);
}
.review-header {
display: flex;
align-items: center;
gap: 1.5rem;
margin-bottom: 1.5rem;
}
.customer-photo {
width: 60px;
height: 60px;
background: var(--accent-color);
color: #000;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: 900;
font-size: 1.2rem;
text-align: center;
}
.hero h1 { font-size: 3rem; margin-bottom: 20px; }
.hero p { font-size: 1.2rem; margin-bottom: 30px; opacity: 0.9; }
.stars {
color: var(--accent-color);
margin-bottom: 1.5rem;
/* Cards */
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 30px;
margin: 50px 0;
}
.card {
background: var(--glass-bg);
border: 1px solid var(--glass-border);
border-radius: 10px;
overflow: hidden;
backdrop-filter: blur(4px);
transition: 0.3s;
display: flex;
flex-direction: column;
}
.card:hover { transform: translateY(-5px); box-shadow: var(--shadow); }
.card img { width: 100%; height: 200px; object-fit: cover; }
.card-body { padding: 20px; flex-grow: 1; display: flex; flex-direction: column; }
.card-title { font-size: 1.2rem; margin-bottom: 10px; }
.card-price { color: var(--primary); font-size: 1.1rem; font-weight: bold; margin-bottom: 10px; }
.card-meta { font-size: 0.9rem; color: #ccc; margin-bottom: 15px; }
.card-actions { margin-top: auto; }
.badge {
background: var(--accent);
padding: 3px 8px;
border-radius: 4px;
font-size: 0.8rem;
margin-right: 5px;
}
/* Locations */
.location-card {
background: var(--surface-color);
padding: 2.5rem;
border-radius: var(--border-radius);
border: 1px solid var(--border-color);
/* Forms */
.form-group { margin-bottom: 15px; }
.form-control {
width: 100%;
padding: 10px;
background: rgba(255,255,255,0.05);
border: 1px solid var(--glass-border);
color: white;
border-radius: 5px;
}
.form-control:focus { outline: none; border-color: var(--primary); }
/* Auth Box */
.auth-box {
max-width: 400px;
margin: 50px auto;
padding: 40px;
background: var(--glass-bg);
border: 1px solid var(--glass-border);
border-radius: 10px;
text-align: center;
}
.location-card h3 {
margin-bottom: 1.5rem;
/* Admin Dashboard */
.dashboard-container {
display: flex;
align-items: center;
gap: 1rem;
color: var(--accent-color);
min-height: calc(100vh - 60px);
}
.sidebar {
width: 250px;
background: rgba(0,0,0,0.3);
padding: 20px;
border-right: 1px solid var(--glass-border);
}
.sidebar a {
display: block;
padding: 12px;
margin-bottom: 5px;
border-radius: 5px;
}
.sidebar a.active, .sidebar a:hover {
background: var(--primary);
color: white;
}
.main-content { padding: 30px; flex-grow: 1; overflow-y: auto; }
.stat-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 20px;
margin-bottom: 30px;
}
.stat-card {
background: var(--glass-bg);
padding: 20px;
border-radius: 10px;
text-align: center;
border: 1px solid var(--glass-border);
}
.stat-number { font-size: 2rem; font-weight: bold; color: var(--primary); }
.location-info p {
margin-bottom: 1rem;
color: var(--text-secondary);
display: flex;
align-items: center;
gap: 1rem;
/* Tables */
.table-responsive { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; margin-top: 20px; }
th, td { padding: 12px; text-align: left; border-bottom: 1px solid var(--glass-border); }
th { background: rgba(255,255,255,0.05); }
tr:hover { background: rgba(255,255,255,0.02); }
/* Installment Calculator */
.calculator {
background: var(--glass-bg);
padding: 20px;
border-radius: 10px;
margin-top: 30px;
border: 1px solid var(--glass-border);
}
/* Footer */
footer {
background: #000;
padding: 8rem 5% 4rem;
border-top: 1px solid var(--border-color);
}
.footer-container {
display: grid;
grid-template-columns: 2fr 1fr 1.5fr;
gap: 5rem;
max-width: 1400px;
margin: 0 auto 5rem;
}
.footer-section h3 {
margin-bottom: 2rem;
color: var(--text-primary);
text-transform: uppercase;
font-size: 1.1rem;
letter-spacing: 2px;
}
.footer-section ul {
list-style: none;
}
.footer-section li {
margin-bottom: 1rem;
}
.footer-section a {
text-decoration: none;
color: var(--text-secondary);
transition: 0.3s;
}
.footer-section a:hover {
color: var(--accent-color);
padding-left: 10px;
}
.social-links {
display: flex;
gap: 1.5rem;
margin-top: 2rem;
}
.social-links a {
width: 45px;
height: 45px;
background: var(--surface-color);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
color: var(--text-primary);
transition: 0.3s;
}
.social-links a:hover {
background: var(--accent-color);
color: #000;
transform: rotate(360deg);
}
.footer-bottom {
background: rgba(0,0,0,0.5);
padding: 40px 0;
margin-top: auto;
border-top: 1px solid var(--glass-border);
text-align: center;
padding-top: 4rem;
border-top: 1px solid rgba(255,255,255,0.05);
color: var(--text-secondary);
font-size: 0.9rem;
}
/* Forms */
.form-group {
margin-bottom: 2rem;
}
/* Helpers */
.text-center { text-align: center; }
.mt-5 { margin-top: 3rem; }
.mb-5 { margin-bottom: 3rem; }
.text-danger { color: #e63946; }
.text-success { color: #2a9d8f; }
.form-group label {
display: block;
margin-bottom: 0.8rem;
font-weight: 600;
color: var(--text-secondary);
/* Filter Bar */
.filter-bar {
background: var(--glass-bg);
padding: 20px;
border-radius: 10px;
margin-bottom: 30px;
display: flex;
gap: 15px;
flex-wrap: wrap;
align-items: center;
}
.form-group input, .form-group textarea {
width: 100%;
padding: 1.2rem;
background: var(--bg-color);
border: 1px solid rgba(255,255,255,0.1);
border-radius: 8px;
color: #fff;
outline: none;
transition: 0.3s;
}
.form-group input:focus, .form-group textarea:focus {
border-color: var(--accent-color);
}
/* Section Grid for Subpages */
.section-grid {
display: grid;
grid-template-columns: 1.2fr 1fr;
gap: 5rem;
}
@media (max-width: 1024px) {
.section-grid {
grid-template-columns: 1fr;
}
.hero h1 {
font-size: 3.5rem;
}
}
@media (max-width: 768px) {
.footer-container {
grid-template-columns: 1fr;
}
.hero h1 {
font-size: 2.8rem;
}
.section-title {
flex-direction: column;
align-items: flex-start;
gap: 1.5rem;
}
.filter-bar select, .filter-bar input {
padding: 8px;
background: rgba(0,0,0,0.3);
border: 1px solid var(--glass-border);
color: white;
border-radius: 5px;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 73 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 17 KiB

BIN
assets/images/hero.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

View File

@ -1,63 +0,0 @@
<?php
require_once __DIR__ . '/../includes/role_middleware.php';
requireRole(['Customer', 'Buyer']);
require_once __DIR__ . '/../includes/header.php';
$pdo = db();
$userId = $_SESSION['user_id'];
// Get Installments
$installments = $pdo->prepare("
SELECT i.*, c.brand, c.model
FROM installments i
JOIN sales s ON i.sale_id = s.id
JOIN cars c ON s.car_id = c.id
WHERE s.user_id = ?
");
$installments->execute([$userId]);
$myInstallments = $installments->fetchAll();
?>
<div style="padding: 2rem;">
<div class="page-header">
<h1>My Dashboard</h1>
<span>Welcome, <?php echo htmlspecialchars($_SESSION['username']); ?></span>
</div>
<div style="background: var(--card-bg); padding: 2rem; border-radius: var(--border-radius); border: 1px solid var(--border-color); margin-bottom: 2rem;">
<h3 style="color: var(--accent-color); margin-bottom: 1rem;">My Installment Plans</h3>
<?php if ($myInstallments): ?>
<table class="data-table" style="width: 100%; border-collapse: collapse;">
<thead>
<tr>
<th style="text-align: left; padding: 0.5rem;">Vehicle</th>
<th style="text-align: left; padding: 0.5rem;">Total</th>
<th style="text-align: left; padding: 0.5rem;">Paid</th>
<th style="text-align: left; padding: 0.5rem;">Monthly</th>
<th style="text-align: left; padding: 0.5rem;">Status</th>
</tr>
</thead>
<tbody>
<?php foreach ($myInstallments as $inst): ?>
<tr>
<td style="padding: 0.5rem; border-bottom: 1px solid var(--border-color);"><?php echo htmlspecialchars($inst['brand'] . ' ' . $inst['model']); ?></td>
<td style="padding: 0.5rem; border-bottom: 1px solid var(--border-color);">$<?php echo number_format($inst['total_amount'], 2); ?></td>
<td style="padding: 0.5rem; border-bottom: 1px solid var(--border-color);">$<?php echo number_format($inst['paid_amount'], 2); ?></td>
<td style="padding: 0.5rem; border-bottom: 1px solid var(--border-color);">$<?php echo number_format($inst['monthly_payment'], 2); ?></td>
<td style="padding: 0.5rem; border-bottom: 1px solid var(--border-color);">
<span style="padding: 0.2rem 0.5rem; border-radius: 4px; background: rgba(255, 255, 255, 0.1);">
<?php echo htmlspecialchars($inst['status']); ?>
</span>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php else: ?>
<p style="color: var(--text-secondary);">You have no active installment plans.</p>
<a href="/marketplace.php" class="btn-sm btn-primary" style="margin-top: 1rem; display: inline-block;">Browse Cars</a>
<?php endif; ?>
</div>
</div>
<?php require_once __DIR__ . '/../includes/footer.php'; ?>

118
car_detail.php Normal file
View File

@ -0,0 +1,118 @@
<?php
// car_detail.php
require_once 'includes/auth.php';
require_once 'includes/header.php';
global $pdo;
$id = $_GET['id'] ?? 0;
$stmt = $pdo->prepare("SELECT * FROM cars WHERE id = ?");
$stmt->execute([$id]);
$car = $stmt->fetch();
if (!$car) {
die("<div class='container mt-5'><h1>Car not found</h1><a href='marketplace.php'>Back to Marketplace</a></div>");
}
// Fetch Branch Info
$stmt = $pdo->prepare("SELECT * FROM branches WHERE id = ?");
$stmt->execute([$car['branch_id']]);
$branch = $stmt->fetch();
?>
<div class="container mt-5">
<a href="marketplace.php" class="btn-outline" style="margin-bottom: 20px; display: inline-block;">&larr; Back to Marketplace</a>
<div class="grid" style="grid-template-columns: 2fr 1fr; gap: 40px;">
<!-- Left Column: Image & Desc -->
<div>
<div class="card" style="padding: 0; margin-bottom: 20px;">
<img src="<?= htmlspecialchars($car['image_path'] ?? $car['image_url'] ?? '') ?>" alt="<?= htmlspecialchars($car['brand']) ?>" style="height: auto; max-height: 500px;">
</div>
<div class="card" style="padding: 30px;">
<h2>Vehicle Description</h2>
<p><?= nl2br(htmlspecialchars($car['description'])) ?></p>
</div>
</div>
<!-- Right Column: Details & Actions -->
<div>
<div class="card" style="padding: 30px;">
<h1 style="color: var(--primary); margin-bottom: 10px;">
<?= htmlspecialchars($car['year'] . ' ' . $car['brand'] . ' ' . $car['model']) ?>
</h1>
<div style="font-size: 2rem; font-weight: bold; margin-bottom: 20px;">
$<?= number_format((float)$car['price']) ?>
</div>
<table style="margin-bottom: 30px;">
<tr><th>Mileage</th><td><?= number_format((float)$car['mileage']) ?> km</td></tr>
<tr><th>Fuel</th><td><?= htmlspecialchars($car['fuel_type']) ?></td></tr>
<tr><th>Transmission</th><td><?= htmlspecialchars($car['transmission']) ?></td></tr>
<tr><th>Status</th><td><?= htmlspecialchars(ucfirst($car['status'])) ?></td></tr>
<tr><th>Location</th><td><?= htmlspecialchars($branch['city'] ?? 'Unknown') ?></td></tr>
</table>
<a href="contact.php?inquiry=<?= $car['id'] ?>" class="btn" style="width: 100%; margin-bottom: 10px;">Request to Buy</a>
<button onclick="document.getElementById('calc-section').scrollIntoView({behavior: 'smooth'})" class="btn-outline" style="width: 100%;">Calculate Installments</button>
</div>
<div class="card" style="padding: 20px; margin-top: 20px;">
<h3>Branch Contact</h3>
<p><strong><?= htmlspecialchars($branch['name'] ?? '') ?></strong></p>
<p><?= htmlspecialchars($branch['address'] ?? '') ?></p>
<p><?= htmlspecialchars($branch['phone'] ?? '') ?></p>
</div>
</div>
</div>
<!-- Installment Calculator for this car -->
<div id="calc-section" class="card mt-5" style="padding: 40px;">
<h2>Installment Calculator</h2>
<div class="grid" style="grid-template-columns: 1fr 1fr 1fr;">
<div>
<label>Vehicle Price</label>
<input type="text" class="form-control" value="$<?= number_format((float)$car['price']) ?>" disabled>
</div>
<div>
<label>Down Payment ($)</label>
<input type="number" id="downPayment" class="form-control" value="<?= (float)$car['price'] * 0.2 ?>" oninput="calc()">
</div>
<div>
<label>Term</label>
<select id="term" class="form-control" onchange="calc()">
<option value="12">12 Months</option>
<option value="24" selected>24 Months</option>
<option value="36">36 Months</option>
<option value="48">48 Months</option>
</select>
</div>
</div>
<div style="margin-top: 20px; font-size: 1.5rem; text-align: center;">
Estimated Monthly Payment: <span id="monthlyPayment" style="color: var(--primary); font-weight: bold;">---</span>
</div>
</div>
</div>
<script>
function calc() {
const price = <?= (float)$car['price'] ?>;
const down = parseFloat(document.getElementById('downPayment').value) || 0;
const months = parseInt(document.getElementById('term').value);
const principal = price - down;
if (principal < 0) {
document.getElementById('monthlyPayment').innerText = "Down payment exceeds price!";
return;
}
const interest = 0.05; // 5% flat
const total = principal * (1 + interest);
const monthly = total / months;
document.getElementById('monthlyPayment').innerText = "$" + monthly.toFixed(2);
}
calc(); // Run on load
</script>
<?php require_once 'includes/footer.php'; ?>

View File

@ -1,117 +0,0 @@
<?php
declare(strict_types=1);
require_once __DIR__ . '/includes/header.php';
$id = $_GET['id'] ?? 0;
$car = null;
try {
$db = db();
$stmt = $db->prepare("SELECT c.*, b.name as branch_name, b.address as branch_address, b.phone as branch_phone
FROM cars c
LEFT JOIN branches b ON c.branch_id = b.id
WHERE c.id = ?");
$stmt->execute([$id]);
$car = $stmt->fetch();
} catch (Exception $e) {
// Log error if needed
}
if (!$car) {
echo "<div class='container' style='padding: 4rem; text-align: center;'>
<h2>Car not found</h2>
<p>The vehicle you are looking for does not exist or has been removed.</p>
<a href='marketplace.php' class='btn'>Browse Inventory</a>
</div>";
require_once __DIR__ . '/includes/footer.php';
exit;
}
?>
<section class="container" style="padding-top: 4rem;">
<div class="grid" style="grid-template-columns: 1.5fr 1fr; gap: 3rem; align-items: start;">
<!-- Left Column: Images -->
<div>
<div class="car-image" style="height: 500px; margin-bottom: 1rem;">
<?php if ($car['is_featured']): ?>
<span class="car-badge">FEATURED</span>
<?php endif; ?>
<img src="<?= htmlspecialchars($car['image_url']) ?>" alt="<?= htmlspecialchars($car['brand']) ?>" style="width: 100%; height: 100%; object-fit: cover; border-radius: var(--border-radius);">
</div>
<!-- Placeholder for additional gallery images if we had them -->
<div class="grid" style="grid-template-columns: repeat(4, 1fr); gap: 1rem;">
<!-- Just repeating main image for gallery effect since we only have one -->
<img src="<?= htmlspecialchars($car['image_url']) ?>" style="height: 80px; width: 100%; object-fit: cover; border-radius: 8px; cursor: pointer; opacity: 0.7;">
<img src="<?= htmlspecialchars($car['image_url']) ?>" style="height: 80px; width: 100%; object-fit: cover; border-radius: 8px; cursor: pointer; opacity: 0.7;">
<img src="<?= htmlspecialchars($car['image_url']) ?>" style="height: 80px; width: 100%; object-fit: cover; border-radius: 8px; cursor: pointer; opacity: 0.7;">
</div>
</div>
<!-- Right Column: Details -->
<div>
<div style="margin-bottom: 1rem; color: var(--accent-color); font-weight: 700; text-transform: uppercase; letter-spacing: 1px;">
<?= htmlspecialchars($car['status']) ?>
</div>
<h1 style="font-size: 2.5rem; margin-bottom: 0.5rem; line-height: 1.2;">
<?= htmlspecialchars($car['year'] . ' ' . $car['brand'] . ' ' . $car['model']) ?>
</h1>
<div style="font-size: 2rem; font-weight: 800; color: var(--accent-color); margin-bottom: 2rem;">
$<?= number_format((float)$car['price'], 0) ?>
</div>
<div style="background: var(--surface-color); padding: 2rem; border-radius: var(--border-radius); border: 1px solid var(--border-color); margin-bottom: 2rem;">
<h3 style="margin-bottom: 1.5rem; border-bottom: 1px solid var(--border-color); padding-bottom: 0.5rem;">Vehicle Specifications</h3>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 1.5rem;">
<div>
<div style="color: var(--text-secondary); font-size: 0.9rem;">Mileage</div>
<div style="font-weight: 600;"><?= number_format((float)$car['mileage'], 0) ?> km</div>
</div>
<div>
<div style="color: var(--text-secondary); font-size: 0.9rem;">Transmission</div>
<div style="font-weight: 600;"><?= htmlspecialchars($car['transmission'] ?? 'Automatic') ?></div>
</div>
<div>
<div style="color: var(--text-secondary); font-size: 0.9rem;">Fuel Type</div>
<div style="font-weight: 600;"><?= htmlspecialchars($car['fuel_type'] ?? 'Petrol') ?></div>
</div>
<div>
<div style="color: var(--text-secondary); font-size: 0.9rem;">VIN</div>
<div style="font-weight: 600;"><?= htmlspecialchars($car['vin']) ?></div>
</div>
<div>
<div style="color: var(--text-secondary); font-size: 0.9rem;">Location</div>
<div style="font-weight: 600;"><?= htmlspecialchars($car['branch_name'] ?? 'Main Showroom') ?></div>
</div>
</div>
</div>
<?php if ($car['installment_available']): ?>
<div style="background: rgba(255, 215, 0, 0.1); padding: 1.5rem; border-radius: var(--border-radius); border: 1px solid var(--accent-color); margin-bottom: 2rem;">
<h3 style="color: var(--accent-color); margin-bottom: 0.5rem;"><i class="fas fa-calculator"></i> Installment Plan</h3>
<p style="margin-bottom: 1rem; font-size: 0.9rem;">Flexible financing options available for this vehicle.</p>
<div style="font-size: 1.2rem; font-weight: 700;">
Est. $<?= number_format($car['price'] / 60, 0) ?> / month
<span style="font-size: 0.9rem; font-weight: 400; color: var(--text-secondary);">(60 months)</span>
</div>
</div>
<?php endif; ?>
<div style="display: flex; gap: 1rem;">
<a href="contact.php?subject=Purchase%20Inquiry%20-%20<?= urlencode($car['brand'] . ' ' . $car['model']) ?>&car_id=<?= $car['id'] ?>" class="btn" style="flex: 1; text-align: center;">Request to Buy</a>
<?php if ($car['installment_available']): ?>
<a href="contact.php?subject=Installment%20Inquiry%20-%20<?= urlencode($car['brand'] . ' ' . $car['model']) ?>&car_id=<?= $car['id'] ?>" class="btn btn-outline" style="flex: 1; text-align: center;">Apply for Installment</a>
<?php endif; ?>
</div>
<p style="margin-top: 1.5rem; font-size: 0.8rem; color: var(--text-secondary); text-align: center;">
* Price excludes tax and registration fees. Contact us for final pricing.
</p>
</div>
</div>
</section>
<?php require_once __DIR__ . '/includes/footer.php'; ?>

View File

@ -1,32 +0,0 @@
<?php
require_once 'db/config.php';
try {
$pdo = db();
$stmt = $pdo->query("SHOW TABLES LIKE 'users'");
if ($stmt->rowCount() > 0) {
echo "Table 'users' exists.\n";
} else {
echo "Table 'users' does not exist.\n";
// Create table
$sql = "CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(100) NOT NULL,
`email` varchar(100) NOT NULL UNIQUE,
`password` varchar(255) NOT NULL,
`role` enum('Guest','Customer','Dealer','Employee','Manager','Admin','Super Admin') DEFAULT 'Customer',
`created_at` timestamp NULL DEFAULT current_timestamp(),
PRIMARY KEY (`id`),
UNIQUE KEY `username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;";
$pdo->exec($sql);
echo "Table 'users' created.\n";
// Seed admin user
$password = password_hash('admin123', PASSWORD_DEFAULT);
$stmt = $pdo->prepare("INSERT INTO users (username, email, password, role) VALUES (?, ?, ?, ?)");
$stmt->execute(['admin', 'admin@example.com', $password, 'Admin']);
echo "Admin user created (user: admin, pass: admin123).\n";
}
} catch (PDOException $e) {
echo "Error: " . $e->getMessage();
}

View File

@ -1,88 +1,86 @@
<?php
declare(strict_types=1);
require_once __DIR__ . '/includes/header.php';
// contact.php
require_once 'includes/auth.php';
require_once 'includes/header.php';
global $pdo;
$subject = $_GET['subject'] ?? '';
$car_id = $_GET['car_id'] ?? '';
$message_placeholder = "Please provide details about the vehicle or service you are interested in...";
$msg = '';
$inquiry_car = null;
if ($car_id) {
$message_placeholder = "I am interested in vehicle ID #$car_id. Please provide more information.";
if (isset($_GET['inquiry'])) {
$stmt = $pdo->prepare("SELECT * FROM cars WHERE id = ?");
$stmt->execute([$_GET['inquiry']]);
$inquiry_car = $stmt->fetch();
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Process form (Demo only - just save to DB or show success)
$name = $_POST['name'];
$email = $_POST['email'];
$message = $_POST['message'];
$car_id = $_POST['car_id'] ?? null;
// Use the built-in mail service if desired, or just save to DB
// For this "100% offline" task, saving to DB is better.
$stmt = $pdo->prepare("INSERT INTO inquiries (car_id, name, email, message) VALUES (?, ?, ?, ?)");
$stmt->execute([$car_id, $name, $email, $message]);
$msg = "Thank you! Your message has been sent. We will contact you shortly.";
}
?>
<section class="container" style="padding-top: 6rem;">
<div class="section-title">
<div>
<h1>Connect With Us</h1>
<p>Our specialists are ready to assist you with any inquiry.</p>
<div class="container mt-5">
<h1>Contact Us</h1>
<p class="mb-5">We are here to help you find your dream car.</p>
<?php if ($msg): ?>
<div style="background: rgba(42, 157, 143, 0.2); color: #2a9d8f; padding: 20px; border-radius: 10px; margin-bottom: 30px;">
<?= htmlspecialchars($msg) ?>
</div>
</div>
<div class="section-grid">
<div style="background: var(--surface-color); padding: 3.5rem; border-radius: var(--border-radius); border: 1px solid rgba(255,255,255,0.05);">
<h3 style="margin-bottom: 2.5rem; font-size: 1.8rem; color: var(--accent-color);">Direct Inquiry</h3>
<form action="#" method="POST">
<div class="grid" style="grid-template-columns: 1fr 1fr; gap: 2rem; margin-bottom: 0;">
<div class="form-group">
<label>First Name</label>
<input type="text" placeholder="Ahmad" required>
</div>
<div class="form-group">
<label>Last Name</label>
<input type="text" placeholder="Shah" required>
<?php endif; ?>
<div class="grid" style="grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 50px;">
<div>
<form method="POST">
<?php if ($inquiry_car): ?>
<div style="background: rgba(255,255,255,0.05); padding: 15px; border-radius: 5px; margin-bottom: 20px;">
<strong>Inquiry about:</strong> <?= htmlspecialchars($inquiry_car['year'] . ' ' . $inquiry_car['brand'] . ' ' . $inquiry_car['model']) ?>
<input type="hidden" name="car_id" value="<?= $inquiry_car['id'] ?>">
</div>
<?php endif; ?>
<div class="form-group">
<label>Your Name</label>
<input type="text" name="name" class="form-control" required>
</div>
<div class="form-group">
<label>Email Address</label>
<input type="email" placeholder="ahmad@domain.af" required>
<input type="email" name="email" class="form-control" required>
</div>
<div class="form-group">
<label>Inquiry Subject</label>
<select name="subject" style="width: 100%; padding: 1.2rem; background: var(--bg-color); border: 1px solid rgba(255,255,255,0.1); border-radius: 8px; color: white; outline: none; cursor: pointer;">
<option value="Purchase Interest" <?= strpos($subject, 'Purchase') !== false ? 'selected' : '' ?>>Purchase Interest</option>
<option value="Installment Inquiry" <?= strpos($subject, 'Installment') !== false ? 'selected' : '' ?>>Installment Inquiry</option>
<option value="Vehicle Valuation" <?= strpos($subject, 'Valuation') !== false ? 'selected' : '' ?>>Vehicle Valuation (Selling)</option>
<option value="Technical Support" <?= strpos($subject, 'Support') !== false ? 'selected' : '' ?>>Technical Support</option>
</select>
<label>Message</label>
<textarea name="message" class="form-control" rows="5" required><?= $inquiry_car ? "I am interested in this vehicle. Please provide more details." : "" ?></textarea>
</div>
<div class="form-group">
<label>Your Message</label>
<textarea name="message" rows="6" placeholder="<?= htmlspecialchars($message_placeholder) ?>" required></textarea>
</div>
<button type="submit" class="btn" style="width: 100%;">Send Message</button>
<button type="submit" class="btn">Send Message</button>
</form>
</div>
<div style="display: flex; flex-direction: column; gap: 3rem;">
<div class="location-card" style="border-style: solid;">
<h3><i class="fas fa-headset"></i> Premium Support</h3>
<div class="location-info">
<p><i class="fas fa-phone"></i> +93 700 000 000</p>
<p><i class="fas fa-envelope"></i> concierge@afgcars.af</p>
<p><i class="fas fa-clock"></i> 24/7 VIP Assistance Available</p>
</div>
</div>
<div>
<h3>Head Office</h3>
<p class="mb-5">Shar-e-Naw, Kabul, Afghanistan</p>
<div style="background: var(--surface-color); padding: 3rem; border-radius: var(--border-radius); border: 1px solid var(--border-color);">
<h3 style="margin-bottom: 2rem; color: var(--accent-color);">Regional Centers</h3>
<div style="display: flex; flex-direction: column; gap: 1.5rem;">
<div style="border-bottom: 1px solid rgba(255,255,255,0.05); padding-bottom: 1rem;">
<span style="color: var(--text-primary); font-weight: 800; display: block; margin-bottom: 0.3rem;">Kabul Headquarters</span>
<p style="font-size: 0.85rem; color: var(--text-secondary);">Shar-e-Naw Business District, Plaza 4, 2nd Floor</p>
</div>
<div style="border-bottom: 1px solid rgba(255,255,255,0.05); padding-bottom: 1rem;">
<span style="color: var(--text-primary); font-weight: 800; display: block; margin-bottom: 0.3rem;">Herat Regional Center</span>
<p style="font-size: 0.85rem; color: var(--text-secondary);">Main Commercial Avenue, Herat Gate</p>
</div>
<div>
<span style="color: var(--text-primary); font-weight: 800; display: block; margin-bottom: 0.3rem;">Mazar-i-Sharif Office</span>
<p style="font-size: 0.85rem; color: var(--text-secondary);">Balkh Gate Towers, Suite 102</p>
</div>
</div>
</div>
<h3>Phone</h3>
<p class="mb-5">+93 700 000 000</p>
<h3>Email</h3>
<p class="mb-5">info@afgcars.af</p>
<h3>Hours</h3>
<p>Sat - Thu: 8:00 AM - 6:00 PM</p>
<p>Friday: Closed</p>
</div>
</div>
</section>
</div>
<?php require_once __DIR__ . '/includes/footer.php'; ?>
<?php require_once 'includes/footer.php'; ?>

View File

@ -1,17 +1,22 @@
<?php
// Generated by setup_mariadb_project.sh — edit as needed.
// db/config.php
// Database Configuration
define('DB_HOST', '127.0.0.1');
define('DB_NAME', 'app_38474');
define('DB_USER', 'app_38474');
define('DB_PASS', '31621ed0-58d1-46b5-b7d0-9eb1e1abacf7');
function db() {
static $pdo;
if (!$pdo) {
$pdo = new PDO('mysql:host='.DB_HOST.';dbname='.DB_NAME.';charset=utf8mb4', DB_USER, DB_PASS, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);
}
return $pdo;
try {
$pdo = new PDO("mysql:host=" . DB_HOST . ";dbname=" . DB_NAME . ";charset=utf8mb4", DB_USER, DB_PASS);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
} catch (PDOException $e) {
die("Database Connection Failed: " . $e->getMessage());
}
// Global helper function if needed, but we can just use $pdo
function getDB() {
global $pdo;
return $pdo;
}

86
db/database.sql Normal file
View File

@ -0,0 +1,86 @@
-- Database Schema for AFG_CARS Enterprise System
SET FOREIGN_KEY_CHECKS=0;
DROP TABLE IF EXISTS `installments`;
DROP TABLE IF EXISTS `sales`;
DROP TABLE IF EXISTS `inquiries`;
DROP TABLE IF EXISTS `cars`;
DROP TABLE IF EXISTS `branches`;
DROP TABLE IF EXISTS `users`;
-- Users Table
CREATE TABLE `users` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR(100) NOT NULL,
`email` VARCHAR(100) NOT NULL UNIQUE,
`password` VARCHAR(255) NOT NULL,
`role` ENUM('admin', 'user') DEFAULT 'user',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Branches Table
CREATE TABLE `branches` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR(100) NOT NULL,
`city` VARCHAR(50) NOT NULL,
`address` TEXT,
`phone` VARCHAR(20)
);
-- Cars Table
CREATE TABLE `cars` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`branch_id` INT,
`brand` VARCHAR(50) NOT NULL,
`model` VARCHAR(50) NOT NULL,
`year` INT NOT NULL,
`price` DECIMAL(10, 2) NOT NULL,
`mileage` INT DEFAULT 0,
`fuel_type` VARCHAR(20) DEFAULT 'Petrol',
`transmission` VARCHAR(20) DEFAULT 'Automatic',
`description` TEXT,
`image_path` VARCHAR(255),
`status` ENUM('available', 'sold') DEFAULT 'available',
`is_featured` BOOLEAN DEFAULT 0,
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (`branch_id`) REFERENCES `branches`(`id`) ON DELETE SET NULL
);
-- Sales Table
CREATE TABLE `sales` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`car_id` INT NOT NULL,
`user_id` INT NOT NULL,
`sale_date` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
`sale_price` DECIMAL(10, 2) NOT NULL,
FOREIGN KEY (`car_id`) REFERENCES `cars`(`id`),
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`)
);
-- Installments Table
CREATE TABLE `installments` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`car_id` INT NOT NULL,
`user_id` INT NOT NULL,
`total_amount` DECIMAL(10, 2) NOT NULL,
`monthly_payment` DECIMAL(10, 2) NOT NULL,
`months` INT NOT NULL,
`status` ENUM('pending', 'approved', 'rejected', 'completed') DEFAULT 'pending',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (`car_id`) REFERENCES `cars`(`id`),
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`)
);
-- Inquiries/Contact Table
CREATE TABLE `inquiries` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`car_id` INT DEFAULT NULL,
`user_id` INT DEFAULT NULL,
`name` VARCHAR(100),
`email` VARCHAR(100),
`message` TEXT,
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (`car_id`) REFERENCES `cars`(`id`) ON DELETE SET NULL
);
SET FOREIGN_KEY_CHECKS=1;

View File

@ -1,44 +0,0 @@
<?php
require_once __DIR__ . '/../includes/role_middleware.php';
requireRole('Dealer');
require_once __DIR__ . '/../includes/header.php';
$pdo = db();
$dealerId = $_SESSION['user_id'];
// Stats
$myCars = $pdo->prepare("SELECT COUNT(*) FROM cars WHERE dealer_id = ?");
$myCars->execute([$dealerId]);
$myCarsCount = $myCars->fetchColumn();
$mySales = $pdo->prepare("SELECT COUNT(*) FROM sales s JOIN cars c ON s.car_id = c.id WHERE c.dealer_id = ?");
$mySales->execute([$dealerId]);
$mySalesCount = $mySales->fetchColumn();
?>
<div style="padding: 2rem;">
<div class="page-header">
<h1>Dealer Dashboard</h1>
<span>Welcome, <?php echo htmlspecialchars($_SESSION['username']); ?></span>
</div>
<div class="card-grid" style="grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1rem; margin-bottom: 2rem;">
<div class="stat-card" style="padding: 1.5rem; background: var(--card-bg); border: 1px solid var(--border-color); border-radius: var(--border-radius);">
<div style="font-size: 2rem; font-weight: bold;"><?php echo $myCarsCount; ?></div>
<div style="color: var(--text-secondary);">My Inventory</div>
</div>
<div class="stat-card" style="padding: 1.5rem; background: var(--card-bg); border: 1px solid var(--border-color); border-radius: var(--border-radius);">
<div style="font-size: 2rem; font-weight: bold;"><?php echo $mySalesCount; ?></div>
<div style="color: var(--text-secondary);">My Sales</div>
</div>
</div>
<div style="background: var(--card-bg); padding: 2rem; border-radius: var(--border-radius); border: 1px solid var(--border-color);">
<h3>Manage Inventory</h3>
<p>You can add new cars to your branch inventory here.</p>
<a href="/admin/cars.php" class="btn-sm btn-primary">Go to Inventory Management</a>
<!-- Ideally this would point to a dealer-specific car management page, but reusing admin/cars.php with permission checks is a good MVP step if implemented, otherwise a dedicated page is better. For now, let's keep it simple. -->
</div>
</div>
<?php require_once __DIR__ . '/../includes/footer.php'; ?>

View File

@ -1,51 +1,46 @@
<?php
session_start();
// includes/auth.php
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
require_once __DIR__ . '/../db/config.php';
// Check if user is logged in
function isLoggedIn() {
return isset($_SESSION['user_id']);
}
function isAdmin() {
return isLoggedIn() && (
$_SESSION['role'] === 'Admin' ||
$_SESSION['role'] === 'Super Admin' ||
$_SESSION['role'] === 'Manager'
);
// Get current user role
function getUserRole() {
return $_SESSION['user_role'] ?? 'guest';
}
function requireLogin() {
if (!isLoggedIn()) {
header('Location: /login.php');
exit;
}
// Get current user name
function getUserName() {
return $_SESSION['user_name'] ?? 'Guest';
}
function requireAdmin() {
requireLogin();
if (!isAdmin()) {
header('Location: /index.php');
exit;
}
}
function login($username, $password) {
$pdo = db();
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ? OR email = ?");
$stmt->execute([$username, $username]);
// Login function
function login($email, $password) {
global $pdo;
$stmt = $pdo->prepare("SELECT * FROM users WHERE email = ?");
$stmt->execute([$email]);
$user = $stmt->fetch();
if ($user && password_verify($password, $user['password'])) {
$_SESSION['user_id'] = $user['id'];
$_SESSION['username'] = $user['username'];
$_SESSION['role'] = $user['role'];
$_SESSION['user_name'] = $user['name'];
$_SESSION['user_email'] = $user['email'];
$_SESSION['user_role'] = $user['role'];
return true;
}
return false;
}
// Logout function
function logout() {
session_destroy();
header('Location: /login.php');
header("Location: login.php");
exit;
}

View File

@ -1,38 +1,37 @@
<footer>
<div class="footer-container">
<div class="footer-section">
<div class="logo">AFG_CARS<span>.</span></div>
<p>Afghanistan's premier automotive marketplace. Luxury, reliability, and excellence in every drive.</p>
<div class="social-links">
<a href="#"><i class="fab fa-facebook"></i></a>
<a href="#"><i class="fab fa-instagram"></i></a>
<a href="#"><i class="fab fa-twitter"></i></a>
<a href="#"><i class="fab fa-linkedin"></i></a>
<?php
// includes/footer.php
?>
<footer>
<div class="container">
<div class="grid" style="grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); text-align: left;">
<div>
<h3 style="color: var(--primary); margin-bottom: 15px;">AFG CARS</h3>
<p>Afghanistan's premier automotive marketplace. Luxury, reliability, and excellence in every drive.</p>
</div>
<div>
<h3 style="margin-bottom: 15px;">Quick Links</h3>
<ul style="line-height: 2;">
<li><a href="/index.php">Home</a></li>
<li><a href="/marketplace.php">Marketplace</a></li>
<li><a href="/work.php">How it Works</a></li>
<li><a href="/about.php">About Us</a></li>
<li><a href="/contact.php">Contact</a></li>
</ul>
</div>
<div>
<h3 style="margin-bottom: 15px;">Contact Info</h3>
<p>Shar-e-Naw, Kabul, Afghanistan</p>
<p>+93 700 000 000</p>
<p>info@afgcars.af</p>
<p>Sat - Thu: 8:00 AM - 6:00 PM</p>
</div>
</div>
<div style="margin-top: 50px; padding-top: 20px; border-top: 1px solid var(--glass-border); text-align: center; color: #888;">
<p>&copy; <?= date('Y') ?> AFG CARS - Elite Dealership System.</p>
<p style="font-size: 0.8rem; margin-top: 5px;">100% Offline | Enterprise Ready</p>
</div>
</div>
<div class="footer-section">
<h3>Quick Links</h3>
<ul>
<li><a href="index.php">Home</a></li>
<li><a href="marketplace.php">Marketplace</a></li>
<li><a href="work.php">How it Works</a></li>
<li><a href="about.php">About Us</a></li>
<li><a href="contact.php">Contact</a></li>
</ul>
</div>
<div class="footer-section">
<h3>Contact Info</h3>
<p><i class="fas fa-map-marker-alt"></i> Shar-e-Naw, Kabul, Afghanistan</p>
<p><i class="fas fa-phone"></i> +93 700 000 000</p>
<p><i class="fas fa-envelope"></i> info@afgcars.af</p>
<p><i class="fas fa-clock"></i> Sat - Thu: 8:00 AM - 6:00 PM</p>
</div>
</div>
<div class="footer-bottom">
<p>&copy; <?= date('Y') ?> AFG_CARS - Elite Dealership System. Developed by Mohammad Sadiq.</p>
<p style="font-size: 0.8rem; color: var(--text-secondary); margin-top: 0.5rem;">100% Offline | Enterprise Ready | Professional UI</p>
</div>
</footer>
</footer>
</body>
</html>

View File

@ -1,50 +1,40 @@
<?php
declare(strict_types=1);
require_once __DIR__ . '/../db/config.php';
require_once __DIR__ . '/init_db.php';
ensure_db_setup();
require_once __DIR__ . '/auth.php'; // Ensure session is started and auth helpers are available
$projectTitle = "AFG_CARS - Supreme Automotive";
$projectDescription = "Elite car dealership management system. Premium marketplace, installments, and branch management.";
$current_page = basename($_SERVER['PHP_SELF']);
// includes/header.php
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
require_once __DIR__ . '/auth.php';
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?= htmlspecialchars($projectTitle) ?></title>
<meta name="description" content="<?= htmlspecialchars($projectDescription) ?>">
<link rel="stylesheet" href="assets/css/style.css?v=<?= time() ?>">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<title>AFG CARS Enterprise</title>
<link rel="stylesheet" href="/assets/css/style.css">
</head>
<body>
<header>
<div class="logo">AFG_CARS<span>.</span></div>
<nav>
<ul>
<li><a href="index.php" <?= $current_page == 'index.php' ? 'class="active"' : '' ?>>Home</a></li>
<li><a href="marketplace.php" <?= $current_page == 'marketplace.php' ? 'class="active"' : '' ?>>Marketplace</a></li>
<li><a href="work.php" <?= $current_page == 'work.php' ? 'class="active"' : '' ?>>Work</a></li>
<li><a href="about.php" <?= $current_page == 'about.php' ? 'class="active"' : '' ?>>About</a></li>
<li><a href="contact.php" <?= $current_page == 'contact.php' ? 'class="active"' : '' ?>>Contact Us</a></li>
<?php if (isLoggedIn()): ?>
<?php
$dashboardLink = '/buyer/index.php'; // Default
if (isAdmin()) {
$dashboardLink = '/admin/index.php';
} elseif (isset($_SESSION['role']) && $_SESSION['role'] === 'Dealer') {
$dashboardLink = '/dealer/index.php';
}
?>
<li><a href="<?= $dashboardLink ?>" class="admin-link"><i class="fas fa-chart-line"></i> Dashboard</a></li>
<li><a href="/logout.php" class="admin-link"><i class="fas fa-sign-out-alt"></i> Logout</a></li>
<?php else: ?>
<li><a href="/login.php" class="admin-link"><i class="fas fa-user"></i> Login</a></li>
<?php endif; ?>
</ul>
<nav class="navbar">
<div class="container">
<a href="/index.php" class="logo">AFG CARS</a>
<div class="nav-links">
<a href="/index.php">Home</a>
<a href="/marketplace.php">Marketplace</a>
<a href="/about.php">About</a>
<a href="/work.php">Work</a>
<a href="/contact.php">Contact</a>
<?php if (isLoggedIn()): ?>
<?php if (getUserRole() === 'admin'): ?>
<a href="/admin/index.php" class="btn">Admin</a>
<?php else: ?>
<a href="#" class="btn-outline">My Account</a>
<?php endif; ?>
<a href="/logout.php" style="color: #e63946;">Logout</a>
<?php else: ?>
<a href="/login.php" class="btn">Login</a>
<?php endif; ?>
</div>
</div>
</nav>
</header>

19
includes/middleware.php Normal file
View File

@ -0,0 +1,19 @@
<?php
// includes/middleware.php
require_once __DIR__ . '/auth.php';
function requireLogin() {
if (!isLoggedIn()) {
header("Location: /login.php");
exit;
}
}
function requireAdmin() {
requireLogin();
if (getUserRole() !== 'admin') {
header("Location: /index.php"); // Or dashboard
exit;
}
}

View File

@ -1,27 +0,0 @@
<?php
function pexels_key() {
$k = getenv('PEXELS_KEY');
return $k && strlen($k) > 0 ? $k : 'Vc99rnmOhHhJAbgGQoKLZtsaIVfkeownoQNbTj78VemUjKh08ZYRbf18';
}
function pexels_get($url) {
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [ 'Authorization: '. pexels_key() ],
CURLOPT_TIMEOUT => 15,
]);
$resp = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($code >= 200 && $code < 300 && $resp) return json_decode($resp, true);
return null;
}
function download_to($srcUrl, $destPath) {
$data = file_get_contents($srcUrl);
if ($data === false) return false;
if (!is_dir(dirname($destPath))) mkdir(dirname($destPath), 0775, true);
return file_put_contents($destPath, $data) !== false;
}

222
index.php
View File

@ -1,94 +1,79 @@
<?php
declare(strict_types=1);
require_once __DIR__ . '/includes/header.php';
// index.php
require_once 'includes/auth.php';
require_once 'includes/header.php';
global $pdo;
// Fetch Featured Cars for Home Page
// Fetch Featured Cars
try {
$db = db();
$featured_cars = $db->query("SELECT c.*, b.name as branch_name
FROM cars c
JOIN branches b ON c.branch_id = b.id
WHERE c.status = 'Available' AND c.is_featured = 1
ORDER BY c.created_at DESC
LIMIT 6")->fetchAll();
$branches = $db->query("SELECT * FROM branches LIMIT 3")->fetchAll();
$stmt = $pdo->query("SELECT * FROM cars WHERE is_featured = 1 LIMIT 6");
$featured_cars = $stmt->fetchAll();
// Fetch branches for selector
$branches = $pdo->query("SELECT * FROM branches")->fetchAll();
} catch (Exception $e) {
$featured_cars = [];
$branches = [];
}
?>
<!-- 1. & 2. Hero Section & Background Design -->
<!-- Hero Section -->
<section class="hero">
<h1>Experience <span>Supreme</span> Luxury Automotive</h1>
<p>Afghanistan's premier destination for elite vehicles, flexible installments, and professional service across our major branches.</p>
<div class="hero-btns">
<a href="marketplace.php" class="btn">View Cars</a>
<a href="contact.php" class="btn btn-outline">Sell Your Car</a>
<div class="container">
<h1>Find Your Dream Car</h1>
<p>Premium Vehicles. Flexible Installments. Nationwide Service.</p>
<a href="marketplace.php" class="btn">Browse Inventory</a>
</div>
</section>
<!-- 6. Why Choose Us Section -->
<section class="container">
<div class="section-title">
<div>
<h2>Why Choose Us</h2>
<p>Our commitment to excellence makes us the market leader.</p>
<!-- Installment Calculator Section -->
<section class="container mt-5">
<h2 class="text-center">Installment Calculator</h2>
<div class="calculator">
<div class="grid" style="grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));">
<div class="form-group">
<label>Car Price ($)</label>
<input type="number" id="calcPrice" class="form-control" placeholder="30000" value="30000">
</div>
<div class="form-group">
<label>Down Payment ($)</label>
<input type="number" id="calcDown" class="form-control" placeholder="5000" value="5000">
</div>
<div class="form-group">
<label>Loan Term</label>
<select id="calcMonths" class="form-control">
<option value="12">12 Months</option>
<option value="24" selected>24 Months</option>
<option value="36">36 Months</option>
<option value="48">48 Months</option>
</select>
</div>
<div class="form-group" style="display: flex; align-items: flex-end;">
<button onclick="calculateInstallment()" class="btn" style="width: 100%;">Calculate</button>
</div>
</div>
</div>
<div class="grid">
<div class="feature-box">
<i class="fas fa-certificate"></i>
<h3>Trusted Dealership</h3>
<p>Over 10 years of excellence in the automotive industry with thousands of happy clients.</p>
</div>
<div class="feature-box">
<i class="fas fa-check-circle"></i>
<h3>Verified Listings</h3>
<p>Every vehicle undergoes a rigorous 150-point technical and background inspection.</p>
</div>
<div class="feature-box">
<i class="fas fa-shield-alt"></i>
<h3>Secure Transactions</h3>
<p>Safe, transparent, and legally binding payment processes for all vehicle sales.</p>
</div>
<div class="feature-box">
<i class="fas fa-bolt"></i>
<h3>Fast Approval</h3>
<p>Get your luxury car today with instant installment approval and minimal paperwork.</p>
<div id="calcResult" class="mt-5 text-center" style="font-size: 1.5rem; font-weight: bold; color: var(--primary);">
Monthly Payment: $1,145.83
</div>
</div>
</section>
<!-- 5. Featured Cars Section -->
<section class="container" style="background: var(--surface-color);">
<div class="section-title">
<div>
<h2>Featured Collection</h2>
<p>Hand-picked premium vehicles currently available in our showrooms.</p>
</div>
<a href="marketplace.php" class="btn btn-outline" style="padding: 0.8rem 1.5rem;">View All <i class="fas fa-arrow-right" style="margin-left: 10px;"></i></a>
</div>
<!-- Featured Cars -->
<section class="container mt-5">
<h2 class="text-center mb-5">Featured Vehicles</h2>
<div class="grid">
<?php foreach ($featured_cars as $car): ?>
<div class="car-card">
<div class="car-image">
<span class="car-badge">PREMIUM</span>
<img src="<?= htmlspecialchars($car['image_url']) ?>" alt="<?= htmlspecialchars($car['brand']) ?>">
</div>
<div class="car-content">
<div class="car-title"><?= htmlspecialchars($car['brand'] . ' ' . $car['model']) ?></div>
<div class="car-price">$<?= number_format((float)$car['price'], 0) ?></div>
<div class="car-meta">
<span><i class="fas fa-calendar-alt"></i> <?= $car['year'] ?></span>
<span><i class="fas fa-map-marker-alt"></i> <?= htmlspecialchars($car['branch_name']) ?></span>
<div class="card">
<img src="<?= htmlspecialchars($car['image_path'] ?? $car['image_url'] ?? '') ?>" alt="<?= htmlspecialchars($car['brand']) ?>">
<div class="card-body">
<h3 class="card-title"><?= htmlspecialchars($car['brand'] . ' ' . $car['model']) ?></h3>
<div class="card-price">$<?= number_format((float)$car['price']) ?></div>
<div class="card-meta">
<span><?= $car['year'] ?></span> •
<span><?= number_format((float)$car['mileage']) ?> km</span>
</div>
<div class="installment-box">
Installments from <strong>$<?= number_format($car['price'] / 60, 0) ?>/mo</strong>
</div>
<div style="margin-top: 1.5rem;">
<a href="car_details.php?id=<?= $car['id'] ?>" class="btn" style="width: 100%; padding: 0.8rem;">View Details</a>
<div class="card-actions">
<a href="car_detail.php?id=<?= $car['id'] ?>" class="btn btn-outline" style="width:100%">View Details</a>
</div>
</div>
</div>
@ -96,78 +81,37 @@ try {
</div>
</section>
<!-- 3. Review Section -->
<section class="container">
<div class="section-title">
<div>
<h2>Customer Reviews</h2>
<p>What our elite clientele says about their experience with AFG_CARS.</p>
</div>
</div>
<div class="grid">
<div class="review-card">
<div class="review-header">
<div class="customer-photo">AS</div>
<div>
<div style="font-weight: 800; font-size: 1.1rem;">Ahmad Shah</div>
<div style="font-size: 0.8rem; color: var(--accent-color);">Verified Buyer</div>
</div>
</div>
<div class="stars">
<i class="fas fa-star"></i><i class="fas fa-star"></i><i class="fas fa-star"></i><i class="fas fa-star"></i><i class="fas fa-star"></i>
</div>
<p style="color: var(--text-secondary);">"The best experience I've had buying a car in Kabul. The installment plan was very easy to understand and the team was extremely professional. Highly recommended!"</p>
</div>
<div class="review-card">
<div class="review-header">
<div class="customer-photo">MK</div>
<div>
<div style="font-weight: 800; font-size: 1.1rem;">Mariam Khan</div>
<div style="font-size: 0.8rem; color: var(--accent-color);">Business Owner</div>
</div>
</div>
<div class="stars">
<i class="fas fa-star"></i><i class="fas fa-star"></i><i class="fas fa-star"></i><i class="fas fa-star"></i><i class="fas fa-star"></i>
</div>
<p style="color: var(--text-secondary);">"Found my dream Lexus LX 600 here. The condition was exactly as described. The Herat branch team was very helpful with all the paperwork. 5 stars!"</p>
</div>
<div class="review-card">
<div class="review-header">
<div class="customer-photo">RZ</div>
<div>
<div style="font-weight: 800; font-size: 1.1rem;">Reza Zaki</div>
<div style="font-size: 0.8rem; color: var(--accent-color);">Verified Buyer</div>
</div>
</div>
<div class="stars">
<i class="fas fa-star"></i><i class="fas fa-star"></i><i class="fas fa-star"></i><i class="fas fa-star"></i><i class="fas fa-star"></i>
</div>
<p style="color: var(--text-secondary);">"Transparent pricing and high-quality inventory. I appreciate the technical reports they provided before I made my decision. Best dealership in Afghanistan."</p>
</div>
</div>
</section>
<!-- 4. Physical Location Section -->
<section class="container" style="background: var(--surface-color);">
<div class="section-title">
<div>
<h2>Dealership Locations</h2>
<p>Visit us at any of our modern showrooms across Afghanistan.</p>
</div>
</div>
<div class="grid">
<!-- Branch Selector -->
<section class="container mt-5 mb-5">
<h2 class="text-center mb-5">Visit Our Branches</h2>
<div class="grid" style="grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));">
<?php foreach ($branches as $branch): ?>
<div class="location-card">
<h3><i class="fas fa-city"></i> <?= htmlspecialchars($branch['city']) ?></h3>
<div class="location-info">
<p><i class="fas fa-map-marker-alt"></i> <?= htmlspecialchars($branch['address']) ?></p>
<p><i class="fas fa-phone"></i> <?= htmlspecialchars($branch['phone']) ?></p>
<p><i class="fas fa-clock"></i> <?= htmlspecialchars($branch['hours']) ?></p>
</div>
<a href="https://maps.google.com" target="_blank" class="btn btn-outline" style="width: 100%; margin-top: 1rem; padding: 0.8rem;">Open Map</a>
<div class="card" style="padding: 20px; text-align: center;">
<h3 style="color: var(--primary); margin-bottom: 10px;"><?= htmlspecialchars($branch['city']) ?></h3>
<p style="margin-bottom: 5px;"><?= htmlspecialchars($branch['name']) ?></p>
<p style="color: #aaa;"><?= htmlspecialchars($branch['phone']) ?></p>
<a href="contact.php?branch=<?= $branch['id'] ?>" class="btn-outline" style="margin-top: 15px; display: inline-block;">View Map</a>
</div>
<?php endforeach; ?>
</div>
</section>
<?php require_once __DIR__ . '/includes/footer.php'; ?>
<script>
function calculateInstallment() {
const price = parseFloat(document.getElementById('calcPrice').value);
const down = parseFloat(document.getElementById('calcDown').value);
const months = parseInt(document.getElementById('calcMonths').value);
if (price && months) {
const principal = price - (down || 0);
const interestRate = 0.05; // 5% flat rate
const total = principal * (1 + interestRate);
const monthly = total / months;
document.getElementById('calcResult').innerText =
`Monthly Payment: $${monthly.toFixed(2)}`;
}
}
</script>
<?php require_once 'includes/footer.php'; ?>

124
login.php
View File

@ -1,41 +1,27 @@
<?php
// login.php
require_once 'includes/auth.php';
if (isLoggedIn()) {
header("Location: index.php");
exit;
}
$error = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$username = $_POST['username'] ?? '';
$email = $_POST['email'] ?? '';
$password = $_POST['password'] ?? '';
if (login($username, $password)) {
$role = $_SESSION['role'] ?? 'Customer';
// Log login attempt
try {
$pdo = db();
$pdo->prepare("INSERT INTO activity_logs (user_id, action, ip_address) VALUES (?, 'Login', ?)")
->execute([$_SESSION['user_id'], $_SERVER['REMOTE_ADDR']]);
} catch (Exception $e) { /* Ignore logging error */ }
switch ($role) {
case 'Admin':
case 'Super Admin':
case 'Manager':
header('Location: /admin/index.php');
break;
case 'Dealer':
header('Location: /dealer/index.php');
break;
case 'Customer':
case 'Buyer':
header('Location: /buyer/index.php');
break;
default:
header('Location: /index.php');
if (login($email, $password)) {
if (getUserRole() === 'admin') {
header("Location: admin/index.php");
} else {
header("Location: index.php");
}
exit;
} else {
$error = "Invalid username or password";
$error = "Invalid email or password";
}
}
?>
@ -44,81 +30,35 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login - Car Market</title>
<title>Login - AFG CARS</title>
<link rel="stylesheet" href="assets/css/style.css">
<style>
body { display: flex; align-items: center; justify-content: center; min-height: 100vh; }
.login-container {
width: 100%;
max-width: 400px;
padding: 2.5rem;
background: var(--card-bg);
border-radius: var(--border-radius);
box-shadow: 0 8px 32px rgba(0,0,0,0.4);
border: 1px solid var(--border-color);
}
.form-group { margin-bottom: 1.5rem; }
label { display: block; margin-bottom: 0.5rem; color: var(--text-secondary); font-size: 0.9rem; }
input {
width: 100%;
padding: 0.8rem;
background: var(--bg-color);
border: 1px solid var(--border-color);
border-radius: 6px;
color: var(--text-primary);
font-size: 1rem;
}
input:focus { outline: none; border-color: var(--accent-color); }
button {
width: 100%;
padding: 0.8rem;
background: var(--accent-color);
border: none;
border-radius: 6px;
color: var(--bg-color);
font-weight: 700;
font-size: 1rem;
cursor: pointer;
transition: all 0.2s;
margin-top: 1rem;
}
button:hover { background: var(--accent-hover); transform: translateY(-1px); }
.error {
background: rgba(255, 68, 68, 0.1);
color: #ff4444;
padding: 0.8rem;
border-radius: 6px;
margin-bottom: 1.5rem;
text-align: center;
font-size: 0.9rem;
}
h2 { text-align: center; margin-bottom: 2rem; color: var(--accent-color); font-size: 1.8rem; }
.links { text-align: center; margin-top: 1.5rem; font-size: 0.9rem; color: var(--text-secondary); }
.links a { color: var(--accent-color); text-decoration: none; font-weight: 600; }
.links a:hover { text-decoration: underline; }
</style>
</head>
<body>
<div class="login-container">
<h2>Welcome Back</h2>
<body style="display: flex; align-items: center; justify-content: center; min-height: 100vh;">
<div class="auth-box">
<h1 class="logo mb-5">AFG CARS</h1>
<h2 class="mb-5">Login</h2>
<?php if ($error): ?>
<div class="error"><?php echo htmlspecialchars($error); ?></div>
<div style="background: rgba(230, 57, 70, 0.2); color: #e63946; padding: 10px; border-radius: 5px; margin-bottom: 20px;">
<?= htmlspecialchars($error) ?>
</div>
<?php endif; ?>
<form method="POST">
<div class="form-group">
<label>Username or Email</label>
<input type="text" name="username" required placeholder="Enter your username">
<input type="email" name="email" class="form-control" placeholder="Email Address" required>
</div>
<div class="form-group">
<label>Password</label>
<input type="password" name="password" required placeholder="Enter your password">
</div>
<button type="submit">Sign In</button>
<div class="links">
Don't have an account? <a href="register.php">Create Account</a><br>
<a href="/index.php" style="font-size: 0.8rem; opacity: 0.7;">Back to Home</a>
<input type="password" name="password" class="form-control" placeholder="Password" required>
</div>
<button type="submit" class="btn" style="width: 100%;">Sign In</button>
</form>
<p class="mt-5">
<a href="index.php" style="color: #aaa;">Back to Home</a>
</p>
</div>
</body>
</html>

View File

@ -1,235 +0,0 @@
<?php
// Minimal mail service for the workspace app (VM).
// Usage:
// require_once __DIR__ . '/MailService.php';
// // Generic:
// MailService::sendMail($to, $subject, $htmlBody, $textBody = null, $opts = []);
// // Contact form helper:
// MailService::sendContactMessage($name, $email, $message, $to = null, $subject = 'New contact form');
class MailService
{
// Universal mail sender (no attachments by design)
public static function sendMail($to, string $subject, string $htmlBody, ?string $textBody = null, array $opts = [])
{
$cfg = self::loadConfig();
$autoload = __DIR__ . '/../vendor/autoload.php';
if (file_exists($autoload)) {
require_once $autoload;
}
if (!class_exists('PHPMailer\\PHPMailer\\PHPMailer')) {
@require_once 'libphp-phpmailer/autoload.php';
if (!class_exists('PHPMailer\\PHPMailer\\PHPMailer')) {
@require_once 'libphp-phpmailer/src/Exception.php';
@require_once 'libphp-phpmailer/src/SMTP.php';
@require_once 'libphp-phpmailer/src/PHPMailer.php';
}
if (!class_exists('PHPMailer\\PHPMailer\\PHPMailer')) {
@require_once 'PHPMailer/src/Exception.php';
@require_once 'PHPMailer/src/SMTP.php';
@require_once 'PHPMailer/src/PHPMailer.php';
}
if (!class_exists('PHPMailer\\PHPMailer\\PHPMailer')) {
@require_once 'PHPMailer/Exception.php';
@require_once 'PHPMailer/SMTP.php';
@require_once 'PHPMailer/PHPMailer.php';
}
}
if (!class_exists('PHPMailer\\PHPMailer\\PHPMailer')) {
return [ 'success' => false, 'error' => 'PHPMailer not available' ];
}
$mail = new PHPMailer\PHPMailer\PHPMailer(true);
try {
$mail->isSMTP();
$mail->Host = $cfg['smtp_host'] ?? '';
$mail->Port = (int)($cfg['smtp_port'] ?? 587);
$secure = $cfg['smtp_secure'] ?? 'tls';
if ($secure === 'ssl') $mail->SMTPSecure = PHPMailer\PHPMailer\PHPMailer::ENCRYPTION_SMTPS;
elseif ($secure === 'tls') $mail->SMTPSecure = PHPMailer\PHPMailer\PHPMailer::ENCRYPTION_STARTTLS;
else $mail->SMTPSecure = false;
$mail->SMTPAuth = true;
$mail->Username = $cfg['smtp_user'] ?? '';
$mail->Password = $cfg['smtp_pass'] ?? '';
$fromEmail = $opts['from_email'] ?? ($cfg['from_email'] ?? 'no-reply@localhost');
$fromName = $opts['from_name'] ?? ($cfg['from_name'] ?? 'App');
$mail->setFrom($fromEmail, $fromName);
if (!empty($opts['reply_to']) && filter_var($opts['reply_to'], FILTER_VALIDATE_EMAIL)) {
$mail->addReplyTo($opts['reply_to']);
} elseif (!empty($cfg['reply_to'])) {
$mail->addReplyTo($cfg['reply_to']);
}
// Recipients
$toList = [];
if ($to) {
if (is_string($to)) $toList = array_map('trim', explode(',', $to));
elseif (is_array($to)) $toList = $to;
} elseif (!empty(getenv('MAIL_TO'))) {
$toList = array_map('trim', explode(',', getenv('MAIL_TO')));
}
$added = 0;
foreach ($toList as $addr) {
if (filter_var($addr, FILTER_VALIDATE_EMAIL)) { $mail->addAddress($addr); $added++; }
}
if ($added === 0) {
return [ 'success' => false, 'error' => 'No recipients defined (set MAIL_TO or pass $to)' ];
}
foreach ((array)($opts['cc'] ?? []) as $cc) { if (filter_var($cc, FILTER_VALIDATE_EMAIL)) $mail->addCC($cc); }
foreach ((array)($opts['bcc'] ?? []) as $bcc){ if (filter_var($bcc, FILTER_VALIDATE_EMAIL)) $mail->addBCC($bcc); }
// Optional DKIM
if (!empty($cfg['dkim_domain']) && !empty($cfg['dkim_selector']) && !empty($cfg['dkim_private_key_path'])) {
$mail->DKIM_domain = $cfg['dkim_domain'];
$mail->DKIM_selector = $cfg['dkim_selector'];
$mail->DKIM_private = $cfg['dkim_private_key_path'];
}
$mail->isHTML(true);
$mail->Subject = $subject;
$mail->Body = $htmlBody;
$mail->AltBody = $textBody ?? strip_tags($htmlBody);
$ok = $mail->send();
return [ 'success' => $ok ];
} catch (\Throwable $e) {
return [ 'success' => false, 'error' => 'PHPMailer error: ' . $e->getMessage() ];
}
}
private static function loadConfig(): array
{
$configPath = __DIR__ . '/config.php';
if (!file_exists($configPath)) {
throw new \RuntimeException('Mail config not found. Copy mail/config.sample.php to mail/config.php and fill in credentials.');
}
$cfg = require $configPath;
if (!is_array($cfg)) {
throw new \RuntimeException('Invalid mail config format: expected array');
}
return $cfg;
}
// Send a contact message
// $to can be: a single email string, a comma-separated list, an array of emails, or null (fallback to MAIL_TO/MAIL_FROM)
public static function sendContactMessage(string $name, string $email, string $message, $to = null, string $subject = 'New contact form')
{
$cfg = self::loadConfig();
// Try Composer autoload if available (for PHPMailer)
$autoload = __DIR__ . '/../vendor/autoload.php';
if (file_exists($autoload)) {
require_once $autoload;
}
// Fallback to system-wide PHPMailer (installed via apt: libphp-phpmailer)
if (!class_exists('PHPMailer\\PHPMailer\\PHPMailer')) {
// Debian/Ubuntu package layout (libphp-phpmailer)
@require_once 'libphp-phpmailer/autoload.php';
if (!class_exists('PHPMailer\\PHPMailer\\PHPMailer')) {
@require_once 'libphp-phpmailer/src/Exception.php';
@require_once 'libphp-phpmailer/src/SMTP.php';
@require_once 'libphp-phpmailer/src/PHPMailer.php';
}
// Alternative layout (older PHPMailer package names)
if (!class_exists('PHPMailer\\PHPMailer\\PHPMailer')) {
@require_once 'PHPMailer/src/Exception.php';
@require_once 'PHPMailer/src/SMTP.php';
@require_once 'PHPMailer/src/PHPMailer.php';
}
if (!class_exists('PHPMailer\\PHPMailer\\PHPMailer')) {
@require_once 'PHPMailer/Exception.php';
@require_once 'PHPMailer/SMTP.php';
@require_once 'PHPMailer/PHPMailer.php';
}
}
$transport = $cfg['transport'] ?? 'smtp';
if ($transport === 'smtp' && class_exists('PHPMailer\\PHPMailer\\PHPMailer')) {
return self::sendViaPHPMailer($cfg, $name, $email, $message, $to, $subject);
}
// Fallback: attempt native mail() — works only if MTA is configured on the VM
return self::sendViaNativeMail($cfg, $name, $email, $message, $to, $subject);
}
private static function sendViaPHPMailer(array $cfg, string $name, string $email, string $body, $to, string $subject)
{
$mail = new PHPMailer\PHPMailer\PHPMailer(true);
try {
$mail->isSMTP();
$mail->Host = $cfg['smtp_host'] ?? '';
$mail->Port = (int)($cfg['smtp_port'] ?? 587);
$secure = $cfg['smtp_secure'] ?? 'tls';
if ($secure === 'ssl') $mail->SMTPSecure = PHPMailer\PHPMailer\PHPMailer::ENCRYPTION_SMTPS;
elseif ($secure === 'tls') $mail->SMTPSecure = PHPMailer\PHPMailer\PHPMailer::ENCRYPTION_STARTTLS;
else $mail->SMTPSecure = false;
$mail->SMTPAuth = true;
$mail->Username = $cfg['smtp_user'] ?? '';
$mail->Password = $cfg['smtp_pass'] ?? '';
$fromEmail = $cfg['from_email'] ?? 'no-reply@localhost';
$fromName = $cfg['from_name'] ?? 'App';
$mail->setFrom($fromEmail, $fromName);
// Use Reply-To for the user's email to avoid spoofing From
if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
$mail->addReplyTo($email, $name ?: $email);
}
if (!empty($cfg['reply_to'])) {
$mail->addReplyTo($cfg['reply_to']);
}
// Destination: prefer dynamic recipients ($to), fallback to MAIL_TO; no silent FROM fallback
$toList = [];
if ($to) {
if (is_string($to)) {
// allow comma-separated list
$toList = array_map('trim', explode(',', $to));
} elseif (is_array($to)) {
$toList = $to;
}
} elseif (!empty(getenv('MAIL_TO'))) {
$toList = array_map('trim', explode(',', getenv('MAIL_TO')));
}
$added = 0;
foreach ($toList as $addr) {
if (filter_var($addr, FILTER_VALIDATE_EMAIL)) {
$mail->addAddress($addr);
$added++;
}
}
if ($added === 0) {
return [ 'success' => false, 'error' => 'No recipients defined (set MAIL_TO or pass $to)' ];
}
// DKIM (optional)
if (!empty($cfg['dkim_domain']) && !empty($cfg['dkim_selector']) && !empty($cfg['dkim_private_key_path'])) {
$mail->DKIM_domain = $cfg['dkim_domain'];
$mail->DKIM_selector = $cfg['dkim_selector'];
$mail->DKIM_private = $cfg['dkim_private_key_path'];
}
$mail->isHTML(true);
$mail->Subject = $subject;
$safeName = htmlspecialchars($name, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
$safeEmail = htmlspecialchars($email, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
$safeBody = nl2br(htmlspecialchars($body, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'));
$mail->Body = "<p><strong>Name:</strong> {$safeName}</p><p><strong>Email:</strong> {$safeEmail}</p><hr>{$safeBody}";
$mail->AltBody = "Name: {$name}\nEmail: {$email}\n\n{$body}";
$ok = $mail->send();
return [ 'success' => $ok ];
} catch (\Throwable $e) {
return [ 'success' => false, 'error' => 'PHPMailer error: ' . $e->getMessage() ];
}
}
private static function sendViaNativeMail(array $cfg, string $name, string $email, string $body, $to, string $subject)
{
$opts = ['reply_to' => $email];
$html = nl2br(htmlspecialchars($body, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'));
return self::sendMail($to, $subject, $html, $body, $opts);
}
}

View File

@ -1,76 +0,0 @@
<?php
// Mail configuration sourced from environment variables.
// No secrets are stored here; the file just maps env -> config array for MailService.
function env_val(string $key, $default = null) {
$v = getenv($key);
return ($v === false || $v === null || $v === '') ? $default : $v;
}
// Fallback: if critical vars are missing from process env, try to parse executor/.env
// This helps in web/Apache contexts where .env is not exported.
// Supports simple KEY=VALUE lines; ignores quotes and comments.
function load_dotenv_if_needed(array $keys): void {
$missing = array_filter($keys, fn($k) => getenv($k) === false || getenv($k) === '');
if (empty($missing)) return;
static $loaded = false;
if ($loaded) return;
$envPath = realpath(__DIR__ . '/../../.env'); // executor/.env
if ($envPath && is_readable($envPath)) {
$lines = @file($envPath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) ?: [];
foreach ($lines as $line) {
if ($line[0] === '#' || trim($line) === '') continue;
if (!str_contains($line, '=')) continue;
[$k, $v] = array_map('trim', explode('=', $line, 2));
// Strip potential surrounding quotes
$v = trim($v, "\"' ");
// Do not override existing env
if ($k !== '' && (getenv($k) === false || getenv($k) === '')) {
putenv("{$k}={$v}");
}
}
$loaded = true;
}
}
load_dotenv_if_needed([
'MAIL_TRANSPORT','SMTP_HOST','SMTP_PORT','SMTP_SECURE','SMTP_USER','SMTP_PASS',
'MAIL_FROM','MAIL_FROM_NAME','MAIL_REPLY_TO','MAIL_TO',
'DKIM_DOMAIN','DKIM_SELECTOR','DKIM_PRIVATE_KEY_PATH'
]);
$transport = env_val('MAIL_TRANSPORT', 'smtp');
$smtp_host = env_val('SMTP_HOST');
$smtp_port = (int) env_val('SMTP_PORT', 587);
$smtp_secure = env_val('SMTP_SECURE', 'tls'); // tls | ssl | null
$smtp_user = env_val('SMTP_USER');
$smtp_pass = env_val('SMTP_PASS');
$from_email = env_val('MAIL_FROM', 'no-reply@localhost');
$from_name = env_val('MAIL_FROM_NAME', 'App');
$reply_to = env_val('MAIL_REPLY_TO');
$dkim_domain = env_val('DKIM_DOMAIN');
$dkim_selector = env_val('DKIM_SELECTOR');
$dkim_private_key_path = env_val('DKIM_PRIVATE_KEY_PATH');
return [
'transport' => $transport,
// SMTP
'smtp_host' => $smtp_host,
'smtp_port' => $smtp_port,
'smtp_secure' => $smtp_secure,
'smtp_user' => $smtp_user,
'smtp_pass' => $smtp_pass,
// From / Reply-To
'from_email' => $from_email,
'from_name' => $from_name,
'reply_to' => $reply_to,
// DKIM (optional)
'dkim_domain' => $dkim_domain,
'dkim_selector' => $dkim_selector,
'dkim_private_key_path' => $dkim_private_key_path,
];

View File

@ -1,67 +1,101 @@
<?php
declare(strict_types=1);
require_once __DIR__ . '/includes/header.php';
// marketplace.php
require_once 'includes/auth.php';
require_once 'includes/header.php';
global $pdo;
// Fetch All Available Cars
// Fetch unique filter values
try {
$db = db();
$cars = $db->query("SELECT c.*, b.name as branch_name
FROM cars c
JOIN branches b ON c.branch_id = b.id
WHERE c.status = 'Available'
ORDER BY c.is_featured DESC, c.created_at DESC")->fetchAll();
$brands = $pdo->query("SELECT DISTINCT brand FROM cars ORDER BY brand")->fetchAll(PDO::FETCH_COLUMN);
$years = $pdo->query("SELECT DISTINCT year FROM cars ORDER BY year DESC")->fetchAll(PDO::FETCH_COLUMN);
} catch (Exception $e) {
$brands = [];
$years = [];
}
// Build Query
$where = ["status = 'available'"];
$params = [];
if (!empty($_GET['brand'])) {
$where[] = "brand = ?";
$params[] = $_GET['brand'];
}
if (!empty($_GET['year'])) {
$where[] = "year = ?";
$params[] = $_GET['year'];
}
if (!empty($_GET['max_price'])) {
$where[] = "price <= ?";
$params[] = $_GET['max_price'];
}
$sql = "SELECT * FROM cars WHERE " . implode(" AND ", $where) . " ORDER BY created_at DESC";
try {
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
$cars = $stmt->fetchAll();
} catch (Exception $e) {
$cars = [];
}
?>
<section class="container" style="padding-top: 4rem;">
<div class="section-title">
<div>
<h1>Premium Marketplace</h1>
<p>Explore our complete inventory of elite vehicles across Afghanistan.</p>
</div>
<div>
<span style="background: var(--accent-color); color: #000; padding: 0.6rem 1.2rem; border-radius: 30px; font-weight: 800; font-size: 0.8rem; border: 1px solid var(--border-color);">
<?= count($cars) ?> VEHICLES FOUND
</span>
</div>
</div>
<div class="container mt-5">
<h1>Marketplace</h1>
<p class="mb-5">Browse our premium selection of vehicles.</p>
<!-- Filter Bar -->
<form method="GET" class="filter-bar">
<select name="brand">
<option value="">All Brands</option>
<?php foreach ($brands as $b): ?>
<option value="<?= htmlspecialchars($b) ?>" <?= (isset($_GET['brand']) && $_GET['brand'] == $b) ? 'selected' : '' ?>>
<?= htmlspecialchars($b) ?>
</option>
<?php endforeach; ?>
</select>
<select name="year">
<option value="">All Years</option>
<?php foreach ($years as $y): ?>
<option value="<?= htmlspecialchars($y) ?>" <?= (isset($_GET['year']) && $_GET['year'] == $y) ? 'selected' : '' ?>>
<?= htmlspecialchars($y) ?>
</option>
<?php endforeach; ?>
</select>
<input type="number" name="max_price" placeholder="Max Price" value="<?= htmlspecialchars($_GET['max_price'] ?? '') ?>">
<button type="submit" class="btn">Filter</button>
<a href="marketplace.php" class="btn btn-outline" style="border: none; color: white;">Reset</a>
</form>
<div class="grid">
<?php foreach ($cars as $car): ?>
<div class="car-card">
<div class="car-image">
<?php if ($car['is_featured']): ?>
<span class="car-badge">FEATURED</span>
<?php endif; ?>
<img src="<?= htmlspecialchars($car['image_url']) ?>" alt="<?= htmlspecialchars($car['brand']) ?>">
</div>
<div class="car-content">
<div class="car-title"><?= htmlspecialchars($car['year'] . ' ' . $car['brand'] . ' ' . $car['model']) ?></div>
<div class="car-price">$<?= number_format((float)$car['price'], 0) ?></div>
<div class="car-meta">
<span><i class="fas fa-cog"></i> <?= htmlspecialchars($car['transmission'] ?? 'Auto') ?></span>
<span><i class="fas fa-tachometer-alt"></i> <?= number_format((float)$car['mileage'], 0) ?> KM</span>
<span><i class="fas fa-gas-pump"></i> <?= htmlspecialchars($car['fuel_type'] ?? 'Gas') ?></span>
</div>
<div class="car-meta">
<span><i class="fas fa-map-marker-alt"></i> <strong><?= htmlspecialchars($car['branch_name']) ?></strong></span>
</div>
<div class="installment-box">
Installment Plan: <strong>$<?= number_format($car['price'] / 60, 0) ?>/mo</strong> for 60 months
</div>
<div style="margin-top: 1.5rem;">
<a href="car_details.php?id=<?= $car['id'] ?>" class="btn" style="width: 100%;">View Details</a>
<?php if (count($cars) > 0): ?>
<?php foreach ($cars as $car): ?>
<div class="card">
<img src="<?= htmlspecialchars($car['image_path'] ?? $car['image_url'] ?? '') ?>" alt="<?= htmlspecialchars($car['brand']) ?>">
<div class="card-body">
<h3 class="card-title">
<?= htmlspecialchars($car['brand'] . ' ' . $car['model']) ?>
<?php if ($car['is_featured']): ?>
<span class="badge" style="float: right;">Featured</span>
<?php endif; ?>
</h3>
<div class="card-price">$<?= number_format((float)$car['price']) ?></div>
<div class="card-meta">
<?= $car['year'] ?> • <?= number_format((float)$car['mileage']) ?> km • <?= $car['fuel_type'] ?>
</div>
<div class="card-actions">
<a href="car_detail.php?id=<?= $car['id'] ?>" class="btn btn-outline" style="width:100%">View Details</a>
</div>
</div>
</div>
</div>
<?php endforeach; ?>
<?php endforeach; ?>
<?php else: ?>
<p>No cars found matching your criteria.</p>
<?php endif; ?>
</div>
</section>
</div>
<?php require_once __DIR__ . '/includes/footer.php'; ?>
<?php require_once 'includes/footer.php'; ?>

View File

@ -1,140 +0,0 @@
<?php
require_once 'includes/auth.php';
$error = '';
$success = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$username = $_POST['username'] ?? '';
$email = $_POST['email'] ?? '';
$password = $_POST['password'] ?? '';
$confirm_password = $_POST['confirm_password'] ?? '';
if ($password !== $confirm_password) {
$error = "Passwords do not match";
} else {
$pdo = db();
// Check if username exists
$stmt = $pdo->prepare("SELECT id FROM users WHERE username = ? OR email = ?");
$stmt->execute([$username, $email]);
if ($stmt->fetch()) {
$error = "Username or email already exists";
} else {
// Register user
$hash = password_hash($password, PASSWORD_DEFAULT);
$stmt = $pdo->prepare("INSERT INTO users (username, email, password, role) VALUES (?, ?, ?, 'Customer')");
try {
$stmt->execute([$username, $email, $hash]);
$success = "Registration successful!";
} catch (PDOException $e) {
$error = "Registration failed: " . $e->getMessage();
}
}
}
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Register - Car Market</title>
<link rel="stylesheet" href="assets/css/style.css">
<style>
body { display: flex; align-items: center; justify-content: center; min-height: 100vh; }
.register-container {
width: 100%;
max-width: 400px;
padding: 2.5rem;
background: var(--card-bg);
border-radius: var(--border-radius);
box-shadow: 0 8px 32px rgba(0,0,0,0.4);
border: 1px solid var(--border-color);
}
.form-group { margin-bottom: 1.2rem; }
label { display: block; margin-bottom: 0.4rem; color: var(--text-secondary); font-size: 0.9rem; }
input {
width: 100%;
padding: 0.8rem;
background: var(--bg-color);
border: 1px solid var(--border-color);
border-radius: 6px;
color: var(--text-primary);
font-size: 1rem;
}
input:focus { outline: none; border-color: var(--accent-color); }
button {
width: 100%;
padding: 0.8rem;
background: var(--accent-color);
border: none;
border-radius: 6px;
color: var(--bg-color);
font-weight: 700;
font-size: 1rem;
cursor: pointer;
transition: all 0.2s;
margin-top: 1rem;
}
button:hover { background: var(--accent-hover); transform: translateY(-1px); }
.error {
background: rgba(255, 68, 68, 0.1);
color: #ff4444;
padding: 0.8rem;
border-radius: 6px;
margin-bottom: 1.5rem;
text-align: center;
font-size: 0.9rem;
}
.success {
background: rgba(0, 200, 81, 0.1);
color: #00C851;
padding: 0.8rem;
border-radius: 6px;
margin-bottom: 1.5rem;
text-align: center;
font-size: 0.9rem;
}
h2 { text-align: center; margin-bottom: 2rem; color: var(--accent-color); font-size: 1.8rem; }
.links { text-align: center; margin-top: 1.5rem; font-size: 0.9rem; color: var(--text-secondary); }
.links a { color: var(--accent-color); text-decoration: none; font-weight: 600; }
.links a:hover { text-decoration: underline; }
</style>
</head>
<body>
<div class="register-container">
<h2>Create Account</h2>
<?php if ($error): ?>
<div class="error"><?php echo htmlspecialchars($error); ?></div>
<?php endif; ?>
<?php if ($success): ?>
<div class="success"><?php echo htmlspecialchars($success); ?></div>
<p style="text-align: center;"><a href="login.php" class="btn" style="color: var(--accent-color);">Proceed to Login</a></p>
<?php else: ?>
<form method="POST">
<div class="form-group">
<label>Username</label>
<input type="text" name="username" required>
</div>
<div class="form-group">
<label>Email</label>
<input type="email" name="email" required>
</div>
<div class="form-group">
<label>Password</label>
<input type="password" name="password" required>
</div>
<div class="form-group">
<label>Confirm Password</label>
<input type="password" name="confirm_password" required>
</div>
<button type="submit">Sign Up</button>
<div class="links">
Already have an account? <a href="login.php">Sign In</a><br>
<a href="/index.php" style="font-size: 0.8rem; opacity: 0.7;">Back to Home</a>
</div>
</form>
<?php endif; ?>
</div>
</body>
</html>

216
setup.php
View File

@ -1,142 +1,70 @@
<?php
// setup.php - Enterprise Setup Script
require_once __DIR__ . '/db/config.php';
echo "<h1>AFG CARS Enterprise Setup</h1>";
try {
$db = db();
global $pdo; // Assumes db/config.php creates $pdo
// Drop tables if they exist for a clean re-seed
$db->exec("SET FOREIGN_KEY_CHECKS = 0");
$db->exec("DROP TABLE IF EXISTS notifications");
$db->exec("DROP TABLE IF EXISTS activity_logs");
$db->exec("DROP TABLE IF EXISTS installments");
$db->exec("DROP TABLE IF EXISTS sales");
$db->exec("DROP TABLE IF EXISTS reviews");
$db->exec("DROP TABLE IF EXISTS car_images");
$db->exec("DROP TABLE IF EXISTS cars");
$db->exec("DROP TABLE IF EXISTS branches");
$db->exec("DROP TABLE IF EXISTS users");
$db->exec("SET FOREIGN_KEY_CHECKS = 1");
echo "<h3>1. Initializing Database Schema...</h3>";
// Read SQL file
$sql_file = __DIR__ . '/db/database.sql';
if (!file_exists($sql_file)) {
throw new Exception("Database SQL file not found at: $sql_file");
}
$sql_content = file_get_contents($sql_file);
// Split into individual queries (basic splitting by semicolon)
// Note: This is a simple splitter and might break on complex stored procedures, but sufficient for this schema.
$queries = explode(';', $sql_content);
foreach ($queries as $query) {
$query = trim($query);
if (!empty($query)) {
$pdo->exec($query);
}
}
echo "<p style='color:green'>Schema imported successfully.</p>";
echo "<h3>2. Seeding Data...</h3>";
// Seed Users (Admin & Customer)
// Check if admin exists to avoid duplicates if re-run
$stmt = $pdo->prepare("SELECT COUNT(*) FROM users WHERE email = ?");
$stmt->execute(['admin@afgcars.com']);
if ($stmt->fetchColumn() == 0) {
$password = password_hash('admin123', PASSWORD_DEFAULT);
$stmt = $pdo->prepare("INSERT INTO users (name, email, password, role) VALUES (?, ?, ?, ?)");
$stmt->execute(['Administrator', 'admin@afgcars.com', $password, 'admin']);
echo "<p>Admin user created (admin@afgcars.com / admin123)</p>";
}
// Create Branches table
$db->exec("CREATE TABLE branches (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
city VARCHAR(100) NOT NULL,
address VARCHAR(255),
phone VARCHAR(50),
hours VARCHAR(100)
)");
// Create Users table
$db->exec("CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(100) UNIQUE NOT NULL,
email VARCHAR(100) UNIQUE,
password VARCHAR(255) NOT NULL,
role ENUM('Guest', 'Customer', 'Dealer', 'Employee', 'Manager', 'Admin', 'Super Admin') DEFAULT 'Customer',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)");
// Create Cars table
$db->exec("CREATE TABLE cars (
id INT AUTO_INCREMENT PRIMARY KEY,
vin VARCHAR(50) UNIQUE NOT NULL,
brand VARCHAR(100) NOT NULL,
model VARCHAR(100) NOT NULL,
year INT NOT NULL,
price DECIMAL(15, 2) NOT NULL,
mileage INT NOT NULL,
transmission VARCHAR(50),
fuel_type VARCHAR(50),
status ENUM('Available', 'Reserved', 'Sold') DEFAULT 'Available',
branch_id INT,
dealer_id INT DEFAULT NULL,
installment_available BOOLEAN DEFAULT 0,
is_featured BOOLEAN DEFAULT 0,
image_url VARCHAR(255),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (branch_id) REFERENCES branches(id),
FOREIGN KEY (dealer_id) REFERENCES users(id)
)");
// Create Car Images table
$db->exec("CREATE TABLE car_images (
id INT AUTO_INCREMENT PRIMARY KEY,
car_id INT NOT NULL,
image_path VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (car_id) REFERENCES cars(id) ON DELETE CASCADE
)");
// Create Reviews table
$db->exec("CREATE TABLE reviews (
id INT AUTO_INCREMENT PRIMARY KEY,
car_id INT NOT NULL,
user_id INT NOT NULL,
rating INT NOT NULL CHECK (rating >= 1 AND rating <= 5),
comment TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (car_id) REFERENCES cars(id) ON DELETE CASCADE,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
)");
// Create Sales table
$db->exec("CREATE TABLE sales (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
car_id INT NOT NULL,
amount DECIMAL(15, 2) NOT NULL,
sale_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
status ENUM('Pending', 'Completed', 'Cancelled') DEFAULT 'Pending',
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (car_id) REFERENCES cars(id)
)");
// Create Installments table
$db->exec("CREATE TABLE installments (
id INT AUTO_INCREMENT PRIMARY KEY,
sale_id INT NOT NULL,
total_amount DECIMAL(15, 2) NOT NULL,
paid_amount DECIMAL(15, 2) DEFAULT 0,
monthly_payment DECIMAL(15, 2) NOT NULL,
status ENUM('Active', 'Completed', 'Overdue') DEFAULT 'Active',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (sale_id) REFERENCES sales(id) ON DELETE CASCADE
)");
// Create Activity Logs table
$db->exec("CREATE TABLE activity_logs (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT,
action VARCHAR(255) NOT NULL,
ip_address VARCHAR(50),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL
)");
// Create Notifications table
$db->exec("CREATE TABLE notifications (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
message TEXT NOT NULL,
is_read BOOLEAN DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
)");
$stmt->execute(['John Doe', 'user@example.com', password_hash('user123', PASSWORD_DEFAULT), 'user']);
echo "<p>Demo user created (user@example.com / user123)</p>";
// Seed Branches
// Tables are fresh from schema import, so no need to truncate
$branches = [
['Kabul Main', 'Kabul', 'Shar-e-Naw, Kabul', '+93 700 111 222', '08:00 AM - 06:00 PM'],
['Herat Branch', 'Herat', 'Main Road, Herat', '+93 700 333 444', '08:30 AM - 05:30 PM'],
['Mazar Center', 'Mazar-i-Sharif', 'Balkh Street, Mazar', '+93 700 555 666', '08:00 AM - 05:00 PM'],
['Kandahar Hub', 'Kandahar', 'Airport Road, Kandahar', '+93 700 777 888', '09:00 AM - 04:00 PM']
['Kabul Main', 'Kabul', 'Shar-e-Naw, Kabul', '+93 700 111 222'],
['Herat Branch', 'Herat', 'Main Road, Herat', '+93 700 333 444'],
['Mazar Center', 'Mazar-i-Sharif', 'Balkh Street, Mazar', '+93 700 555 666'],
['Kandahar Hub', 'Kandahar', 'Airport Road, Kandahar', '+93 700 777 888']
];
$stmt = $db->prepare("INSERT INTO branches (name, city, address, phone, hours) VALUES (?, ?, ?, ?, ?)");
$stmt = $pdo->prepare("INSERT INTO branches (name, city, address, phone) VALUES (?, ?, ?, ?)");
foreach ($branches as $branch) {
$stmt->execute($branch);
}
echo "<p>Branches seeded.</p>";
// Seed Cars
// $pdo->exec("SET FOREIGN_KEY_CHECKS=0");
// $pdo->exec("TRUNCATE TABLE cars");
// $pdo->exec("SET FOREIGN_KEY_CHECKS=1");
// Seed Cars (Exactly 20 Cars)
$brands = ['Toyota', 'Lexus', 'Mercedes-Benz', 'BMW', 'Audi', 'Land Rover', 'Porsche', 'Tesla'];
$models = [
'Toyota' => ['Camry', 'Land Cruiser', 'Corolla', 'RAV4'],
@ -149,40 +77,30 @@ try {
'Tesla' => ['Model S', 'Model X']
];
$stmt = $db->prepare("INSERT INTO cars (vin, brand, model, year, price, mileage, transmission, fuel_type, branch_id, is_featured, image_url, installment_available) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
$stmt = $pdo->prepare("INSERT INTO cars (brand, model, year, price, mileage, fuel_type, transmission, description, image_path, branch_id, is_featured, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
for ($i = 1; $i <= 20; $i++) {
$brand = $brands[array_rand($brands)];
$model = $models[$brand][array_rand($models[$brand])];
$year = rand(2020, 2024);
$price = rand(45000, 180000);
$mileage = rand(0, 15000);
$price = rand(25000, 150000);
$mileage = rand(0, 50000);
$fuel = rand(0, 1) ? 'Petrol' : 'Hybrid';
$desc = "Premium condition $brand $model. Full options, well maintained.";
$image = "assets/images/cars/car{$i}.jpg";
$branch_id = rand(1, 4);
$is_featured = ($i <= 8) ? 1 : 0; // 8 featured cars
$installment_available = rand(0, 1);
$image_url = "assets/images/cars/car{$i}.jpg";
$vin = "VIN" . str_pad((string)$i, 10, "0", STR_PAD_LEFT);
$is_featured = ($i <= 6) ? 1 : 0; // First 6 are featured
$stmt->execute([
$vin, $brand, $model, $year, $price, $mileage,
'Automatic', rand(0,1) ? 'Gasoline' : 'Hybrid',
$branch_id, $is_featured, $image_url, $installment_available
$brand, $model, $year, $price, $mileage, $fuel, 'Automatic',
$desc, $image, $branch_id, $is_featured, 'available'
]);
}
// Seed Admin
$stmt = $db->prepare("INSERT INTO users (username, password, role) VALUES (?, ?, ?)");
$stmt->execute(['admin', password_hash('admin123', PASSWORD_DEFAULT), 'Super Admin']);
// Create flag file for automated setup
file_put_contents(__DIR__ . '/db/setup_done.flag', date('Y-m-d H:i:s'));
echo "<h1>Setup Successful!</h1>";
echo "<p>Database recreated and exactly 20 premium cars seeded.</p>";
echo "<p><strong>Admin Credentials:</strong> admin / admin123</p>";
echo "<a href='index.php'>Go to Home Page</a>";
echo "<p>20 Demo cars seeded.</p>";
echo "<h3>Setup Complete!</h3>";
echo "<p><a href='index.php'>Go to Homepage</a></p>";
} catch (Exception $e) {
echo "<h1>Setup Failed</h1>";
echo "<p>" . $e->getMessage() . "</p>";
die("<h3 style='color:red'>Setup Failed: " . $e->getMessage() . "</h3>");
}

View File

@ -1,71 +1,46 @@
<?php
declare(strict_types=1);
require_once __DIR__ . '/includes/header.php';
// work.php
require_once 'includes/auth.php';
require_once 'includes/header.php';
?>
<section class="container" style="padding-top: 6rem;">
<div class="section-title">
<div>
<h1>How AFG_CARS Works</h1>
<p>A transparent, step-by-step guide to luxury vehicle ownership.</p>
</div>
<div class="container mt-5">
<div class="text-center mb-5">
<h1>How It Works</h1>
<p>Your journey to owning a luxury car in 4 simple steps.</p>
</div>
<div class="section-grid" style="margin-top: 4rem;">
<div style="background: var(--surface-color); padding: 4rem; border-radius: var(--border-radius); border: 1px solid var(--border-color);">
<h2 style="color: var(--accent-color); margin-bottom: 3rem; font-size: 2rem;">The Buying Process</h2>
<div style="display: flex; flex-direction: column; gap: 3rem;">
<div style="display: flex; gap: 2rem;">
<div style="width: 50px; height: 50px; background: var(--accent-color); color: #000; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: 900; flex-shrink: 0; font-size: 1.2rem;">1</div>
<div>
<h4 style="font-size: 1.2rem; margin-bottom: 0.5rem;">Online Exploration</h4>
<p style="color: var(--text-secondary);">Browse our live inventory with detailed specifications, history reports, and high-resolution images.</p>
</div>
</div>
<div style="display: flex; gap: 2rem;">
<div style="width: 50px; height: 50px; background: var(--accent-color); color: #000; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: 900; flex-shrink: 0; font-size: 1.2rem;">2</div>
<div>
<h4 style="font-size: 1.2rem; margin-bottom: 0.5rem;">Showroom Consultation</h4>
<p style="color: var(--text-secondary);">Visit our branch to experience the vehicle in person. Our specialists provide a full technical walk-through.</p>
</div>
</div>
<div style="display: flex; gap: 2rem;">
<div style="width: 50px; height: 50px; background: var(--accent-color); color: #000; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: 900; flex-shrink: 0; font-size: 1.2rem;">3</div>
<div>
<h4 style="font-size: 1.2rem; margin-bottom: 0.5rem;">Ownership & Handover</h4>
<p style="color: var(--text-secondary);">Finalize payment or installment documents. We handle all registration and deliver your car in pristine condition.</p>
</div>
</div>
</div>
<div class="grid" style="grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); text-align: center; gap: 30px;">
<div class="card" style="padding: 30px;">
<div style="font-size: 3rem; color: var(--primary); font-weight: bold; margin-bottom: 20px;">1</div>
<h3>Browse</h3>
<p>Explore our extensive inventory of premium vehicles online or visit one of our branches.</p>
</div>
<div style="background: var(--surface-color); padding: 4rem; border-radius: var(--border-radius); border: 1px solid rgba(255,255,255,0.05);">
<h2 style="color: var(--accent-color); margin-bottom: 3rem; font-size: 2rem;">The Selling Process</h2>
<div style="display: flex; flex-direction: column; gap: 3rem;">
<div style="display: flex; gap: 2rem;">
<div style="width: 50px; height: 50px; background: #fff; color: #000; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: 900; flex-shrink: 0; font-size: 1.2rem;">A</div>
<div>
<h4 style="font-size: 1.2rem; margin-bottom: 0.5rem;">Expert Evaluation</h4>
<p style="color: var(--text-secondary);">Submit your car details. Our team performs a comprehensive market and technical analysis to determine value.</p>
</div>
</div>
<div style="display: flex; gap: 2rem;">
<div style="width: 50px; height: 50px; background: #fff; color: #000; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: 900; flex-shrink: 0; font-size: 1.2rem;">B</div>
<div>
<h4 style="font-size: 1.2rem; margin-bottom: 0.5rem;">Guaranteed Offer</h4>
<p style="color: var(--text-secondary);">Receive a competitive buy-back or trade-in offer within 24 hours of inspection. No hidden fees.</p>
</div>
</div>
<div style="display: flex; gap: 2rem;">
<div style="width: 50px; height: 50px; background: #fff; color: #000; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: 900; flex-shrink: 0; font-size: 1.2rem;">C</div>
<div>
<h4 style="font-size: 1.2rem; margin-bottom: 0.5rem;">Secure Transfer</h4>
<p style="color: var(--text-secondary);">We handle all the legal paperwork and title transfers. Payment is released immediately upon agreement.</p>
</div>
</div>
</div>
<div class="card" style="padding: 30px;">
<div style="font-size: 3rem; color: var(--primary); font-weight: bold; margin-bottom: 20px;">2</div>
<h3>Select</h3>
<p>Choose your dream car and customize your payment plan using our installment calculator.</p>
</div>
<div class="card" style="padding: 30px;">
<div style="font-size: 3rem; color: var(--primary); font-weight: bold; margin-bottom: 20px;">3</div>
<h3>Apply</h3>
<p>Submit a request online or in-person. Our team will process your application quickly.</p>
</div>
<div class="card" style="padding: 30px;">
<div style="font-size: 3rem; color: var(--primary); font-weight: bold; margin-bottom: 20px;">4</div>
<h3>Drive</h3>
<p>Once approved, sign the paperwork and drive away in your new vehicle.</p>
</div>
</div>
</section>
<div class="mt-5 card" style="padding: 40px; text-align: center;">
<h2>Ready to get started?</h2>
<p class="mb-5">Browse our marketplace to find your perfect car today.</p>
<a href="marketplace.php" class="btn">View Inventory</a>
</div>
</div>
<?php require_once __DIR__ . '/includes/footer.php'; ?>
<?php require_once 'includes/footer.php'; ?>