"use client" import { useEffect, useState, useRef } from "react" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { Alert, AlertDescription } from "@/components/ui/alert" import type { CartItem, CustomerInfo, OrderResult } from "@/lib/square-types" interface PaymentFormProps { items: CartItem[] onPaymentSuccess: (result: OrderResult) => void onPaymentError: (error: string) => void } declare global { interface Window { Square: any } } export default function SquarePaymentForm({ items, onPaymentSuccess, onPaymentError }: PaymentFormProps) { const [isLoading, setIsLoading] = useState(false) const [squareLoaded, setSquareLoaded] = useState(false) const [loadingError, setLoadingError] = useState("") const [customerInfo, setCustomerInfo] = useState({ name: "", email: "", phone: "", address: { street: "", city: "", state: "", zipCode: "", country: "US" }, }) const paymentsRef = useRef(null) const cardRef = useRef(null) const totalAmount = items.reduce((sum, item) => sum + item.price * item.quantity, 0) useEffect(() => { loadSquareSDK() return () => { // Cleanup on unmount if (cardRef.current) { try { cardRef.current.destroy() } catch (e) { console.warn("Error destroying card:", e) } } } }, []) const loadSquareSDK = async () => { try { setLoadingError("") // Check if Square is already loaded if (window.Square) { await initializeSquare() return } // Validate required environment variables if (!process.env.NEXT_PUBLIC_SQUARE_APPLICATION_ID) { throw new Error("Square Application ID not configured") } if (!process.env.NEXT_PUBLIC_SQUARE_LOCATION_ID) { throw new Error("Square Location ID not configured") } // Load Square Web Payments SDK const script = document.createElement("script") script.src = process.env.SQUARE_ENVIRONMENT === "production" ? "https://web.squarecdn.com/v1/square.js" : "https://sandbox.web.squarecdn.com/v1/square.js" script.async = true script.onload = async () => { try { await initializeSquare() } catch (error) { setLoadingError(`Square initialization failed: ${error instanceof Error ? error.message : 'Unknown error'}`) } } script.onerror = () => { setLoadingError("Failed to load Square payment system") } document.head.appendChild(script) } catch (error) { setLoadingError(error instanceof Error ? error.message : "Failed to load payment system") } } const initializeSquare = async () => { try { console.log("Initializing Square Web Payments SDK...") // Initialize Square Payments paymentsRef.current = window.Square.payments( process.env.NEXT_PUBLIC_SQUARE_APPLICATION_ID, process.env.NEXT_PUBLIC_SQUARE_LOCATION_ID ) // Create and attach card payment method cardRef.current = await paymentsRef.current.card({ style: { input: { fontSize: '16px', fontFamily: 'Arial, sans-serif', color: '#373F4A', backgroundColor: '#FFFFFF', borderRadius: '6px', borderColor: '#E0E2E5', borderWidth: '1px', padding: '12px' }, '.input-container': { borderRadius: '6px', borderColor: '#E0E2E5', borderWidth: '1px' }, '.input-container.is-focus': { borderColor: '#4A90E2', boxShadow: '0 0 0 1px #4A90E2' }, '.input-container.is-error': { borderColor: '#E02F2F' }, '.message-text': { color: '#E02F2F', fontSize: '14px' } } }) await cardRef.current.attach('#card-container') setSquareLoaded(true) console.log("Square Web Payments SDK initialized successfully") } catch (error) { console.error("Square initialization error:", error) setLoadingError(`Payment system initialization failed: ${error instanceof Error ? error.message : 'Unknown error'}`) } } const handleCustomerInfoChange = (field: string, value: string) => { if (field.includes(".")) { const [parent, child] = field.split(".") setCustomerInfo((prev) => ({ ...prev, [parent]: { ...prev[parent as keyof CustomerInfo], [child]: value, }, })) } else { setCustomerInfo((prev) => ({ ...prev, [field]: value, })) } } const validateForm = (): string | null => { if (!customerInfo.name.trim()) return "Name is required" if (!customerInfo.email.trim()) return "Email is required" if (!/\S+@\S+\.\S+/.test(customerInfo.email)) return "Valid email is required" return null } const handlePayment = async () => { if (!squareLoaded || !cardRef.current) { onPaymentError("Payment system not ready") return } const validationError = validateForm() if (validationError) { onPaymentError(validationError) return } setIsLoading(true) try { console.log("Starting payment process...") // Step 1: Create order console.log("Creating order...") const orderResponse = await fetch("/api/square/orders/create", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ items, customerInfo }), }) if (!orderResponse.ok) { const errorText = await orderResponse.text() throw new Error(`Order creation failed: ${errorText}`) } const orderResult = await orderResponse.json() if (!orderResult.success) { throw new Error(orderResult.error || "Failed to create order") } console.log("Order created:", orderResult.order.id) // Step 2: Tokenize the card console.log("Tokenizing card...") const tokenResult = await cardRef.current.tokenize() if (tokenResult.status !== "OK") { const errorMessage = tokenResult.errors?.[0]?.detail || "Card tokenization failed" throw new Error(errorMessage) } console.log("Card tokenized successfully") // Step 3: Process payment console.log("Processing payment...") const paymentResponse = await fetch("/api/square/payments/create", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ sourceId: tokenResult.token, orderId: orderResult.order.id, amount: totalAmount, currency: "USD", customerInfo, items }), }) if (!paymentResponse.ok) { const errorText = await paymentResponse.text() throw new Error(`Payment processing failed: ${errorText}`) } const paymentResult = await paymentResponse.json() if (!paymentResult.success) { throw new Error(paymentResult.error || "Payment failed") } console.log("Payment processed successfully:", paymentResult.payment.id) // Success! onPaymentSuccess({ orderId: orderResult.order.id, paymentId: paymentResult.payment.id, status: paymentResult.payment.status, totalAmount: totalAmount, receiptUrl: paymentResult.payment.receiptUrl }) } catch (error) { console.error("Payment error:", error) onPaymentError(error instanceof Error ? error.message : "Payment failed") } finally { setIsLoading(false) } } return (
{/* Loading Error */} {loadingError && ( {loadingError} )} {/* Order Summary */} Order Summary
{items.map((item) => (

{item.name}

Quantity: {item.quantity}

{item.description &&

{item.description}

}

${(item.price * item.quantity).toFixed(2)}

))}
Total: ${totalAmount.toFixed(2)}
{/* Customer Information */} Customer Information
handleCustomerInfoChange("name", e.target.value)} required /> handleCustomerInfoChange("email", e.target.value)} required />
handleCustomerInfoChange("phone", e.target.value)} />

Shipping Address

handleCustomerInfoChange("address.street", e.target.value)} />
handleCustomerInfoChange("address.city", e.target.value)} /> handleCustomerInfoChange("address.state", e.target.value)} /> handleCustomerInfoChange("address.zipCode", e.target.value)} />
{/* Payment Form */} Payment Information {!squareLoaded && !loadingError && (

Loading secure payment form...

)}
{/* Square card form will be inserted here */}

Secure payment powered by Square • PCI DSS Compliant

) }