added debounce to - + buttons
This commit is contained in:
@@ -1,37 +1,58 @@
|
||||
"use client"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Card } from "@/components/ui/card"
|
||||
import { Label } from "@/components/ui/label"
|
||||
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"
|
||||
import { Textarea } from "@/components/ui/textarea"
|
||||
import { Separator } from "@/components/ui/separator"
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
|
||||
import DeliveryTypeSelector from "./DeliveryTypeSelector"
|
||||
import type { Order, Province, DeliveryType, CartTranslations, PaymentType } from "../types"
|
||||
"use client";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card } from "@/components/ui/card";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import DeliveryTypeSelector from "./DeliveryTypeSelector";
|
||||
import { useTranslations } from "next-intl";
|
||||
import type { DeliveryType, PaymentType, Province } from "@/lib/types/api";
|
||||
|
||||
interface OrderBillingItem {
|
||||
title: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
interface OrderBilling {
|
||||
body: OrderBillingItem[];
|
||||
footer: {
|
||||
title: string;
|
||||
value: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface OrderSummaryProps {
|
||||
order: Order
|
||||
translations: CartTranslations
|
||||
paymentType: PaymentType | null
|
||||
deliveryType: DeliveryType
|
||||
selectedRegion: string
|
||||
selectedProvince: number | null
|
||||
note: string
|
||||
regionGroups: Record<string, Province[]>
|
||||
availableRegions: string[]
|
||||
paymentTypes: PaymentType[]
|
||||
onPaymentTypeChange: (type: PaymentType) => void
|
||||
onDeliveryTypeChange: (type: DeliveryType) => void
|
||||
onRegionChange: (regionCode: string) => void
|
||||
onProvinceChange: (provinceId: number) => void
|
||||
onNoteChange: (note: string) => void
|
||||
onCompleteOrder: () => void
|
||||
isLoading: boolean
|
||||
order: {
|
||||
id: number;
|
||||
billing: OrderBilling;
|
||||
};
|
||||
paymentType: PaymentType | null;
|
||||
deliveryType: DeliveryType;
|
||||
selectedRegion: string;
|
||||
selectedProvince: number | null;
|
||||
note: string;
|
||||
regionGroups: Record<string, Province[]>;
|
||||
availableRegions: string[];
|
||||
paymentTypes: PaymentType[];
|
||||
onPaymentTypeChange: (type: PaymentType) => void;
|
||||
onDeliveryTypeChange: (type: DeliveryType) => void;
|
||||
onRegionChange: (regionCode: string) => void;
|
||||
onProvinceChange: (provinceId: number) => void;
|
||||
onNoteChange: (note: string) => void;
|
||||
onCompleteOrder: () => void;
|
||||
isLoading: boolean;
|
||||
}
|
||||
|
||||
export default function OrderSummary({
|
||||
order,
|
||||
translations: t,
|
||||
paymentType,
|
||||
deliveryType,
|
||||
selectedRegion,
|
||||
@@ -48,29 +69,35 @@ export default function OrderSummary({
|
||||
onCompleteOrder,
|
||||
isLoading,
|
||||
}: OrderSummaryProps) {
|
||||
const provincesForSelectedRegion = selectedRegion ? regionGroups[selectedRegion] || [] : []
|
||||
const isFormValid = selectedRegion && selectedProvince && paymentType
|
||||
const t = useTranslations();
|
||||
|
||||
const provincesForSelectedRegion = selectedRegion
|
||||
? regionGroups[selectedRegion] || []
|
||||
: [];
|
||||
const isFormValid = selectedRegion && selectedProvince && paymentType;
|
||||
|
||||
return (
|
||||
<Card className="w-full md:w-[380px] p-6 rounded-xl h-fit sticky top-20">
|
||||
{/* Payment Type */}
|
||||
<div className="mb-6">
|
||||
<h3 className="text-lg font-semibold mb-3">{t.paymentType}</h3>
|
||||
<h3 className="text-lg font-semibold mb-3">{t("payment_type")}</h3>
|
||||
<div className="flex gap-2">
|
||||
{paymentTypes.map((type) => (
|
||||
<Card
|
||||
key={type.id}
|
||||
className={`flex-1 cursor-pointer transition-all ${
|
||||
paymentType?.id === type.id
|
||||
? "border-2 border-[#005bff] bg-blue-50"
|
||||
paymentType?.id === type.id
|
||||
? "border-2 border-[#005bff] bg-blue-50"
|
||||
: "border-2 border-gray-200"
|
||||
}`}
|
||||
onClick={() => onPaymentTypeChange(type)}
|
||||
>
|
||||
<div className="flex flex-col items-center justify-center p-4 gap-2">
|
||||
<span className={`text-xs font-medium ${
|
||||
paymentType?.id === type.id ? "text-[#005bff]" : ""
|
||||
}`}>
|
||||
<span
|
||||
className={`text-xs font-medium ${
|
||||
paymentType?.id === type.id ? "text-[#005bff]" : ""
|
||||
}`}
|
||||
>
|
||||
{type.name}
|
||||
</span>
|
||||
</div>
|
||||
@@ -80,21 +107,22 @@ export default function OrderSummary({
|
||||
</div>
|
||||
|
||||
{/* Delivery Type */}
|
||||
<DeliveryTypeSelector
|
||||
selectedType={deliveryType}
|
||||
onSelect={onDeliveryTypeChange}
|
||||
translations={t}
|
||||
<DeliveryTypeSelector
|
||||
selectedType={deliveryType}
|
||||
onSelect={onDeliveryTypeChange}
|
||||
/>
|
||||
|
||||
{/* Region Selection */}
|
||||
<div className="mb-6">
|
||||
<Label className="text-lg font-semibold mb-3 block">{t.selectRegion}</Label>
|
||||
<RadioGroup
|
||||
value={selectedRegion}
|
||||
<Label className="text-lg font-semibold mb-3 block">
|
||||
{t("choose_region")}
|
||||
</Label>
|
||||
<RadioGroup
|
||||
value={selectedRegion}
|
||||
onValueChange={(value) => {
|
||||
onRegionChange(value)
|
||||
onProvinceChange(null as any)
|
||||
}}
|
||||
onRegionChange(value);
|
||||
onProvinceChange(null as any);
|
||||
}}
|
||||
className="flex flex-wrap gap-4"
|
||||
>
|
||||
{availableRegions.map((regionCode) => (
|
||||
@@ -104,7 +132,10 @@ export default function OrderSummary({
|
||||
id={`region-${regionCode}`}
|
||||
className="border-2 border-gray-400 data-[state=checked]:border-[#005bff] data-[state=checked]:bg-white"
|
||||
/>
|
||||
<Label htmlFor={`region-${regionCode}`} className="cursor-pointer uppercase">
|
||||
<Label
|
||||
htmlFor={`region-${regionCode}`}
|
||||
className="cursor-pointer uppercase"
|
||||
>
|
||||
{regionCode}
|
||||
</Label>
|
||||
</div>
|
||||
@@ -115,13 +146,15 @@ export default function OrderSummary({
|
||||
{/* Province Selection */}
|
||||
{selectedRegion && provincesForSelectedRegion.length > 0 && (
|
||||
<div className="mb-6">
|
||||
<Label className="text-lg font-semibold mb-3 block">{t.selectAddress}</Label>
|
||||
<Select
|
||||
value={selectedProvince?.toString() || ""}
|
||||
<Label className="text-lg font-semibold mb-3 block">
|
||||
{t("choose_address")}
|
||||
</Label>
|
||||
<Select
|
||||
value={selectedProvince?.toString() || ""}
|
||||
onValueChange={(value) => onProvinceChange(parseInt(value))}
|
||||
>
|
||||
<SelectTrigger className="rounded-xl">
|
||||
<SelectValue placeholder={t.selectAddress} />
|
||||
<SelectValue placeholder={t("choose_address")} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{provincesForSelectedRegion.map((province) => (
|
||||
@@ -136,20 +169,23 @@ export default function OrderSummary({
|
||||
|
||||
{/* Note */}
|
||||
<div className="mb-6">
|
||||
<Label className="text-lg font-semibold mb-3 block">{t.note}</Label>
|
||||
<Label className="text-lg font-semibold mb-3 block">{t("note")}</Label>
|
||||
<Textarea
|
||||
value={note}
|
||||
onChange={(e) => onNoteChange(e.target.value)}
|
||||
className="rounded-xl resize-none"
|
||||
rows={3}
|
||||
placeholder={t.note}
|
||||
placeholder={t("note")}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Billing */}
|
||||
<div className="space-y-2 mb-4">
|
||||
{order.billing.body.map((item, index) => (
|
||||
<div key={index} className="flex justify-between text-base font-medium">
|
||||
<div
|
||||
key={index}
|
||||
className="flex justify-between text-base font-medium"
|
||||
>
|
||||
<span>{item.title}:</span>
|
||||
<span>{item.value}</span>
|
||||
</div>
|
||||
@@ -159,8 +195,12 @@ export default function OrderSummary({
|
||||
<Separator className="my-4" />
|
||||
|
||||
<div className="flex justify-between items-center mb-6">
|
||||
<span className="text-lg font-semibold">{order.billing.footer.title}:</span>
|
||||
<span className="text-lg font-bold text-green-600">{order.billing.footer.value}</span>
|
||||
<span className="text-lg font-semibold">
|
||||
{order.billing.footer.title}:
|
||||
</span>
|
||||
<span className="text-lg font-bold text-green-600">
|
||||
{order.billing.footer.value}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
@@ -169,8 +209,8 @@ export default function OrderSummary({
|
||||
className="w-full rounded-xl bg-[#005bff] hover:bg-[#004dcc] h-12 text-lg font-bold disabled:opacity-50"
|
||||
size="lg"
|
||||
>
|
||||
{isLoading ? `${t.placeOrder}...` : t.placeOrder}
|
||||
{isLoading ? `${t("order")}...` : t("order")}
|
||||
</Button>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user