"use client"; import { useState, useEffect } from "react"; import { useRouter } from "next/navigation"; import Link from "next/link"; import Image from "next/image"; import { useTranslations, useLocale } from "next-intl"; import Header from "@/components/layout/Header"; import Footer from "@/components/layout/Footer"; import { useSaleorCheckoutStore } from "@/stores/saleorCheckoutStore"; import { formatPrice } from "@/lib/saleor"; import { saleorClient } from "@/lib/saleor/client"; import { useAnalytics } from "@/lib/analytics"; import { CHECKOUT_SHIPPING_ADDRESS_UPDATE, CHECKOUT_BILLING_ADDRESS_UPDATE, CHECKOUT_COMPLETE, CHECKOUT_EMAIL_UPDATE, CHECKOUT_METADATA_UPDATE, CHECKOUT_SHIPPING_METHOD_UPDATE, } from "@/lib/saleor/mutations/Checkout"; import { GET_CHECKOUT_BY_ID } from "@/lib/saleor/queries/Checkout"; import type { Checkout } from "@/types/saleor"; interface ShippingAddressUpdateResponse { checkoutShippingAddressUpdate?: { checkout?: Checkout; errors?: Array<{ message: string }>; }; } interface BillingAddressUpdateResponse { checkoutBillingAddressUpdate?: { checkout?: Checkout; errors?: Array<{ message: string }>; }; } interface CheckoutCompleteResponse { checkoutComplete?: { order?: { number: string }; errors?: Array<{ message: string }>; }; } interface EmailUpdateResponse { checkoutEmailUpdate?: { checkout?: Checkout; errors?: Array<{ message: string }>; }; } interface MetadataUpdateResponse { updateMetadata?: { item?: { id: string; metadata?: Array<{ key: string; value: string }>; }; errors?: Array<{ message: string }>; }; } interface ShippingMethodUpdateResponse { checkoutShippingMethodUpdate?: { checkout?: Checkout; errors?: Array<{ message: string }>; }; } interface CheckoutQueryResponse { checkout?: Checkout; } interface ShippingMethod { id: string; name: string; price: { amount: number; currency: string; }; } interface AddressForm { firstName: string; lastName: string; streetAddress1: string; streetAddress2: string; city: string; postalCode: string; country: string; phone: string; email: string; } export default function CheckoutPage() { const t = useTranslations("Checkout"); const locale = useLocale(); const router = useRouter(); const { checkout, refreshCheckout, getLines, getTotal } = useSaleorCheckoutStore(); const { trackCheckoutStarted, trackCheckoutStep, trackOrderCompleted, identifyUser } = useAnalytics(); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); const [orderComplete, setOrderComplete] = useState(false); const [orderNumber, setOrderNumber] = useState(null); const [sameAsShipping, setSameAsShipping] = useState(true); const [shippingAddress, setShippingAddress] = useState({ firstName: "", lastName: "", streetAddress1: "", streetAddress2: "", city: "", postalCode: "", country: "RS", phone: "", email: "", }); const [billingAddress, setBillingAddress] = useState({ firstName: "", lastName: "", streetAddress1: "", streetAddress2: "", city: "", postalCode: "", country: "RS", phone: "", email: "", }); const [shippingMethods, setShippingMethods] = useState([]); const [selectedShippingMethod, setSelectedShippingMethod] = useState(""); const [showShippingMethods, setShowShippingMethods] = useState(false); const lines = getLines(); const total = getTotal(); useEffect(() => { if (!checkout) { refreshCheckout(); } }, [checkout, refreshCheckout]); // Track checkout started when page loads useEffect(() => { if (checkout) { const lines = getLines(); const total = getTotal(); trackCheckoutStarted({ total, currency: "RSD", item_count: lines.reduce((sum, line) => sum + line.quantity, 0), items: lines.map(line => ({ id: line.variant.id, name: line.variant.product.name, quantity: line.quantity, price: line.variant.pricing?.price?.gross?.amount || 0, })), }); } }, [checkout]); // Scroll to top when order is complete useEffect(() => { if (orderComplete) { window.scrollTo({ top: 0, behavior: "smooth" }); } }, [orderComplete]); const handleShippingChange = (field: keyof AddressForm, value: string) => { setShippingAddress((prev) => ({ ...prev, [field]: value })); if (sameAsShipping && field !== "email") { setBillingAddress((prev) => ({ ...prev, [field]: value })); } }; const handleBillingChange = (field: keyof AddressForm, value: string) => { setBillingAddress((prev) => ({ ...prev, [field]: value })); }; const handleEmailChange = (value: string) => { setShippingAddress((prev) => ({ ...prev, email: value })); }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!checkout) { setError(t("errorNoCheckout")); return; } if (!shippingAddress.email || !shippingAddress.email.includes("@")) { setError(t("errorEmailRequired")); return; } if (!shippingAddress.firstName || !shippingAddress.lastName || !shippingAddress.streetAddress1 || !shippingAddress.city || !shippingAddress.postalCode || !shippingAddress.phone) { setError(t("errorFieldsRequired")); return; } setIsLoading(true); setError(null); try { // If we're showing shipping methods and one is selected, complete the order if (showShippingMethods && selectedShippingMethod) { console.log("Phase 2: Completing order with shipping method..."); console.log("Step 1: Updating billing address..."); const billingResult = await saleorClient.mutate({ mutation: CHECKOUT_BILLING_ADDRESS_UPDATE, variables: { checkoutId: checkout.id, billingAddress: { firstName: billingAddress.firstName, lastName: billingAddress.lastName, streetAddress1: billingAddress.streetAddress1, streetAddress2: billingAddress.streetAddress2, city: billingAddress.city, postalCode: billingAddress.postalCode, country: billingAddress.country, phone: billingAddress.phone, }, }, }); if (billingResult.data?.checkoutBillingAddressUpdate?.errors && billingResult.data.checkoutBillingAddressUpdate.errors.length > 0) { throw new Error(`Billing address update failed: ${billingResult.data.checkoutBillingAddressUpdate.errors[0].message}`); } console.log("Step 1: Billing address updated successfully"); console.log("Step 2: Setting shipping method..."); const shippingMethodResult = await saleorClient.mutate({ mutation: CHECKOUT_SHIPPING_METHOD_UPDATE, variables: { checkoutId: checkout.id, shippingMethodId: selectedShippingMethod, }, }); if (shippingMethodResult.data?.checkoutShippingMethodUpdate?.errors && shippingMethodResult.data.checkoutShippingMethodUpdate.errors.length > 0) { throw new Error(`Shipping method update failed: ${shippingMethodResult.data.checkoutShippingMethodUpdate.errors[0].message}`); } console.log("Step 2: Shipping method set successfully"); console.log("Step 3: Saving phone number..."); const metadataResult = await saleorClient.mutate({ mutation: CHECKOUT_METADATA_UPDATE, variables: { checkoutId: checkout.id, metadata: [ { key: "phone", value: shippingAddress.phone }, { key: "shippingPhone", value: shippingAddress.phone }, ], }, }); if (metadataResult.data?.updateMetadata?.errors && metadataResult.data.updateMetadata.errors.length > 0) { console.warn("Failed to save phone metadata:", metadataResult.data.updateMetadata.errors); } else { console.log("Step 3: Phone number saved successfully"); } console.log("Step 4: Completing checkout..."); const completeResult = await saleorClient.mutate({ mutation: CHECKOUT_COMPLETE, variables: { checkoutId: checkout.id, }, }); if (completeResult.data?.checkoutComplete?.errors && completeResult.data.checkoutComplete.errors.length > 0) { throw new Error(completeResult.data.checkoutComplete.errors[0].message); } const order = completeResult.data?.checkoutComplete?.order; if (order) { setOrderNumber(order.number); setOrderComplete(true); // Track order completion const lines = getLines(); const total = getTotal(); trackOrderCompleted({ order_id: checkout.id, order_number: order.number, total, currency: "RSD", item_count: lines.reduce((sum, line) => sum + line.quantity, 0), shipping_cost: shippingMethods.find(m => m.id === selectedShippingMethod)?.price.amount, customer_email: shippingAddress.email, }); // Identify the user identifyUser({ profileId: shippingAddress.email, email: shippingAddress.email, firstName: shippingAddress.firstName, lastName: shippingAddress.lastName, }); } else { throw new Error(t("errorCreatingOrder")); } } else { // Phase 1: Update email and address, then fetch shipping methods console.log("Phase 1: Updating email and address..."); console.log("Step 1: Updating email..."); const emailResult = await saleorClient.mutate({ mutation: CHECKOUT_EMAIL_UPDATE, variables: { checkoutId: checkout.id, email: shippingAddress.email, }, }); if (emailResult.data?.checkoutEmailUpdate?.errors && emailResult.data.checkoutEmailUpdate.errors.length > 0) { throw new Error(`Email update failed: ${emailResult.data.checkoutEmailUpdate.errors[0].message}`); } console.log("Step 1: Email updated successfully"); console.log("Step 2: Updating shipping address..."); console.log("Shipping address data:", { firstName: shippingAddress.firstName, lastName: shippingAddress.lastName, streetAddress1: shippingAddress.streetAddress1, city: shippingAddress.city, postalCode: shippingAddress.postalCode, country: shippingAddress.country, phone: shippingAddress.phone, }); const shippingResult = await saleorClient.mutate({ mutation: CHECKOUT_SHIPPING_ADDRESS_UPDATE, variables: { checkoutId: checkout.id, shippingAddress: { firstName: shippingAddress.firstName, lastName: shippingAddress.lastName, streetAddress1: shippingAddress.streetAddress1, streetAddress2: shippingAddress.streetAddress2, city: shippingAddress.city, postalCode: shippingAddress.postalCode, country: shippingAddress.country, phone: shippingAddress.phone, }, }, }); if (shippingResult.data?.checkoutShippingAddressUpdate?.errors && shippingResult.data.checkoutShippingAddressUpdate.errors.length > 0) { throw new Error(`Shipping address update failed: ${shippingResult.data.checkoutShippingAddressUpdate.errors[0].message}`); } console.log("Step 2: Shipping address updated successfully"); // Query for checkout to get available shipping methods console.log("Step 3: Fetching shipping methods..."); const checkoutQueryResult = await saleorClient.query({ query: GET_CHECKOUT_BY_ID, variables: { id: checkout.id, }, fetchPolicy: "network-only", }); const availableMethods = checkoutQueryResult.data?.checkout?.shippingMethods || []; console.log("Available shipping methods:", availableMethods); if (availableMethods.length === 0) { throw new Error(t("errorNoShippingMethods")); } setShippingMethods(availableMethods); setShowShippingMethods(true); // Track shipping step trackCheckoutStep("shipping_method_selection", { available_methods_count: availableMethods.length, }); // Don't complete yet - show shipping method selection console.log("Phase 1 complete. Waiting for shipping method selection..."); } } catch (err: unknown) { console.error("Checkout error:", err); if (err instanceof Error) { if (err.name === "AbortError") { setError("Request timed out. Please check your connection and try again."); } else { setError(err.message || t("errorOccurred")); } } else { setError(t("errorOccurred")); } } finally { setIsLoading(false); } }; if (orderComplete) { return ( <>

{t("orderConfirmed")}

{t("thankYou")}

{orderNumber && (

{t("orderNumber")}

#{orderNumber}

)}

{t("confirmationEmail")}

{t("continueShoppingBtn")}
); } return ( <>

{t("checkout")}

{error && (
{error}
)}

{t("contactInfo")}

handleEmailChange(e.target.value)} className="w-full border border-border px-4 py-2 rounded" placeholder="email@example.com" />

{t("emailRequired")}

handleShippingChange("phone", e.target.value)} className="w-full border border-border px-4 py-2 rounded" placeholder="+381..." />

{t("phoneRequired")}

{t("shippingAddress")}

handleShippingChange("firstName", e.target.value)} className="w-full border border-border px-4 py-2 rounded" />
handleShippingChange("lastName", e.target.value)} className="w-full border border-border px-4 py-2 rounded" />
handleShippingChange("streetAddress1", e.target.value)} className="w-full border border-border px-4 py-2 rounded" />
handleShippingChange("streetAddress2", e.target.value)} placeholder={t("streetAddressOptional")} className="w-full border border-border px-4 py-2 rounded" />
handleShippingChange("city", e.target.value)} className="w-full border border-border px-4 py-2 rounded" />
handleShippingChange("postalCode", e.target.value)} className="w-full border border-border px-4 py-2 rounded" />
{/* Shipping Method Selection */} {showShippingMethods && shippingMethods.length > 0 && (

{t("shippingMethod")}

{shippingMethods.map((method) => ( ))}
{!selectedShippingMethod && (

{t("errorSelectShipping")}

)}
)}

{t("orderSummary")}

{lines.length === 0 ? (

{t("yourCartEmpty")}

) : ( <>
{lines.map((line) => (
{line.variant.product.media[0]?.url && ( {line.variant.product.name} )}

{line.variant.product.name}

{t("qty")}: {line.quantity}

{formatPrice(line.totalPrice.gross.amount)}

))}
{t("subtotal")} {formatPrice(checkout?.subtotalPrice?.gross?.amount || 0)}
{t("total")} {formatPrice(total)}
)}
); }