015b1cf7b5
- Add @stripe/stripe-js + @stripe/react-stripe-js - New src/lib/stripe-client.ts: cached loadStripe helper - New src/actions/billing/retail-payment-intent.ts: server action that creates a PaymentIntent with automatic_payment_methods - New src/components/storefront/StripeExpressCheckout.tsx: embedded ExpressCheckoutElement (Apple Pay, Google Pay, Link, PayPal) + PaymentElement (card) + hosted-checkout fallback - /checkout form is now controlled; StripeExpressCheckout reads name/email/stop from form state and confirms in-page via stripe.confirmPayment - /checkout/success handles both ?session_id= and ?payment_intent= so embedded + hosted flows both land on the same order-creation page using the pending_checkout sessionStorage payload - Export StopInfo from CartContext and select 'time' on the stops fetch so the local Stop shape matches the context's StopInfo - QuickCartSheet express buttons are visual shortcuts only; /checkout auto-renders the real Apple Pay / Google Pay buttons Requires NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY for the embedded path; if missing the embedded section falls back to the hosted Stripe Checkout button. npx tsc --noEmit passes.
36 lines
1.2 KiB
TypeScript
36 lines
1.2 KiB
TypeScript
/**
|
|
* Browser-only Stripe.js loader.
|
|
*
|
|
* Reads `NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY` and returns a cached
|
|
* `loadStripe` promise. Never call this from a server component — it
|
|
* pulls in `@stripe/stripe-js` which depends on `window`.
|
|
*
|
|
* The published key is safe to ship to the browser; the secret key
|
|
* never leaves the server (see `src/actions/billing/retail-checkout.ts`).
|
|
*/
|
|
"use client";
|
|
|
|
import { loadStripe, type Stripe } from "@stripe/stripe-js";
|
|
|
|
let stripePromise: Promise<Stripe | null> | null = null;
|
|
|
|
/**
|
|
* Returns the cached Stripe.js promise, creating it on the first call.
|
|
* Returns `null` if the publishable key is not configured — callers
|
|
* should fall back to the hosted Stripe Checkout flow in that case.
|
|
*/
|
|
export function getStripe(): Promise<Stripe | null> | null {
|
|
if (typeof window === "undefined") return null;
|
|
const key = process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY;
|
|
if (!key) return null;
|
|
if (!stripePromise) {
|
|
stripePromise = loadStripe(key);
|
|
}
|
|
return stripePromise;
|
|
}
|
|
|
|
/** Synchronous check — useful for deciding whether to render Stripe Elements. */
|
|
export function hasStripePublishableKey(): boolean {
|
|
return Boolean(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY);
|
|
}
|