256 lines
8.8 KiB
PHP
256 lines
8.8 KiB
PHP
<?php
|
|
/**
|
|
* Demo: Product Detail Page
|
|
* Shows how to embed paypal-checkout-widget.php on a product/menu item page.
|
|
*
|
|
* In your real app, replace the hardcoded $school, $product, and $buyer values
|
|
* with data from your session and database.
|
|
*/
|
|
|
|
require_once __DIR__ . '/demo-helper.php';
|
|
|
|
// ── In your real app these come from session / DB ─────────────────────────────
|
|
// Auto-resolve to a PayPal-connected school so the buttons actually render.
|
|
// (Pass ?school=Name to force a specific connected school.)
|
|
$school = pp_demo_resolve_school($_GET['school'] ?? null);
|
|
$schoolReady = $school !== null;
|
|
$schoolLabel = $school ?? 'Demo School';
|
|
$buyerEmail = ''; // e.g. $_SESSION['user']['email']
|
|
|
|
$product = [
|
|
'name' => 'Monthly Lunch Plan — October',
|
|
'description' => '20 school days · hot lunch + drink',
|
|
'price' => '1.00',
|
|
'currency' => 'USD',
|
|
'image' => '🍱',
|
|
];
|
|
// ── End of real-app variables ─────────────────────────────────────────────────
|
|
|
|
// Build the $ppCheckout array the widget expects
|
|
$ppCheckout = [
|
|
'school_name' => $schoolLabel,
|
|
'amount' => $product['price'],
|
|
'currency' => $product['currency'],
|
|
'items' => [[
|
|
'name' => $product['name'],
|
|
'quantity' => '1',
|
|
'unit_amount' => ['currency_code' => $product['currency'], 'value' => $product['price']],
|
|
]],
|
|
'buyer_email' => $buyerEmail,
|
|
'page_type' => 'product-details', // tells PayPal which page the buyer is on
|
|
'order_api_url' => './order-api.php',
|
|
'success_url' => './demo-success.php?school=' . urlencode($schoolLabel),
|
|
'cancel_url' => '',
|
|
];
|
|
?>
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title><?= htmlspecialchars($product['name']) ?> — <?= htmlspecialchars($schoolLabel) ?></title>
|
|
<style>
|
|
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
body {
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
background: #f7f8fa;
|
|
color: #1a202c;
|
|
}
|
|
|
|
/* ── Top bar ── */
|
|
.topbar {
|
|
background: #fff;
|
|
border-bottom: 1px solid #e2e8f0;
|
|
padding: 14px 24px;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
}
|
|
.topbar-logo { font-size: 22px; }
|
|
.topbar-name { font-weight: 700; font-size: 17px; color: #003087; }
|
|
.topbar-school { font-size: 13px; color: #718096; margin-left: auto; }
|
|
|
|
/* ── Layout ── */
|
|
.page { max-width: 960px; margin: 32px auto; padding: 0 20px; display: grid; grid-template-columns: 1fr 420px; gap: 32px; }
|
|
@media (max-width: 700px) { .page { grid-template-columns: 1fr; } }
|
|
|
|
/* ── Product card ── */
|
|
.product-card {
|
|
background: #fff;
|
|
border-radius: 12px;
|
|
border: 1px solid #e2e8f0;
|
|
overflow: hidden;
|
|
}
|
|
.product-hero {
|
|
background: linear-gradient(135deg, #ebf4ff, #e6fffa);
|
|
padding: 40px;
|
|
text-align: center;
|
|
font-size: 80px;
|
|
}
|
|
.product-body { padding: 24px; }
|
|
.product-badge {
|
|
display: inline-block;
|
|
background: #ebf4ff;
|
|
color: #003087;
|
|
font-size: 11px;
|
|
font-weight: 700;
|
|
text-transform: uppercase;
|
|
letter-spacing: .5px;
|
|
padding: 3px 10px;
|
|
border-radius: 20px;
|
|
margin-bottom: 10px;
|
|
}
|
|
.product-name { font-size: 22px; font-weight: 700; margin-bottom: 8px; }
|
|
.product-desc { font-size: 14px; color: #718096; line-height: 1.6; margin-bottom: 20px; }
|
|
.product-features { list-style: none; margin-bottom: 24px; }
|
|
.product-features li {
|
|
font-size: 14px;
|
|
color: #4a5568;
|
|
padding: 6px 0;
|
|
border-bottom: 1px solid #f0f0f0;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
}
|
|
.product-features li::before { content: '✓'; color: #38a169; font-weight: 700; }
|
|
|
|
/* ── Checkout panel ── */
|
|
.checkout-panel {
|
|
background: #fff;
|
|
border-radius: 12px;
|
|
border: 1px solid #e2e8f0;
|
|
padding: 24px;
|
|
height: fit-content;
|
|
position: sticky;
|
|
top: 24px;
|
|
}
|
|
.checkout-price { font-size: 32px; font-weight: 700; color: #1a202c; margin-bottom: 4px; }
|
|
.checkout-price-sub { font-size: 13px; color: #718096; margin-bottom: 24px; }
|
|
.checkout-divider { border: none; border-top: 1px solid #e2e8f0; margin: 20px 0; }
|
|
|
|
/* ── Card payment fallback (below widget divider) ── */
|
|
.card-section h4 { font-size: 14px; font-weight: 600; color: #4a5568; margin-bottom: 14px; }
|
|
.card-field {
|
|
border: 1.5px solid #e2e8f0;
|
|
border-radius: 8px;
|
|
padding: 11px 14px;
|
|
font-size: 15px;
|
|
width: 100%;
|
|
margin-bottom: 12px;
|
|
color: #a0aec0;
|
|
}
|
|
.card-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
|
|
.btn-card {
|
|
width: 100%;
|
|
padding: 13px;
|
|
background: #2d3748;
|
|
color: #fff;
|
|
border: none;
|
|
border-radius: 8px;
|
|
font-size: 15px;
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
margin-top: 4px;
|
|
}
|
|
.btn-card:hover { background: #1a202c; }
|
|
.secure-note {
|
|
text-align: center;
|
|
font-size: 12px;
|
|
color: #a0aec0;
|
|
margin-top: 14px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 4px;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<nav class="topbar">
|
|
<span class="topbar-logo">🍽️</span>
|
|
<span class="topbar-name">HotLunches</span>
|
|
<span class="topbar-school"><?= htmlspecialchars($schoolLabel) ?></span>
|
|
</nav>
|
|
|
|
<div class="page">
|
|
|
|
<!-- Left: product info -->
|
|
<div>
|
|
<div class="product-card">
|
|
<div class="product-hero"><?= $product['image'] ?></div>
|
|
<div class="product-body">
|
|
<span class="product-badge">Lunch Plan</span>
|
|
<h1 class="product-name"><?= htmlspecialchars($product['name']) ?></h1>
|
|
<p class="product-desc"><?= htmlspecialchars($product['description']) ?></p>
|
|
<ul class="product-features">
|
|
<li>Hot meal prepared fresh daily</li>
|
|
<li>Allergen information included</li>
|
|
<li>Weekly menu sent every Friday</li>
|
|
<li>Full refund if plan cancelled before start date</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Right: checkout panel -->
|
|
<div>
|
|
<div class="checkout-panel">
|
|
|
|
<div class="checkout-price">$<?= htmlspecialchars($product['price']) ?></div>
|
|
<div class="checkout-price-sub">per student · October 2025</div>
|
|
<?php
|
|
/* Pay Later message near price — shows "Pay in 4 payments of $X" (placement: product) */
|
|
$ppMessage = [
|
|
'school_name' => $schoolLabel,
|
|
'amount' => $product['price'],
|
|
'currency' => $product['currency'],
|
|
'placement' => 'product',
|
|
'page_type' => 'product-details',
|
|
];
|
|
require_once __DIR__ . '/paypal-paylater-message.php';
|
|
?>
|
|
|
|
<?php if (!$schoolReady): ?>
|
|
<div style="background:#fffaf0;border:1px solid #feebc8;color:#9c4221;border-radius:10px;padding:14px 16px;font-size:13px;line-height:1.6;margin-bottom:16px;">
|
|
<strong>No PayPal-connected school found.</strong><br>
|
|
The checkout buttons appear once a school has completed PayPal onboarding.
|
|
Connect one in <a href="index.php" style="color:#9c4221;font-weight:600;">School Merchant Setup</a>,
|
|
or open this page as <code>?school=<connected school name></code>.
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<?php
|
|
/*
|
|
* ══════════════════════════════════════════════════════
|
|
* PAYPAL WIDGET — rendered FIRST, above card payment.
|
|
* The widget outputs:
|
|
* 1. FraudNet (hidden)
|
|
* 2. "We accept PayPal and Venmo" banner
|
|
* 3. PayPal + Venmo + Pay Later buttons
|
|
* 4. "── or pay another way ──" divider
|
|
* Card section below appears under that divider.
|
|
* ══════════════════════════════════════════════════════
|
|
*/
|
|
require_once __DIR__ . '/paypal-checkout-widget.php';
|
|
?>
|
|
|
|
<!-- Card payment — shown below the widget divider -->
|
|
<div class="card-section">
|
|
<h4>Pay with card</h4>
|
|
<input class="card-field" type="text" placeholder="Card number" disabled>
|
|
<div class="card-row">
|
|
<input class="card-field" type="text" placeholder="MM / YY" disabled>
|
|
<input class="card-field" type="text" placeholder="CVV" disabled>
|
|
</div>
|
|
<button class="btn-card" disabled>Pay $<?= htmlspecialchars($product['price']) ?></button>
|
|
<p class="secure-note">🔒 Secured by PayPal</p>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</body>
|
|
</html>
|