Switch to version 3: modified src/hooks/useCheckout.ts

This commit is contained in:
2026-03-03 04:54:59 +00:00
parent 819cf506ff
commit 79ee098180

View File

@@ -1,62 +1,117 @@
"use client";
import { useState } from "react";
import { Product } from "@/lib/api/product";
export interface CartItem {
id: string;
name: string;
price: number;
quantity: number;
}
export const useCheckout = () => {
const [cartItems, setCartItems] = useState<CartItem[]>([]);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const addToCart = (item: CartItem) => {
setCartItems((prev) => {
const existing = prev.find((i) => i.id === item.id);
if (existing) {
return prev.map((i) => (i.id === item.id ? { ...i, quantity: i.quantity + item.quantity } : i));
}
return [...prev, item];
});
};
const removeFromCart = (id: string) => {
setCartItems((prev) => prev.filter((item) => item.id !== id));
};
const updateQuantity = (id: string, quantity: number) => {
setCartItems((prev) =>
prev.map((item) => (item.id === id ? { ...item, quantity: Math.max(1, quantity) } : item))
);
};
const getTotal = () => {
return cartItems.reduce((total, item) => total + item.price * item.quantity, 0).toFixed(2);
};
const checkout = async () => {
setIsLoading(true);
try {
// Simulate checkout process
await new Promise((resolve) => setTimeout(resolve, 1000));
setCartItems([]);
} catch (err) {
setError(err instanceof Error ? err.message : "Checkout failed");
} finally {
setIsLoading(false);
}
};
return {
cartItems,
isLoading,
error,
addToCart,
removeFromCart,
updateQuantity,
getTotal,
checkout
};
export type CheckoutItem = {
productId: string;
quantity: number;
imageSrc?: string;
imageAlt?: string;
metadata?: {
brand?: string;
variant?: string;
rating?: number;
reviewCount?: string;
[key: string]: string | number | undefined;
};
};
export type CheckoutResult = {
success: boolean;
url?: string;
error?: string;
};
export function useCheckout() {
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const checkout = async (items: CheckoutItem[], options?: { successUrl?: string; cancelUrl?: string }): Promise<CheckoutResult> => {
const apiUrl = process.env.NEXT_PUBLIC_API_URL;
const projectId = process.env.NEXT_PUBLIC_PROJECT_ID;
if (!apiUrl || !projectId) {
const errorMsg = "NEXT_PUBLIC_API_URL or NEXT_PUBLIC_PROJECT_ID not configured";
setError(errorMsg);
return { success: false, error: errorMsg };
}
setIsLoading(true);
setError(null);
try {
const response = await fetch(`${apiUrl}/stripe/project/checkout-session`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
projectId,
items,
successUrl: options?.successUrl || window.location.href,
cancelUrl: options?.cancelUrl || window.location.href,
}),
});
if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
const errorMsg = errorData.message || `Request failed with status ${response.status}`;
setError(errorMsg);
return { success: false, error: errorMsg };
}
const data = await response.json();
if (data.data.url) {
window.location.href = data.data.url;
}
return { success: true, url: data.data.url };
} catch (err) {
const errorMsg = err instanceof Error ? err.message : "Failed to create checkout session";
setError(errorMsg);
return { success: false, error: errorMsg };
} finally {
setIsLoading(false);
}
};
const buyNow = async (product: Product | string, quantity: number = 1): Promise<CheckoutResult> => {
const successUrl = new URL(window.location.href);
successUrl.searchParams.set("success", "true");
if (typeof product === "string") {
return checkout([{ productId: product, quantity }], { successUrl: successUrl.toString() });
}
let metadata: CheckoutItem["metadata"] = {};
if (product.metadata && Object.keys(product.metadata).length > 0) {
const { imageSrc, imageAlt, images, ...restMetadata } = product.metadata;
metadata = restMetadata;
} else {
if (product.brand) metadata.brand = product.brand;
if (product.variant) metadata.variant = product.variant;
if (product.rating !== undefined) metadata.rating = product.rating;
if (product.reviewCount) metadata.reviewCount = product.reviewCount;
}
return checkout([{
productId: product.id,
quantity,
imageSrc: product.imageSrc,
imageAlt: product.imageAlt,
metadata: Object.keys(metadata).length > 0 ? metadata : undefined,
}], { successUrl: successUrl.toString() });
};
return {
checkout,
buyNow,
isLoading,
error,
clearError: () => setError(null),
};
}