Files
myron 5637b6d7f5 CSS modularization Phase 2: account, cart, checkout
Extract account/cart/checkout styles into dedicated CSS files; remove inline styles and orphaned style blocks from HTML. Wire $extraHead on all account pages, cart.php, and checkout.php.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 17:51:57 +00:00

343 lines
15 KiB
PHP

<?php
/**
* Tom's Java Jive - Checkout Page
*/
$pageTitle = "Checkout - Tom's Java Jive";
require_once __DIR__ . '/includes/functions.php';
require_once __DIR__ . '/includes/auth.php';
$cart = getCart();
if (empty($cart)) {
redirect('/cart.php');
}
$customer = CustomerAuth::getFullUser();
$cartItems = [];
$subtotal = 0;
// Get product details for cart items
foreach ($cart as $productId => $quantity) {
$product = db()->fetch(
"SELECT product_id, name, price, sale_price, stock, images FROM products WHERE product_id = :id AND is_active = 1",
['id' => $productId]
);
if ($product) {
$images = json_decode($product['images'] ?? '[]', true);
$product['image'] = !empty($images) ? $images[0] : '/assets/images/placeholder-product.svg';
$product['quantity'] = min($quantity, $product['stock']);
$product['unit_price'] = $product['sale_price'] ?? $product['price'];
$product['total'] = $product['unit_price'] * $product['quantity'];
$subtotal += $product['total'];
$cartItems[] = $product;
}
}
// Get shipping settings
$shippingSettings = getSetting('shipping', [
'flat_rate_enabled' => true,
'flat_rate_amount' => 5.99,
'free_shipping_threshold' => 50
]);
$shippingCost = 0;
if ($shippingSettings['flat_rate_enabled'] ?? true) {
if ($subtotal >= ($shippingSettings['free_shipping_threshold'] ?? 50)) {
$shippingCost = 0;
} else {
$shippingCost = $shippingSettings['flat_rate_amount'] ?? 5.99;
}
}
$total = $subtotal + $shippingCost;
// Get Stripe publishable key
$stripeKey = STRIPE_PUBLISHABLE_KEY;
$errors = [];
// Handle form submission
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Validate form
$email = trim($_POST['email'] ?? '');
$name = trim($_POST['name'] ?? '');
$phone = trim($_POST['phone'] ?? '');
$address = trim($_POST['address'] ?? '');
$city = trim($_POST['city'] ?? '');
$state = trim($_POST['state'] ?? '');
$zip = trim($_POST['zip'] ?? '');
if (empty($email)) $errors['email'] = 'Email is required';
if (empty($name)) $errors['name'] = 'Name is required';
if (empty($address)) $errors['address'] = 'Address is required';
if (empty($city)) $errors['city'] = 'City is required';
if (empty($state)) $errors['state'] = 'State is required';
if (empty($zip)) $errors['zip'] = 'ZIP code is required';
if (empty($errors)) {
// Create order
$orderId = generateId('ord_');
$orderNumber = generateOrderNumber();
// Get or create customer
$customerId = null;
if ($customer) {
$customerId = $customer['customer_id'];
} else {
$customerId = CustomerAuth::createGuest($email, $name, $phone);
}
// Prepare order items
$orderItems = [];
foreach ($cartItems as $item) {
$orderItems[] = [
'product_id' => $item['product_id'],
'name' => $item['name'],
'price' => $item['unit_price'],
'quantity' => $item['quantity'],
'total' => $item['total']
];
}
// Insert order
db()->insert('orders', [
'order_id' => $orderId,
'order_number' => $orderNumber,
'customer_id' => $customerId,
'customer_email' => $email,
'customer_name' => $name,
'customer_phone' => $phone,
'items' => json_encode($orderItems),
'subtotal' => $subtotal,
'shipping_cost' => $shippingCost,
'total' => $total,
'shipping_address' => json_encode([
'address' => $address,
'city' => $city,
'state' => $state,
'zip' => $zip,
'country' => 'USA'
]),
'shipping_method' => 'standard',
'payment_method' => 'stripe',
'payment_status' => 'pending',
'order_status' => 'pending'
]);
// Insert order items for reporting
foreach ($orderItems as $item) {
db()->insert('order_items', [
'order_id' => $orderId,
'product_id' => $item['product_id'],
'name' => $item['name'],
'price' => $item['price'],
'quantity' => $item['quantity'],
'total' => $item['total']
]);
}
// Reduce stock
foreach ($cartItems as $item) {
db()->query(
"UPDATE products SET stock = stock - :qty WHERE product_id = :id",
['qty' => $item['quantity'], 'id' => $item['product_id']]
);
}
// Store order ID for payment
$_SESSION['pending_order_id'] = $orderId;
// Redirect to payment page
redirect('/payment.php?order=' . $orderId);
}
}
$metaTitle = "Secure Checkout | Tom's Java Jive";
$metaDescription = 'Complete your coffee order with secure checkout.';
$canonicalUrl = 'https://tomsjavajive.com/checkout.php';
$metaRobots = "noindex, nofollow";
$suppressSchema = true;
$extraHead = '<link rel="stylesheet" href="/assets/css/checkout.css?v=' . filemtime(__DIR__ . '/assets/css/checkout.css') . '">';
require_once __DIR__ . '/includes/header.php';
?>
<section class="section" style="padding-top: 2rem;">
<div class="container">
<h1 style="margin-bottom: 2rem;">Checkout</h1>
<form method="POST" action="" id="checkout-form">
<div class="checkout-layout">
<!-- Customer & Shipping Info -->
<div>
<!-- Contact Information -->
<div class="card mb-2">
<div class="card-header">
<h3 style="margin: 0;">Contact Information</h3>
</div>
<div class="card-body">
<?php if ($customer): ?>
<p>Logged in as <strong><?= htmlspecialchars($customer['email']) ?></strong></p>
<input type="hidden" name="email" value="<?= htmlspecialchars($customer['email']) ?>">
<input type="hidden" name="name" value="<?= htmlspecialchars($customer['name']) ?>">
<?php else: ?>
<div class="form-group">
<label class="form-label">Email Address *</label>
<input type="email" name="email" class="form-input"
value="<?= htmlspecialchars($_POST['email'] ?? '') ?>" required>
<?php if (isset($errors['email'])): ?>
<span class="form-error"><?= $errors['email'] ?></span>
<?php endif; ?>
</div>
<div class="form-group">
<label class="form-label">Full Name *</label>
<input type="text" name="name" class="form-input"
value="<?= htmlspecialchars($_POST['name'] ?? '') ?>" required>
<?php if (isset($errors['name'])): ?>
<span class="form-error"><?= $errors['name'] ?></span>
<?php endif; ?>
</div>
<div class="form-group mb-0">
<label class="form-label">Phone (Optional)</label>
<input type="tel" name="phone" class="form-input"
value="<?= htmlspecialchars($_POST['phone'] ?? '') ?>">
</div>
<p class="text-muted mt-1" style="font-size: 0.875rem;">
Already have an account? <a href="/login.php">Sign in</a>
</p>
<?php endif; ?>
</div>
</div>
<!-- Shipping Address -->
<div class="card mb-2">
<div class="card-header">
<h3 style="margin: 0;">Shipping Address</h3>
</div>
<div class="card-body">
<?php
$savedAddress = $customer ? json_decode($customer['shipping_address'] ?? '{}', true) : [];
?>
<div class="form-group">
<label class="form-label">Street Address *</label>
<input type="text" name="address" class="form-input"
value="<?= htmlspecialchars($_POST['address'] ?? $savedAddress['address'] ?? '') ?>" required>
<?php if (isset($errors['address'])): ?>
<span class="form-error"><?= $errors['address'] ?></span>
<?php endif; ?>
</div>
<div class="address-grid">
<div class="form-group">
<label class="form-label">City *</label>
<input type="text" name="city" class="form-input"
value="<?= htmlspecialchars($_POST['city'] ?? $savedAddress['city'] ?? '') ?>" required>
<?php if (isset($errors['city'])): ?>
<span class="form-error"><?= $errors['city'] ?></span>
<?php endif; ?>
</div>
<div class="form-group">
<label class="form-label">State *</label>
<input type="text" name="state" class="form-input"
value="<?= htmlspecialchars($_POST['state'] ?? $savedAddress['state'] ?? '') ?>" required>
<?php if (isset($errors['state'])): ?>
<span class="form-error"><?= $errors['state'] ?></span>
<?php endif; ?>
</div>
<div class="form-group">
<label class="form-label">ZIP *</label>
<input type="text" name="zip" class="form-input"
value="<?= htmlspecialchars($_POST['zip'] ?? $savedAddress['zip'] ?? '') ?>" required>
<?php if (isset($errors['zip'])): ?>
<span class="form-error"><?= $errors['zip'] ?></span>
<?php endif; ?>
</div>
</div>
</div>
</div>
<!-- Order Notes -->
<div class="card">
<div class="card-header">
<h3 style="margin: 0;">Order Notes (Optional)</h3>
</div>
<div class="card-body">
<textarea name="notes" class="form-textarea" placeholder="Special delivery instructions..."
style="min-height: 80px;"></textarea>
</div>
</div>
</div>
<!-- Order Summary -->
<div class="card checkout-summary">
<div class="card-header">
<h3 style="margin: 0;">Order Summary</h3>
</div>
<div class="card-body">
<!-- Cart Items -->
<div class="checkout-items-preview">
<?php foreach ($cartItems as $item): ?>
<div class="checkout-item">
<img src="<?= htmlspecialchars($item['image']) ?>" alt=""
class="checkout-item-img">
<div class="checkout-item-info">
<p><?= htmlspecialchars($item['name']) ?></p>
<small><?= formatCurrency($item['unit_price']) ?> x <?= $item['quantity'] ?></small>
</div>
<div class="checkout-item-total">
<?= formatCurrency($item['total']) ?>
</div>
</div>
<?php endforeach; ?>
</div>
<!-- Totals -->
<div class="checkout-summary-row">
<span>Subtotal</span>
<span><?= formatCurrency($subtotal) ?></span>
</div>
<div class="checkout-summary-row">
<span>Shipping</span>
<span>
<?php if ($shippingCost == 0): ?>
<span class="text-success">FREE</span>
<?php else: ?>
<?= formatCurrency($shippingCost) ?>
<?php endif; ?>
</span>
</div>
<hr style="margin: 1rem 0;">
<div class="checkout-summary-total">
<span>Total</span>
<span><?= formatCurrency($total) ?></span>
</div>
<button type="submit" class="btn btn-primary btn-lg btn-block mt-2">
Continue to Payment
</button>
<a href="/cart.php" class="btn btn-secondary btn-block mt-1">
<i class="fas fa-arrow-left"></i> Back to Cart
</a>
<p class="secure-badge">
<i class="fas fa-lock"></i> Secure checkout powered by Stripe
</p>
</div>
</div>
</div>
</form>
</div>
</section>
<?php require_once __DIR__ . '/includes/footer.php'; ?>