added shipping method

This commit is contained in:
@jcarymuhammedow
2026-03-02 17:46:18 +05:00
parent bf5980e3b3
commit c13a4655bf
7 changed files with 282 additions and 71 deletions

View File

@@ -13,9 +13,13 @@ import {
SelectValue,
} from "@/components/ui/select";
import { Input } from "@/components/ui/input";
import DeliveryTypeSelector from "./DeliveryTypeSelector";
import { useTranslations } from "next-intl";
import type { DeliveryType, PaymentType, Province } from "@/lib/types/api";
import type {
DeliveryType,
PaymentType,
Province,
OrderDelivery,
} from "@/lib/types/api";
import { useState } from "react";
interface OrderBillingItem {
@@ -37,7 +41,8 @@ interface OrderSummaryProps {
billing: OrderBilling;
};
paymentType: PaymentType | null;
deliveryType: DeliveryType;
orderDeliveries: OrderDelivery[];
selectedOrderDelivery: OrderDelivery | null;
selectedRegion: string;
selectedProvince: number | null;
notes: string;
@@ -51,7 +56,7 @@ interface OrderSummaryProps {
onNameChange: (name: string) => void;
onLastNameChange: (lastName: string) => void;
onPaymentTypeChange: (type: PaymentType) => void;
onDeliveryTypeChange: (type: DeliveryType) => void;
onOrderDeliveryChange: (delivery: OrderDelivery) => void;
onRegionChange: (regionCode: string) => void;
onProvinceChange: (provinceId: number) => void;
onNoteChange: (notes: string) => void;
@@ -62,7 +67,8 @@ interface OrderSummaryProps {
export default function OrderSummary({
order,
paymentType,
deliveryType,
orderDeliveries,
selectedOrderDelivery,
selectedRegion,
selectedProvince,
notes,
@@ -76,7 +82,7 @@ export default function OrderSummary({
onNameChange,
onLastNameChange,
onPaymentTypeChange,
onDeliveryTypeChange,
onOrderDeliveryChange,
onRegionChange,
onProvinceChange,
onNoteChange,
@@ -90,6 +96,15 @@ export default function OrderSummary({
? regionGroups[selectedRegion] || []
: [];
const filteredDeliveries = orderDeliveries.filter((delivery) => {
if (!selectedRegion) return true;
if (selectedRegion === "ag") {
return delivery.name === "standart" || delivery.name === "self_pickup";
} else {
return delivery.name === "region";
}
});
const phoneDigits = phone.replace(/\D/g, "");
const isPhoneValid = phoneDigits.length === 11;
@@ -97,6 +112,7 @@ export default function OrderSummary({
selectedRegion &&
selectedProvince &&
paymentType &&
selectedOrderDelivery &&
isPhoneValid &&
name.trim() !== "" &&
lastName.trim() !== "";
@@ -136,7 +152,7 @@ export default function OrderSummary({
return (
<Card className="w-full md:w-[380px] p-4 md:p-6 rounded-xl h-fit sticky top-20">
{/* Customer Information */}
<div className="mb-6">
<div className="mb-4">
<h3 className="text-lg font-semibold mb-3">
{t("customer_information")}
</h3>
@@ -198,7 +214,7 @@ export default function OrderSummary({
</div>
{/* Payment Type */}
<div className="mb-6">
<div className="mb-4">
<h3 className="text-lg font-semibold mb-3">{t("payment_type")}</h3>
<div className="flex gap-2">
{paymentTypes.map((type) => (
@@ -231,16 +247,13 @@ export default function OrderSummary({
</div>
{/* Region Selection */}
<div className="mb-6">
<div className="mb-4">
<Label className="text-lg font-semibold mb-3 block">
{t("choose_region")}
</Label>
<RadioGroup
value={selectedRegion}
onValueChange={(value) => {
onRegionChange(value);
onProvinceChange(null as any);
}}
onValueChange={(value) => onRegionChange(value)}
className="flex flex-wrap gap-4"
>
{availableRegions.map((regionCode) => (
@@ -270,7 +283,7 @@ export default function OrderSummary({
{/* Province Selection */}
{selectedRegion && provincesForSelectedRegion.length > 0 && (
<div className="mb-6">
<div className="mb-4">
<Label className="text-lg font-semibold mb-3 block">
{t("choose_address")}
</Label>
@@ -299,8 +312,56 @@ export default function OrderSummary({
</div>
)}
{/* Shipping Method */}
{selectedRegion && (
<div className="mb-4">
<h3 className="text-lg font-semibold mb-3">{t("shipping_method")}</h3>
<div className="flex gap-2">
{filteredDeliveries.map((delivery) => (
<Card
key={delivery.name}
className={`flex-1 cursor-pointer py-4 transition-all ${
selectedOrderDelivery?.name === delivery.name
? "border-2 border-[#005bff] bg-blue-50"
: showValidation && !selectedOrderDelivery
? "border-2 border-red-500"
: "border-2 border-gray-200"
}`}
onClick={() => onOrderDeliveryChange(delivery)}
>
<div className="flex items-center flex-col p-4">
<div className="flex flex-col">
<span
className={`text-sm font-medium ${
selectedOrderDelivery?.name === delivery.name
? "text-[#005bff]"
: ""
}`}
>
{t(delivery.name)}
</span>
</div>
<span
className={`text-sm font-bold ${
selectedOrderDelivery?.name === delivery.name
? "text-[#005bff]"
: "text-green-600"
}`}
>
{delivery.price === 0 ? t("free") : `${delivery.price} TMT`}
</span>
</div>
</Card>
))}
</div>
{showValidation && !selectedOrderDelivery && (
<p className="text-xs text-red-500 mt-1">{t("requiredField")}</p>
)}
</div>
)}
{/* Note */}
<div className="mb-6">
<div className="mb-4">
<Label className="text-lg font-semibold mb-3 block">{t("note")}</Label>
<Textarea
value={notes}

View File

@@ -5,15 +5,14 @@ import {
UseQueryOptions,
} from "@tanstack/react-query";
import { apiClient } from "@/lib/api";
import type { CartItem } from "@/lib/types/api";
import type {
CartItem,
CartResponse,
CreateOrderPayload,
OrderDelivery,
} from "@/lib/types/api";
import { useEffect } from "react";
interface CartResponse {
message: string;
data: CartItem[];
errorDetails?: string;
}
const pendingUpdates = new Map<number, number>();
let updateLock = false;
@@ -457,21 +456,24 @@ export function useUpdateCartItemQuantity() {
});
}
export function useOrderDeliveries() {
return useQuery({
queryKey: ["order-deliveries"],
queryFn: async () => {
const response = await apiClient.get<{
message: string;
data: OrderDelivery[];
}>("/order-deliveries");
return response.data.data;
},
});
}
export function useCreateOrder() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async (payload: {
customer_name?: string;
customer_phone: number;
customer_address: string;
shipping_method: string;
payment_type_id: number;
delivery_time?: string;
delivery_at?: string;
region: string;
notes?: string;
}) => {
mutationFn: async (payload: CreateOrderPayload) => {
const response = await apiClient.post("/orders", payload);
return response.data;
},