fix: Add SALEOR_API_TOKEN auth for COD transaction creation
- Add SALEOR_API_TOKEN environment variable support - Update Apollo client to include auth header - Enable COD transaction creation after checkout
This commit is contained in:
@@ -13,18 +13,13 @@ 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,
|
||||
ORDER_METADATA_UPDATE,
|
||||
CHECKOUT_LANGUAGE_CODE_UPDATE,
|
||||
TRANSACTION_CREATE,
|
||||
} from "@/lib/saleor/mutations/Checkout";
|
||||
import { PaymentSection } from "./components/PaymentSection";
|
||||
import { DEFAULT_PAYMENT_METHOD } from "@/lib/config/paymentMethods";
|
||||
import { GET_CHECKOUT_BY_ID } from "@/lib/saleor/queries/Checkout";
|
||||
import type { Checkout } from "@/types/saleor";
|
||||
import { createCheckoutService, type Address } from "@/lib/services/checkoutService";
|
||||
|
||||
interface ShippingAddressUpdateResponse {
|
||||
checkoutShippingAddressUpdate?: {
|
||||
@@ -33,44 +28,6 @@ interface ShippingAddressUpdateResponse {
|
||||
};
|
||||
}
|
||||
|
||||
interface BillingAddressUpdateResponse {
|
||||
checkoutBillingAddressUpdate?: {
|
||||
checkout?: Checkout;
|
||||
errors?: Array<{ message: string }>;
|
||||
};
|
||||
}
|
||||
|
||||
interface CheckoutCompleteResponse {
|
||||
checkoutComplete?: {
|
||||
order?: { id: string; 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;
|
||||
}
|
||||
@@ -100,7 +57,7 @@ export default function CheckoutPage() {
|
||||
const t = useTranslations("Checkout");
|
||||
const locale = useLocale();
|
||||
const router = useRouter();
|
||||
const { checkout, refreshCheckout, getLines, getTotal } = useSaleorCheckoutStore();
|
||||
const { checkout, refreshCheckout, clearCheckout, getLines, getTotal } = useSaleorCheckoutStore();
|
||||
const { trackCheckoutStarted, trackCheckoutStep, trackOrderCompleted, identifyUser } = useAnalytics();
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
@@ -291,137 +248,112 @@ export default function CheckoutPage() {
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
console.log("Completing order...");
|
||||
console.log("Completing order via CheckoutService...");
|
||||
|
||||
console.log("Step 1: Updating email...");
|
||||
const emailResult = await saleorClient.mutate<EmailUpdateResponse>({
|
||||
mutation: CHECKOUT_EMAIL_UPDATE,
|
||||
variables: {
|
||||
checkoutId: checkout.id,
|
||||
email: shippingAddress.email,
|
||||
},
|
||||
});
|
||||
// Create checkout service instance
|
||||
const checkoutService = createCheckoutService(checkout.id);
|
||||
|
||||
if (emailResult.data?.checkoutEmailUpdate?.errors && emailResult.data.checkoutEmailUpdate.errors.length > 0) {
|
||||
const errorMessage = emailResult.data.checkoutEmailUpdate.errors[0].message;
|
||||
if (errorMessage.includes("Couldn't resolve to a node")) {
|
||||
console.error("Checkout not found, clearing cart...");
|
||||
localStorage.removeItem('cart');
|
||||
localStorage.removeItem('checkoutId');
|
||||
window.location.href = `/${locale}/products`;
|
||||
return;
|
||||
}
|
||||
throw new Error(`Email update failed: ${errorMessage}`);
|
||||
// Transform form data to service types
|
||||
const serviceShippingAddress: Address = {
|
||||
firstName: shippingAddress.firstName,
|
||||
lastName: shippingAddress.lastName,
|
||||
streetAddress1: shippingAddress.streetAddress1,
|
||||
streetAddress2: shippingAddress.streetAddress2,
|
||||
city: shippingAddress.city,
|
||||
postalCode: shippingAddress.postalCode,
|
||||
country: shippingAddress.country,
|
||||
phone: shippingAddress.phone,
|
||||
};
|
||||
|
||||
const serviceBillingAddress: Address = {
|
||||
firstName: billingAddress.firstName,
|
||||
lastName: billingAddress.lastName,
|
||||
streetAddress1: billingAddress.streetAddress1,
|
||||
streetAddress2: billingAddress.streetAddress2,
|
||||
city: billingAddress.city,
|
||||
postalCode: billingAddress.postalCode,
|
||||
country: billingAddress.country,
|
||||
phone: billingAddress.phone,
|
||||
};
|
||||
|
||||
// Execute checkout pipeline
|
||||
const result = await checkoutService.execute({
|
||||
email: shippingAddress.email,
|
||||
shippingAddress: serviceShippingAddress,
|
||||
billingAddress: serviceBillingAddress,
|
||||
shippingMethodId: selectedShippingMethod,
|
||||
languageCode: locale.toUpperCase(),
|
||||
metadata: {
|
||||
phone: shippingAddress.phone,
|
||||
shippingPhone: shippingAddress.phone,
|
||||
userLanguage: locale,
|
||||
userLocale: locale,
|
||||
},
|
||||
});
|
||||
|
||||
if (!result.success || !result.order) {
|
||||
// Handle specific error types
|
||||
if (result.error === "CHECKOUT_EXPIRED") {
|
||||
console.error("Checkout not found, clearing cart...");
|
||||
localStorage.removeItem('cart');
|
||||
localStorage.removeItem('checkoutId');
|
||||
window.location.href = `/${locale}/products`;
|
||||
return;
|
||||
}
|
||||
console.log("Step 1: Email updated successfully");
|
||||
throw new Error(result.error || t("errorCreatingOrder"));
|
||||
}
|
||||
|
||||
console.log("Step 2: Updating language code...");
|
||||
await saleorClient.mutate({
|
||||
mutation: CHECKOUT_LANGUAGE_CODE_UPDATE,
|
||||
variables: {
|
||||
checkoutId: checkout.id,
|
||||
languageCode: locale.toUpperCase(),
|
||||
},
|
||||
});
|
||||
console.log("Step 2: Language code updated to", locale.toUpperCase());
|
||||
|
||||
console.log("Step 3: Updating billing address...");
|
||||
const billingResult = await saleorClient.mutate<BillingAddressUpdateResponse>({
|
||||
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 3: Billing address updated successfully");
|
||||
|
||||
console.log("Step 4: Setting shipping method...");
|
||||
const shippingMethodResult = await saleorClient.mutate<ShippingMethodUpdateResponse>({
|
||||
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 4: Shipping method set successfully");
|
||||
|
||||
console.log("Step 5: Saving metadata...");
|
||||
const metadataResult = await saleorClient.mutate<MetadataUpdateResponse>({
|
||||
mutation: CHECKOUT_METADATA_UPDATE,
|
||||
variables: {
|
||||
checkoutId: checkout.id,
|
||||
metadata: [
|
||||
{ key: "phone", value: shippingAddress.phone },
|
||||
{ key: "shippingPhone", value: shippingAddress.phone },
|
||||
{ key: "userLanguage", value: locale },
|
||||
{ key: "userLocale", value: locale },
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
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 5: Phone number saved successfully");
|
||||
}
|
||||
|
||||
console.log("Step 6: Completing checkout...");
|
||||
const completeResult = await saleorClient.mutate<CheckoutCompleteResponse>({
|
||||
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,
|
||||
// Success!
|
||||
setOrderNumber(result.order.number);
|
||||
setOrderComplete(true);
|
||||
|
||||
// If COD payment, create a transaction on the order
|
||||
if (selectedPaymentMethod === 'cod' && result.order.id) {
|
||||
try {
|
||||
console.log("Creating COD transaction for order:", result.order.id);
|
||||
await saleorClient.mutate({
|
||||
mutation: TRANSACTION_CREATE,
|
||||
variables: {
|
||||
orderId: result.order.id,
|
||||
transaction: {
|
||||
name: "Cash on Delivery",
|
||||
message: "COD - Payment pending on delivery"
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Identify the user
|
||||
identifyUser({
|
||||
profileId: shippingAddress.email,
|
||||
email: shippingAddress.email,
|
||||
firstName: shippingAddress.firstName,
|
||||
lastName: shippingAddress.lastName,
|
||||
});
|
||||
} else {
|
||||
throw new Error(t("errorCreatingOrder"));
|
||||
console.log("COD transaction created successfully");
|
||||
} catch (txError) {
|
||||
console.error("Failed to create COD transaction:", txError);
|
||||
// Don't fail the checkout if transaction creation fails
|
||||
}
|
||||
}
|
||||
|
||||
// Clear the checkout/cart from the store
|
||||
clearCheckout();
|
||||
|
||||
// Track order completion
|
||||
const lines = getLines();
|
||||
const total = getTotal();
|
||||
trackOrderCompleted({
|
||||
order_id: checkout.id,
|
||||
order_number: result.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,
|
||||
});
|
||||
|
||||
console.log("Order completed successfully:", result.order.number);
|
||||
|
||||
} catch (err: unknown) {
|
||||
console.error("Checkout error:", err);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user