126 lines
6.5 KiB
PHP
126 lines
6.5 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
session_start();
|
|
require_once __DIR__ . '/includes/leads.php';
|
|
|
|
$projectName = $_SERVER['PROJECT_NAME'] ?? 'Northline Studio';
|
|
$projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Admin lead detail for agency quote requests.';
|
|
$projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
|
|
$accessKey = getenv('ADMIN_ACCESS_KEY') ?: '';
|
|
$demoMode = $accessKey === '';
|
|
$authenticated = $demoMode || !empty($_SESSION['admin_ok']);
|
|
if (!$authenticated) {
|
|
header('Location: admin.php');
|
|
exit;
|
|
}
|
|
if (empty($_SESSION['admin_csrf'])) {
|
|
$_SESSION['admin_csrf'] = bin2hex(random_bytes(32));
|
|
}
|
|
$statuses = lead_statuses();
|
|
$id = isset($_GET['id']) ? (int)$_GET['id'] : (int)($_POST['id'] ?? 0);
|
|
$error = null;
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
$token = (string)($_POST['csrf'] ?? '');
|
|
if ($token === '' || !hash_equals((string)$_SESSION['admin_csrf'], $token)) {
|
|
$error = 'The form expired. Please try again.';
|
|
} else {
|
|
try {
|
|
update_lead($id, (string)($_POST['status'] ?? 'new'), (string)($_POST['admin_notes'] ?? ''));
|
|
header('Location: admin_lead.php?id=' . $id . '&saved=1');
|
|
exit;
|
|
} catch (Throwable $e) {
|
|
error_log('Lead update failed: ' . $e->getMessage());
|
|
$error = 'Could not update the lead.';
|
|
}
|
|
}
|
|
}
|
|
|
|
try {
|
|
$lead = $id > 0 ? get_lead($id) : null;
|
|
} catch (Throwable $e) {
|
|
error_log('Lead detail load failed: ' . $e->getMessage());
|
|
$lead = null;
|
|
$error = 'Lead data is unavailable.';
|
|
}
|
|
function h(?string $value): string { return htmlspecialchars((string)$value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); }
|
|
function status_label(array $statuses, string $status): string { return $statuses[$status] ?? ucfirst($status); }
|
|
?>
|
|
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title><?= $lead ? 'Lead #' . h((string)$lead['id']) : 'Lead Not Found' ?> | <?= h($projectName) ?></title>
|
|
<?php if ($projectDescription): ?>
|
|
<meta name="description" content="<?= h($projectDescription) ?>">
|
|
<meta property="og:description" content="<?= h($projectDescription) ?>">
|
|
<meta property="twitter:description" content="<?= h($projectDescription) ?>">
|
|
<?php endif; ?>
|
|
<?php if ($projectImageUrl): ?>
|
|
<meta property="og:image" content="<?= h($projectImageUrl) ?>">
|
|
<meta property="twitter:image" content="<?= h($projectImageUrl) ?>">
|
|
<?php endif; ?>
|
|
<meta name="robots" content="noindex, nofollow">
|
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
<link rel="stylesheet" href="assets/css/custom.css?v=2026052901">
|
|
</head>
|
|
<body class="admin-shell">
|
|
<header class="site-header">
|
|
<nav class="navbar">
|
|
<div class="container">
|
|
<a class="navbar-brand" href="/"><span class="brand-mark" aria-hidden="true">N</span><?= h($projectName) ?></a>
|
|
<div class="d-flex gap-2"><a class="btn btn-outline-dark btn-sm" href="admin.php">Dashboard</a><a class="btn btn-dark btn-sm" href="/#quote">New quote</a></div>
|
|
</div>
|
|
</nav>
|
|
</header>
|
|
<main class="container py-4 py-md-5">
|
|
<?php if ($error): ?><div class="alert alert-danger"><?= h($error) ?></div><?php endif; ?>
|
|
<?php if (!$lead): ?>
|
|
<section class="admin-card empty-state"><h1 class="h3">Lead not found</h1><p>The requested lead may not exist.</p><a class="btn btn-dark" href="admin.php">Back to dashboard</a></section>
|
|
<?php else: ?>
|
|
<div class="d-flex flex-column flex-md-row justify-content-between gap-2 mb-3">
|
|
<div><p class="eyebrow">Lead #<?= h((string)$lead['id']) ?></p><h1 class="h2 mb-1"><?= h($lead['name']) ?></h1><p class="text-secondary mb-0"><?= h($lead['service']) ?> · <?= h(date('M j, Y H:i', strtotime($lead['created_at']))) ?></p></div>
|
|
<span class="badge-soft align-self-md-start"><?= h(status_label($statuses, $lead['status'])) ?></span>
|
|
</div>
|
|
<div class="row g-3">
|
|
<div class="col-lg-7">
|
|
<section class="detail-panel h-100">
|
|
<h2 class="h4">Request details</h2>
|
|
<div class="detail-meta my-3">
|
|
<div><span>Email</span><a href="mailto:<?= h($lead['email']) ?>"><?= h($lead['email']) ?></a></div>
|
|
<div><span>Phone</span><?= h($lead['phone'] ?: 'Not provided') ?></div>
|
|
<div><span>Company</span><?= h($lead['company'] ?: 'Not provided') ?></div>
|
|
<div><span>Budget</span><?= h($lead['budget'] ?: 'Not sure') ?></div>
|
|
<div><span>Timeline</span><?= h($lead['timeline'] ?: 'Flexible') ?></div>
|
|
<div><span>Source</span><?= h($lead['source'] ?: 'website') ?></div>
|
|
</div>
|
|
<h3 class="h5">Project notes</h3>
|
|
<p class="mb-0"><?= nl2br(h($lead['message'])) ?></p>
|
|
</section>
|
|
</div>
|
|
<div class="col-lg-5">
|
|
<form class="detail-panel needs-validation" method="post" action="admin_lead.php" novalidate>
|
|
<input type="hidden" name="csrf" value="<?= h($_SESSION['admin_csrf']) ?>">
|
|
<input type="hidden" name="id" value="<?= h((string)$lead['id']) ?>">
|
|
<h2 class="h4">Follow-up</h2>
|
|
<label class="form-label" for="status">Status</label>
|
|
<select class="form-select mb-3" id="status" name="status">
|
|
<?php foreach ($statuses as $key => $label): ?>
|
|
<option value="<?= h($key) ?>" <?= $lead['status'] === $key ? 'selected' : '' ?>><?= h($label) ?></option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
<label class="form-label" for="admin_notes">Internal notes</label>
|
|
<textarea class="form-control" id="admin_notes" name="admin_notes" rows="8" placeholder="Add call notes, next action, or proposal context."><?= h($lead['admin_notes'] ?? '') ?></textarea>
|
|
<button class="btn btn-dark w-100 mt-3" type="submit">Save lead</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
<?php endif; ?>
|
|
</main>
|
|
<div class="toast-container position-fixed bottom-0 end-0 p-3"><div id="siteToast" class="toast" role="status" aria-live="polite" aria-atomic="true"><div class="toast-header"><strong class="me-auto">Dashboard</strong><button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button></div><div class="toast-body">Saved.</div></div></div>
|
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
|
<script src="assets/js/main.js?v=2026052901" defer></script>
|
|
</body>
|
|
</html>
|