feat(checkout): real Stripe Express + Elements on /checkout
- 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.
This commit is contained in:
@@ -20,6 +20,8 @@ type StopInfo = {
|
||||
brand_id: string;
|
||||
};
|
||||
|
||||
export type { StopInfo };
|
||||
|
||||
type CartContextType = {
|
||||
cart: CartItem[];
|
||||
subtotal: number;
|
||||
@@ -334,7 +336,7 @@ export function CartProvider({ children }: { children: ReactNode }) {
|
||||
);
|
||||
}
|
||||
|
||||
export function useCart() {
|
||||
export function useCart(): CartContextType {
|
||||
const context = useContext(CartContext);
|
||||
if (!context) throw new Error("useCart must be used inside CartProvider");
|
||||
return context;
|
||||
|
||||
Reference in New Issue
Block a user