Skip to content

Commit 82782cd

Browse files
committed
fix: Implement shipping method selection in checkout process
- Added shipping method options (standard and express) with associated pricing and delivery durations. - Updated checkout form to include shipping method in the form data and adjusted total calculation accordingly.
1 parent 85119fb commit 82782cd

File tree

2 files changed

+95
-64
lines changed

2 files changed

+95
-64
lines changed

src/app/checkout/page.tsx

Lines changed: 79 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,20 @@ import Link from 'next/link';
2222
import { useRouter } from 'next/navigation';
2323
import Image from 'next/image';
2424

25+
type shippingType = 'standard' | 'express';
26+
27+
interface shippingDetails {
28+
name: string;
29+
price: number;
30+
duration: string;
31+
}
32+
33+
// logic usually done in the backend, client calls the exposed endopoint
34+
const shippingMethods: Record<shippingType, shippingDetails> = {
35+
standard: { name: 'Standard Shipping', price: 25, duration: '5-7 business days' },
36+
express: { name: 'Express Shipping', price: 50, duration: '2-3 business days' },
37+
};
38+
2539
interface CheckoutFormData {
2640
// Contact Information
2741
email: string;
@@ -37,6 +51,8 @@ interface CheckoutFormData {
3751
zipCode: string;
3852
country: string;
3953

54+
shippingMethod: shippingType;
55+
4056
// Payment Information
4157
paymentMethod: string;
4258
cardNumber: string;
@@ -67,6 +83,7 @@ export default function CheckoutPage() {
6783
city: '',
6884
state: '',
6985
zipCode: '',
86+
shippingMethod: 'standard',
7087
country: 'US',
7188
paymentMethod: 'card',
7289
cardNumber: '',
@@ -84,14 +101,16 @@ export default function CheckoutPage() {
84101

85102
const subtotal = total;
86103
const discount = subtotal * 0.1;
87-
const deliveryFee = 50;
104+
const deliveryFee = shippingMethods[formData.shippingMethod].price;
88105
const tax = (subtotal - discount) * 0.08;
89106
const finalTotal = subtotal - discount + deliveryFee + tax;
90107

91108
const handleInputChange = (field: keyof CheckoutFormData, value: string | boolean) => {
92109
setFormData((prev) => ({ ...prev, [field]: value }));
93110
};
94111

112+
console.log(formData.shippingMethod);
113+
95114
const handleSubmit = async (e: React.FormEvent) => {
96115
e.preventDefault();
97116
setIsProcessing(true);
@@ -218,7 +237,7 @@ export default function CheckoutPage() {
218237
</div>
219238

220239
<div>
221-
<Label htmlFor="address">Address *</Label>
240+
<Label htmlFor="address">Street Address *</Label>
222241
<Input
223242
id="address"
224243
required
@@ -239,23 +258,30 @@ export default function CheckoutPage() {
239258
</div>
240259

241260
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
242-
<div>
243-
<Label htmlFor="city">City *</Label>
244-
<Input
245-
id="city"
246-
required
247-
value={formData.city}
248-
onChange={(e) => handleInputChange('city', e.target.value)}
249-
placeholder="New York"
250-
/>
251-
</div>
261+
{/* <div>
262+
<Label htmlFor="state">States *</Label>
263+
<Select
264+
value={formData.state}
265+
onValueChange={(value) => handleInputChange('state', value)}
266+
>
267+
<SelectTrigger aria-labelledby="state-label">
268+
<SelectValue placeholder="Select state" />
269+
</SelectTrigger>
270+
<SelectContent>
271+
<SelectItem value="NY">New York</SelectItem>
272+
<SelectItem value="CA">California</SelectItem>
273+
<SelectItem value="TX">Texas</SelectItem>
274+
<SelectItem value="FL">Florida</SelectItem>
275+
</SelectContent>
276+
</Select>
277+
</div> */}
252278
<div>
253279
<Label htmlFor="state">State *</Label>
254280
<Select
255281
value={formData.state}
256282
onValueChange={(value) => handleInputChange('state', value)}
257283
>
258-
<SelectTrigger>
284+
<SelectTrigger aria-label="state">
259285
<SelectValue placeholder="Select state" />
260286
</SelectTrigger>
261287
<SelectContent>
@@ -266,6 +292,16 @@ export default function CheckoutPage() {
266292
</SelectContent>
267293
</Select>
268294
</div>
295+
<div>
296+
<Label htmlFor="city">City *</Label>
297+
<Input
298+
id="city"
299+
required
300+
value={formData.city}
301+
onChange={(e) => handleInputChange('city', e.target.value)}
302+
placeholder="New York"
303+
/>
304+
</div>
269305
<div>
270306
<Label htmlFor="zipCode">ZIP Code *</Label>
271307
<Input
@@ -283,43 +319,38 @@ export default function CheckoutPage() {
283319
{/* Shipping Method */}
284320
<div className="bg-white rounded-2xl p-6">
285321
<h2 className="text-xl font-semibold text-gray-900 mb-6">Shipping Method</h2>
286-
<RadioGroup defaultValue="standard" className="space-y-4">
287-
<div className="flex items-center space-x-3 p-4 border border-gray-200 rounded-lg">
288-
<RadioGroupItem value="standard" id="standard" />
289-
<div className="flex-1">
290-
<Label
291-
htmlFor="standard"
292-
className="flex items-center justify-between cursor-pointer"
293-
>
294-
<div className="flex items-center">
295-
<Truck className="h-5 w-5 mr-3 text-gray-600" />
296-
<div>
297-
<div className="font-medium">Standard Shipping</div>
298-
<div className="text-sm text-gray-600">5-7 business days</div>
299-
</div>
300-
</div>
301-
<span className="font-medium">$50.00</span>
302-
</Label>
303-
</div>
304-
</div>
305-
<div className="flex items-center space-x-3 p-4 border border-gray-200 rounded-lg">
306-
<RadioGroupItem value="express" id="express" />
307-
<div className="flex-1">
308-
<Label
309-
htmlFor="express"
310-
className="flex items-center justify-between cursor-pointer"
311-
>
312-
<div className="flex items-center">
313-
<Truck className="h-5 w-5 mr-3 text-gray-600" />
314-
<div>
315-
<div className="font-medium">Express Shipping</div>
316-
<div className="text-sm text-gray-600">2-3 business days</div>
322+
<RadioGroup
323+
value={formData.shippingMethod}
324+
onValueChange={(value) =>
325+
handleInputChange('shippingMethod', value as shippingType)
326+
}
327+
className="space-y-4"
328+
>
329+
{Object.entries(shippingMethods).map(([key, details]) => (
330+
<div
331+
key={key}
332+
className="flex items-center space-x-3 p-4 border border-gray-200 rounded-lg"
333+
>
334+
<RadioGroupItem value={key} id={key} />
335+
<div className="flex-1">
336+
<Label
337+
htmlFor={key}
338+
className="flex items-center justify-between cursor-pointer"
339+
>
340+
<div className="flex items-center">
341+
<Truck className="h-5 w-5 mr-3 text-gray-600" />
342+
<div>
343+
<div className="font-medium">{details.name}</div>
344+
<div className="text-sm text-gray-600">
345+
{key === 'standard' ? '5-7 business days' : '2-3 business days'}
346+
</div>
347+
</div>
317348
</div>
318-
</div>
319-
<span className="font-medium">$25.00</span>
320-
</Label>
349+
<span className="font-medium">${details.price.toFixed(2)}</span>
350+
</Label>
351+
</div>
321352
</div>
322-
</div>
353+
))}
323354
</RadioGroup>
324355
</div>
325356

src/components/ui/price.tsx

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,36 @@
1-
import { cn } from "@/lib/utils"
1+
import { cn } from '@/lib/utils';
22

33
interface PriceProps {
4-
amount: number
5-
currency?: string
6-
className?: string
7-
size?: "sm" | "md" | "lg" | "xl"
4+
amount: number;
5+
currency?: string;
6+
className?: string;
7+
size?: 'sm' | 'md' | 'lg' | 'xl';
88
}
99

10-
export function Price({ amount, currency = "USD", className, size = "md" }: PriceProps) {
10+
export function Price({ amount, currency = 'USD', className, size = 'md' }: PriceProps) {
1111
const formatPrice = (amount: number) => {
12-
return new Intl.NumberFormat("en-US", {
13-
style: "currency",
12+
return new Intl.NumberFormat('en-US', {
13+
style: 'currency',
1414
currency: currency,
1515
minimumFractionDigits: 0,
1616
maximumFractionDigits: 0,
17-
}).format(amount)
18-
}
17+
}).format(amount);
18+
};
1919

2020
return (
2121
<span
2222
className={cn(
23-
"font-semibold text-gray-900",
23+
'font-semibold text-gray-900',
2424
{
25-
"text-sm": size === "sm",
26-
"text-base": size === "md",
27-
"text-lg": size === "lg",
28-
"text-2xl": size === "xl",
25+
'text-sm': size === 'sm',
26+
'text-base': size === 'md',
27+
'text-lg': size === 'lg',
28+
'text-2xl': size === 'xl',
2929
},
3030
className,
3131
)}
3232
>
3333
{formatPrice(amount)}
3434
</span>
35-
)
35+
);
3636
}

0 commit comments

Comments
 (0)