139 lines
7.5 KiB
PHP
139 lines
7.5 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
require_once __DIR__ . '/app.php';
|
|
|
|
ensure_schema();
|
|
|
|
$requestId = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);
|
|
$request = $requestId ? fetch_request($requestId) : null;
|
|
|
|
if (!$request) {
|
|
http_response_code(404);
|
|
render_head(app_name() . ' | Request not found', 'The selected taxi request could not be found.', 'noindex,nofollow');
|
|
render_header();
|
|
?>
|
|
<section class="section-block">
|
|
<div class="container">
|
|
<div class="card-panel text-center py-5">
|
|
<h1 class="h3 mb-3">Request not found</h1>
|
|
<p class="text-secondary mb-4">The taxi flow may have expired or the link is incomplete.</p>
|
|
<a href="/" class="btn btn-dark">Create a new request</a>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
<?php
|
|
render_footer();
|
|
exit;
|
|
}
|
|
|
|
$recommendedOffers = hydrate_recommended_offers($request);
|
|
$bookedOffer = !empty($request['booked_offer_slug']) ? offer_by_slug((string) $request['booked_offer_slug']) : null;
|
|
$toast = isset($_GET['created']) ? 'Taxi confirmed. Recommendations are ready.' : null;
|
|
if (isset($_GET['booked'])) {
|
|
$toast = 'Booking confirmed and attributed to the taxi confirmation screen.';
|
|
}
|
|
|
|
render_head(app_name() . ' | Taxi confirmed', 'Taxi confirmation with contextual recommendations and one-click booking.');
|
|
render_header();
|
|
?>
|
|
<section class="section-block">
|
|
<div class="container">
|
|
<div class="row g-4 align-items-start">
|
|
<div class="col-lg-4">
|
|
<div class="card-panel sticky-summary">
|
|
<div class="eyebrow">Taxi confirmed</div>
|
|
<h1 class="h3 mb-3">Ride for <?= h($request['passenger_name']) ?></h1>
|
|
<dl class="summary-list mb-0">
|
|
<div>
|
|
<dt>Pickup</dt>
|
|
<dd><?= h($request['pickup_point']) ?></dd>
|
|
</div>
|
|
<div>
|
|
<dt>Destination</dt>
|
|
<dd><?= h(destination_label((string) $request['destination_area'])) ?></dd>
|
|
</div>
|
|
<div>
|
|
<dt>ETA</dt>
|
|
<dd><?= estimate_eta_minutes((string) $request['destination_area']) ?> min</dd>
|
|
</div>
|
|
<div>
|
|
<dt>Channel</dt>
|
|
<dd><?= h(source_channel_label((string) $request['source_channel'])) ?></dd>
|
|
</div>
|
|
<div>
|
|
<dt>Pickup time</dt>
|
|
<dd><?= h(date('d M Y · H:i', strtotime((string) $request['pickup_time']))) ?></dd>
|
|
</div>
|
|
</dl>
|
|
<div class="divider"></div>
|
|
<div class="small text-secondary">Attribution source: taxi confirmation screen · request #<?= (int) $request['id'] ?></div>
|
|
<div class="d-grid gap-2 mt-4">
|
|
<a href="/request_detail.php?id=<?= (int) $request['id'] ?>" class="btn btn-outline-dark">View request detail</a>
|
|
<a href="/" class="btn btn-light border">Create another request</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-8">
|
|
<div class="card-panel mb-3">
|
|
<div class="card-head">
|
|
<div>
|
|
<div class="eyebrow">Top 3 contextual offers</div>
|
|
<h2 class="h4 mb-1">Recommended for the confirmed route</h2>
|
|
<p class="text-secondary mb-0">Scored by destination fit, time window, quality, and simple strategic weighting.</p>
|
|
</div>
|
|
<span class="badge rounded-pill <?= h(status_badge_class((string) $request['status'])) ?>"><?= h(str_replace('_', ' ', (string) $request['status'])) ?></span>
|
|
</div>
|
|
</div>
|
|
<?php if ($bookedOffer): ?>
|
|
<div class="alert alert-success d-flex gap-3 align-items-start" role="alert">
|
|
<i class="bi bi-check-circle-fill fs-4"></i>
|
|
<div>
|
|
<div class="fw-semibold">Booking confirmed: <?= h($bookedOffer['title']) ?></div>
|
|
<div class="small">This booking is stored as a conversion from the taxi confirmation flow.</div>
|
|
</div>
|
|
</div>
|
|
<?php endif; ?>
|
|
<div class="row g-3">
|
|
<?php foreach ($recommendedOffers as $offer): ?>
|
|
<div class="col-md-6 col-xl-4">
|
|
<article class="offer-card h-100 <?= $bookedOffer && $bookedOffer['slug'] === $offer['slug'] ? 'offer-card-active' : '' ?>">
|
|
<div class="d-flex justify-content-between align-items-start gap-3">
|
|
<div>
|
|
<div class="small text-secondary text-uppercase mb-2"><?= h($offer['sector']) ?></div>
|
|
<h3 class="h5 mb-2"><?= h($offer['title']) ?></h3>
|
|
</div>
|
|
<span class="score-pill">Score <?= (int) ($offer['score'] ?? 0) ?></span>
|
|
</div>
|
|
<p class="text-secondary offer-copy"><?= h($offer['description']) ?></p>
|
|
<ul class="list-unstyled offer-meta mb-3">
|
|
<li><i class="bi bi-geo-alt"></i> <?= h($offer['location']) ?></li>
|
|
<li><i class="bi bi-clock"></i> <?= h($offer['duration']) ?> · <?= h($offer['availability']) ?></li>
|
|
<li><i class="bi bi-currency-euro"></i> From €<?= (int) $offer['price_from'] ?> · Commission <?= h($offer['commission']) ?></li>
|
|
</ul>
|
|
<div class="reason-stack mb-3">
|
|
<?php foreach (($offer['reasons'] ?? []) as $reason): ?>
|
|
<span class="reason-pill"><?= h($reason) ?></span>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
<div class="small text-secondary mb-3">Meeting point: <?= h($offer['meeting_point']) ?></div>
|
|
<?php if ($bookedOffer && $bookedOffer['slug'] === $offer['slug']): ?>
|
|
<button class="btn btn-success w-100" type="button" disabled>Booked from taxi flow</button>
|
|
<?php else: ?>
|
|
<form method="post" action="/book_offer.php" class="d-grid">
|
|
<input type="hidden" name="request_id" value="<?= (int) $request['id'] ?>">
|
|
<input type="hidden" name="offer_slug" value="<?= h($offer['slug']) ?>">
|
|
<button type="submit" class="btn btn-dark book-offer-btn">Book this offer</button>
|
|
</form>
|
|
<?php endif; ?>
|
|
</article>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
<?php render_footer($toast); ?>
|