import {
Card,
CardContent,
CardHeader,
CardTitle
} from '@components/common/ui/Card.js';
import {
Item,
ItemActions,
ItemContent,
ItemDescription,
ItemTitle
} from '@components/common/ui/Item.js';
import { Label } from '@components/common/ui/Label.js';
import {
RadioGroup,
RadioGroupItem
} from '@components/common/ui/RadioGroup.js';
import { useCheckout } from '@components/frontStore/checkout/CheckoutContext.js';
import { _ } from '@evershop/evershop/lib/locale/translate/_';
import { CustomerAddressGraphql } from '@evershop/evershop/types/customerAddress';
import { Package } from 'lucide-react';
import React from 'react';
interface ShippingMethod {
code: string;
name: string;
cost?: {
value: number;
text: string;
};
description?: string;
isSelected?: boolean;
}
// Skeleton component for loading state
function ShippingMethodSkeleton() {
return (
{[1, 2, 3, 4].map((index) => (
))}
);
}
export function ShippingMethods({
methods,
shippingAddress,
isLoading,
onSelect
}: {
methods: ShippingMethod[];
shippingAddress?: CustomerAddressGraphql;
isLoading?: boolean;
onSelect?: (method: ShippingMethod) => Promise | boolean;
}) {
const { form } = useCheckout();
const { formState, setValue, watch } = form;
const [isProcessing, setIsProcessing] = React.useState(false);
const currentValue = watch('shippingMethod');
const handleMethodSelect = async (method: ShippingMethod) => {
if (!onSelect) {
// If no onSelect function provided, allow normal behavior
setValue('shippingMethod', method.code);
return;
}
if (isProcessing || formState.disabled) {
return;
}
try {
setIsProcessing(true);
const result = await Promise.resolve(onSelect(method));
if (result) {
// Only update the form value if onSelect returns true
setValue('shippingMethod', method.code);
}
// If result is false, keep the current selection
} catch (error) {
// Keep the current selection on error
} finally {
setIsProcessing(false);
}
};
return (
{isLoading ? (
) : (
<>
{methods?.length === 0 ? (
{!shippingAddress?.country || !shippingAddress?.province ? (
{_(
'Available shipping methods will appear once you provide your address details'
)}
) : (
{_('No shipping methods available')}
{_(
'No shipping options are available for your location'
)}
)}
) : (
{
const method = methods.find((m) => m.code === value);
if (method) {
handleMethodSelect(method);
} else {
setValue('shippingMethod', value);
}
}}
>
{methods.map((method: ShippingMethod) => (
-
{
!isProcessing && handleMethodSelect(method);
}}
disabled={isProcessing}
/>
{method.description && (
{method.description}
)}
{method.cost ? (
<>
{method.cost.value > 0 ? (
{method.cost.text}
) : (
<>
{method.cost.text}
{_('FREE')}
>
)}
>
) : (
{_('Contact for pricing')}
)}
))}
)}
{formState.errors.shippingMethod && (
{formState.errors.shippingMethod?.message?.toString() ||
_('Please select a shipping method')}
)}
>
)}
);
}