Vitron-Front/app/routes/store.$storeId.orders.$orderId.tsx
2026-04-29 01:44:16 +03:30

942 lines
32 KiB
TypeScript
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { LoaderFunctionArgs, type MetaFunction } from "@remix-run/node";
import { useLoaderData, useNavigate, useParams } from "@remix-run/react";
import {
useGetSellerOrderDetail,
useUpdateSellerOrder,
} from "../requestHandler/use-order-hooks";
import { useServiceGetCouriers } from "../requestHandler/use-courier-hooks";
import { formatDate, formatPrice, formatTime, safeGoBack } from "../utils/helpers";
import {
MapPin,
Wallet,
User,
PhoneCall,
Mail,
Truck,
AlertTriangle,
X,
Edit,
Package,
Signpost,
NotebookPen
} from "lucide-react";
import HeaderWithSupport from "../components/HeaderWithSupport";
import { Button } from "../components/ui/button";
import {
Drawer,
DrawerContent,
DrawerHeader,
DrawerTitle,
DrawerTrigger,
DrawerFooter,
} from "../components/ui/drawer";
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogFooter,
DialogOverlay,
} from "../components/ui/dialog";
import { useState, useEffect } from "react";
import {
SellerOrderListStatusEnum,
SellerOrderUpdateStatusEnum,
SellerOrderUpdateCancelReasonEnum,
} from "../../src/api/types";
import { RadioGroup, RadioGroupItem } from "~/components/ui/radio-group";
import AppInput from "~/components/AppInput";
import AppTextArea from "~/components/AppTextArea";
import { toast } from "~/hooks/use-toast";
import { useStoreOwnership } from "../hooks/useStoreOwnership";
export const meta: MetaFunction = () => {
return [
{ title: "جزئیات سفارش - ویترون" },
{
name: "description",
content:
"مشاهده جزئیات کامل سفارش دریافتی در فروشگاه شما. مدیریت وضعیت سفارش، کد رهگیری و اطلاعات مشتری.",
},
{
name: "keywords",
content: "جزئیات سفارش، مدیریت سفارش، کد رهگیری، فروشگاه، ویترون",
},
{ name: "robots", content: "noindex, follow" },
{ property: "og:title", content: "جزئیات سفارش - ویترون" },
{
property: "og:description",
content:
"مشاهده جزئیات کامل سفارش دریافتی در فروشگاه شما. مدیریت وضعیت سفارش، کد رهگیری و اطلاعات مشتری.",
},
{ property: "og:type", content: "website" },
{ name: "twitter:card", content: "summary" },
{ name: "twitter:title", content: "جزئیات سفارش - ویترون" },
{
name: "twitter:description",
content:
"مشاهده جزئیات کامل سفارش دریافتی در فروشگاه شما. مدیریت وضعیت سفارش، کد رهگیری و اطلاعات مشتری.",
},
];
};
export async function loader({ params }: LoaderFunctionArgs) {
const { storeId, orderId } = params;
if (!storeId) {
throw new Response("Store ID is required", { status: 400 });
}
if (!orderId) {
throw new Response("Order ID is required", { status: 400 });
}
return { storeId, orderId };
}
export default function OrderDetail() {
const navigate = useNavigate();
const { orderId, storeId } = useLoaderData<typeof loader>();
const { data: order, isLoading, error } = useGetSellerOrderDetail(orderId);
const { data: sellerCouriers } = useServiceGetCouriers(storeId);
// Check store ownership - this will redirect if user doesn't own the store
const { isLoading: isOwnershipLoading } = useStoreOwnership(storeId);
// State for drawer and modal
const [isAcceptDrawerOpen, setIsAcceptDrawerOpen] = useState(false);
const [isCancelModalOpen, setIsCancelModalOpen] = useState(false);
const [isTrackingDrawerOpen, setIsTrackingDrawerOpen] = useState(false);
const [isEditTrackingDrawerOpen, setIsEditTrackingDrawerOpen] =
useState(false);
const [isReactivateModalOpen, setIsReactivateModalOpen] = useState(false);
const [isUpdating, setIsUpdating] = useState(false);
const handleBack = () => {
safeGoBack(navigate);
};
// Resolve courier name from selected seller courier id
const selectedSellerCourierId = order?.shippingInfo?.sellerCourier;
const selectedCourier =
sellerCouriers?.find(
(c: any) =>
c?.id === selectedSellerCourierId ||
c?.courierId === selectedSellerCourierId ||
c?.courier?.id === selectedSellerCourierId
) || undefined;
const courierName =
selectedCourier?.courierName ||
"-";
// Show loading while checking ownership
if (isOwnershipLoading) {
return (
<div className="min-h-[500px] bg-WHITE">
<HeaderWithSupport title="جزئیات سفارش" onBack={handleBack} />
<div className="flex justify-center items-center p-8">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600"></div>
</div>
</div>
);
}
if (isLoading) {
return (
<div className="min-h-[500px] bg-WHITE">
<HeaderWithSupport title="جزئیات سفارش" onBack={handleBack} />
<div className="flex justify-center items-center p-8">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600"></div>
</div>
</div>
);
}
if (error || !order) {
return (
<div className="min-h-[500px] bg-WHITE">
<HeaderWithSupport title="جزئیات سفارش" onBack={handleBack} />
<div className="p-4">
<div className="bg-red-50 border border-red-200 rounded-lg p-4">
<p className="text-red-700 text-center">
خطا در بارگذاری اطلاعات سفارش. لطفا دوباره تلاش کنید.
</p>
</div>
</div>
</div>
);
}
return (
<>
<div className="bg-WHITE">
<HeaderWithSupport title="سفارش جدید" onBack={handleBack} />
<div className="w-full flex flex-col gap-2">
<div className="flex w-full items-center justify-around p-4">
<p className="text-R12 text-GRAY">
{order.createdAt && formatDate(order.createdAt)} -{" "}
{order.createdAt && formatTime(order.createdAt)}
</p>
<p className="text-R12 text-GRAY">
سفارش شماره {order.invoice?.invoiceNumber}
</p>
</div>
</div>
<div className="space-y-4">
{/* Order Items */}
{order.items && order.items.length > 0 && (
<div className="bg-WHITE p-4">
<div className="space-y-3">
{order.items.map((item, index) => {
console.log("item", item);
return (
<div
key={index}
className="flex flex-col items-center w-full gap-3"
>
{/* Product Info */}
<div className="w-full flex items-center justify-between line-clamp-1">
<div>
{index + 1}- {item.productTitle || "محصول"}(
{formatPrice(item.totalPrice)} تومان)
</div>
<div
onClick={() => {
navigate(`/product/${item.productId}`);
}}
role="button"
tabIndex={0}
onKeyDown={(e) => {
if (e.key === "Enter") {
navigate(`/product/${item.productId}`);
}
}}
className="text-R10 text-BLUE cursor-pointer shrink-0"
>
مشاهده محصول
</div>
</div>
<div className="flex items-center w-full justify-between text-R12">
<div className="flex gap-1 items-center justify-center">
<span>تعداد:</span>
<div className="text-R12 font-bold px-2 py-1 bg-WHITE3 rounded-md border">
{item.quantity}
</div>
</div>
<div className="flex gap-1 items-center justify-center">
{item.variant?.color?.value !== "UNSELECTED" && (
<>
<span>رنگ:</span>
<div
className="h-10 w-10 rounded-md shadow-md"
style={{
backgroundColor:
item.variant?.color?.value !== "UNSELECTED"
? item.variant?.color?.info.detail
: "",
}}
/>
</>
)}
</div>
<div className="flex gap-1 items-center justify-center">
{item.variant?.size?.value !== "UNSELECTED" && (
<>
<span>سایز:</span>
<div className="h-10 w-10 rounded-md shadow-md bg-BLACK text-WHITE text-R12 items-center justify-center flex">
{item.variant?.size?.value !== "UNSELECTED"
? item.variant?.size?.info.persian
: ""}
</div>
</>
)}
</div>
</div>
</div>
);
})}
</div>
</div>
)}
<div className="flex flex-col gap-2 px-4 py-2">
<div className="flex items-center gap-2 mb-3">
<Wallet size={20} />
<p className="text-B12 font-bold">مبلغ فاکتور:</p>
<p className="text-R12">
{formatPrice(order?.totalPrice || "0")} تومان
</p>
</div>
<div className="flex items-center gap-2 mb-3">
<User size={20} />
<p className="text-B12 font-bold">نام گیرنده:</p>
<p className="text-R12">{order.shippingInfo?.receiverName}</p>
</div>
<div className="flex items-center gap-2 mb-3">
<PhoneCall size={20} />
<p className="text-B12 font-bold">شمارهی گیرنده:</p>
<p className="text-R12">{order.shippingInfo?.receiverPhone}</p>
</div>
<div className="flex items-center gap-2 mb-3">
<MapPin size={20} />
<p className="text-B12 font-bold">آدرس:</p>
<p className="text-R12">{order.shippingInfo?.mainAddress}</p>
</div>
{order.shippingInfo?.entryReference ? (
<div className="flex items-center gap-2 mb-3">
<Signpost size={20} />
<p className="text-B12 font-bold">پلاک:</p>
<p className="text-R12">{order.shippingInfo.entryReference}</p>
</div>
) : null}
{order.shippingInfo?.details ? (
<div className="flex items-center gap-2 mb-3">
<NotebookPen size={20} />
<p className="text-B12 font-bold">توضیحات:</p>
<p className="text-R12">{order.shippingInfo.details}</p>
</div>
) : null}
<div className="flex items-center gap-2 mb-3">
<Mail size={20} />
<p className="text-B12 font-bold">کد پستی:</p>
<p className="text-R12">{order.shippingInfo?.postalCode}</p>
</div>
<div className="flex items-center gap-2 mb-3">
<Truck size={20} />
<p className="text-B12 font-bold">شیوه ارسال:</p>
<p className="text-R12">{courierName}</p>
</div>
</div>
</div>
{/* Action Buttons */}
{order.status === SellerOrderListStatusEnum.Pending && (
<div className="max-w-md mx-auto fixed bottom-[60px] left-0 right-0 bg-WHITE border-t p-4 flex gap-3">
<Button
variant="dark"
size="xl"
className="w-full text-WHITE bg-VITROWN_BLUE text-white"
disabled={isUpdating}
onClick={() => setIsAcceptDrawerOpen(true)}
>
<p className="text-R14">پذیرش سفارش</p>
</Button>
<Button
variant="primary"
size="xl"
className="w-full"
disabled={isUpdating}
onClick={() => setIsCancelModalOpen(true)}
>
<p className="text-R14">رد سفارش</p>
</Button>
</div>
)}
{order.status === SellerOrderListStatusEnum.Confirmed && (
<div className="max-w-md mx-auto fixed bottom-[60px] left-0 right-0 bg-WHITE border-t p-4 flex gap-3">
<Button
variant="dark"
size="xl"
className="w-full text-WHITE bg-VITROWN_BLUE text-white"
disabled={isUpdating}
onClick={() => setIsTrackingDrawerOpen(true)}
>
<Package size={16} className="ml-2" />
<p className="text-R14">افزودن کد رهگیری</p>
</Button>
</div>
)}
{order.status === SellerOrderListStatusEnum.Shipped && (
<div className="max-w-md mx-auto fixed bottom-[60px] left-0 right-0 bg-WHITE border-t p-4 flex gap-3">
<Button
variant="dark"
size="xl"
className="w-full text-WHITE bg-VITROWN_BLUE text-white"
disabled={isUpdating}
onClick={() => setIsEditTrackingDrawerOpen(true)}
>
<Edit size={16} className="ml-2" />
<p className="text-R14">ویرایش کد رهگیری</p>
</Button>
</div>
)}
{order.status === SellerOrderListStatusEnum.Cancelled && (
<div className="max-w-md mx-auto bg-WHITE border-t p-4 flex gap-3">
<p className="text-R12 text-GRAY">این سفارش لغو شده است</p>
</div>
)}
{order.status === SellerOrderListStatusEnum.Delivered && (
<div className="fixed bottom-[60px] left-0 right-0 bg-WHITE border-t p-4">
<div className="bg-green-50 border border-green-200 rounded-lg p-4 text-center">
<Package size={24} className="mx-auto mb-2 text-green-600" />
<p className="text-green-700 font-medium">
محصول با موفقیت به دست مشتری رسیده است
</p>
</div>
</div>
)}
</div>
<AcceptOrderDrawer
isAcceptDrawerOpen={isAcceptDrawerOpen}
setIsAcceptDrawerOpen={setIsAcceptDrawerOpen}
orderId={orderId}
setIsUpdating={setIsUpdating}
/>
<CancelOrderModal
isCancelModalOpen={isCancelModalOpen}
setIsCancelModalOpen={setIsCancelModalOpen}
orderId={orderId}
setIsUpdating={setIsUpdating}
/>
<AddTrackingDrawer
isTrackingDrawerOpen={isTrackingDrawerOpen}
setIsTrackingDrawerOpen={setIsTrackingDrawerOpen}
orderId={orderId}
setIsUpdating={setIsUpdating}
/>
<EditTrackingDrawer
isEditTrackingDrawerOpen={isEditTrackingDrawerOpen}
setIsEditTrackingDrawerOpen={setIsEditTrackingDrawerOpen}
orderId={orderId}
initialTrackingCode={order?.shippingInfo?.trackingCode || ""}
setIsUpdating={setIsUpdating}
/>
<ReactivateOrderModal
isReactivateModalOpen={isReactivateModalOpen}
setIsReactivateModalOpen={setIsReactivateModalOpen}
orderId={orderId}
setIsUpdating={setIsUpdating}
/>
</>
);
}
const AcceptOrderDrawer = ({
isAcceptDrawerOpen,
setIsAcceptDrawerOpen,
orderId,
setIsUpdating,
}: {
isAcceptDrawerOpen: boolean;
setIsAcceptDrawerOpen: (open: boolean) => void;
orderId: string;
setIsUpdating: (isUpdating: boolean) => void;
}) => {
const [trackingCode, setTrackingCode] = useState("");
const navigate = useNavigate();
const { storeId } = useParams();
const { mutate: updateOrder, isPending: isUpdating } = useUpdateSellerOrder();
setIsUpdating(isUpdating);
const handleAcceptOrder = () => {
if (!trackingCode.trim()) return;
updateOrder(
{
orderId,
data: {
status: SellerOrderUpdateStatusEnum.Shipped,
trackingCode: trackingCode.trim(),
},
},
{
onSuccess: () => {
setIsAcceptDrawerOpen(false);
setTrackingCode("");
toast({
title: "سفارش با موفقیت پذیرش شد",
description: "سفارش با موفقیت پذیرش شد",
});
navigate(`/store/${storeId}/orders`);
},
}
);
};
const handleAcceptOrderWithoutTrackingCode = () => {
updateOrder(
{ orderId, data: { status: SellerOrderUpdateStatusEnum.Confirmed } },
{
onSuccess: () => {
setIsAcceptDrawerOpen(false);
toast({
title: "سفارش با موفقیت پذیرش شد",
description: "سفارش با موفقیت پذیرش شد",
});
navigate(`/store/${storeId}/orders`);
},
}
);
};
return (
<Drawer open={isAcceptDrawerOpen} onOpenChange={setIsAcceptDrawerOpen}>
<DrawerTrigger asChild></DrawerTrigger>
<DrawerContent>
<DrawerHeader>
<DrawerTitle className="text-center">پذیرش سفارش</DrawerTitle>
<X
onClick={() => setIsAcceptDrawerOpen(false)}
className="absolute top-4 left-4 cursor-pointer"
/>
</DrawerHeader>
<div className="p-4 space-y-4">
<div>
<AppInput
inputTitle="کد رهگیری محصول ارسال شده"
inputPlaceholder="کد رهگیری را وارد کنید"
inputValue={trackingCode}
inputOnChange={(e) => setTrackingCode(e.target.value)}
className="w-full"
inputDir={trackingCode === "" ? "rtl" : "ltr"}
inputTitleFontSize="text-R14"
/>
</div>
</div>
<DrawerFooter>
<div className="flex gap-3">
<Button
onClick={handleAcceptOrder}
variant="dark"
size="xl"
disabled={!trackingCode.trim() || isUpdating}
className="flex-1"
>
{isUpdating ? "در حال ارسال..." : "ارسال"}
</Button>
<Button
variant="primary"
size="xl"
onClick={handleAcceptOrderWithoutTrackingCode}
className="flex-1"
>
بعدا ارسال میکنم
</Button>
</div>
</DrawerFooter>
</DrawerContent>
</Drawer>
);
};
const CancelOrderModal = ({
isCancelModalOpen,
setIsCancelModalOpen,
orderId,
setIsUpdating,
}: {
isCancelModalOpen: boolean;
setIsCancelModalOpen: (open: boolean) => void;
orderId: string;
setIsUpdating: (isUpdating: boolean) => void;
}) => {
const navigate = useNavigate();
const { storeId } = useParams();
const [cancelReason, setCancelReason] = useState<
SellerOrderUpdateCancelReasonEnum | ""
>("");
const [cancelDescription, setCancelDescription] = useState("");
const { mutate: updateOrder, isPending: isUpdating } = useUpdateSellerOrder();
setIsUpdating(isUpdating);
const handleCancelOrder = () => {
if (!cancelReason) return;
const data = {
status: SellerOrderUpdateStatusEnum.Cancelled,
cancelReason,
...(cancelReason === SellerOrderUpdateCancelReasonEnum.Other &&
cancelDescription.trim() && {
cancelDescription: cancelDescription.trim(),
}),
};
updateOrder(
{ orderId, data },
{
onSuccess: () => {
setIsCancelModalOpen(false);
setCancelReason("");
setCancelDescription("");
toast({
title: "سفارش با موفقیت لغو شد",
description: "سفارش با موفقیت لغو شد",
});
navigate(`/store/${storeId}/orders`);
},
}
);
};
return (
<Dialog open={isCancelModalOpen} onOpenChange={setIsCancelModalOpen}>
<DialogOverlay className="bg-BLACK/50" />
<DialogContent className="p-4 bg-WHITE overflow-y-auto rounded-[15px] w-[calc(100%-40px)]">
<DialogHeader className="text-center space-y-4">
<div className="flex justify-center">
<div className="p-2 bg-red-100 rounded-full">
<AlertTriangle className="h-6 w-6 text-red-600" />
</div>
</div>
<DialogTitle className="text-center">لغو سفارش</DialogTitle>
<p className="text-sm text-BLACK2">علت لغو کردن این سفارش چیست؟</p>
</DialogHeader>
<div className="space-y-4 py-4">
<RadioGroup
onValueChange={(value) =>
setCancelReason(value as SellerOrderUpdateCancelReasonEnum)
}
value={cancelReason}
className="flex flex-col gap-4 px-4"
dir="rtl"
>
<div className="flex items-center gap-1">
<RadioGroupItem
value={SellerOrderUpdateCancelReasonEnum.OutOfStock}
id="outOfStock"
className="size-5"
/>
<label htmlFor="outOfStock" className="flex flex-col gap-1">
<p className="text-R14">اتمام موجودی</p>
</label>
</div>
<div className="flex items-center gap-1">
<RadioGroupItem
value={SellerOrderUpdateCancelReasonEnum.OutOfServiceArea}
id="outOfServiceArea"
className="size-5"
/>
<label htmlFor="outOfServiceArea" className="flex flex-col gap-1">
<p className="text-R14">خارج از محدوده سرویس دهی</p>
</label>
</div>
<div className="flex items-center gap-1">
<RadioGroupItem
value={SellerOrderUpdateCancelReasonEnum.Other}
id="other"
className="size-5"
/>
<label htmlFor="other" className="flex flex-col gap-1">
<p className="text-R14">سایر دلایل</p>
</label>
</div>
</RadioGroup>
{cancelReason === SellerOrderUpdateCancelReasonEnum.Other && (
<div className="px-4">
<AppTextArea
inputTitle="توضیحات لغو سفارش"
inputPlaceholder="علت لغو سفارش را توضیح دهید..."
inputValue={cancelDescription}
inputOnChange={(e: React.ChangeEvent<HTMLTextAreaElement>) =>
setCancelDescription(e.target.value)
}
/>
</div>
)}
</div>
<DialogFooter>
<div className="flex gap-3 w-full">
<Button
onClick={handleCancelOrder}
disabled={
!cancelReason ||
(cancelReason === SellerOrderUpdateCancelReasonEnum.Other &&
!cancelDescription.trim()) ||
isUpdating
}
variant="dark"
size="xl"
className="flex-1"
>
{isUpdating ? "در حال پردازش..." : "تایید"}
</Button>
<Button
variant="primary"
size="xl"
onClick={() => setIsCancelModalOpen(false)}
className="flex-1"
>
انصراف
</Button>
</div>
</DialogFooter>
</DialogContent>
</Dialog>
);
};
const AddTrackingDrawer = ({
isTrackingDrawerOpen,
setIsTrackingDrawerOpen,
orderId,
setIsUpdating,
}: {
isTrackingDrawerOpen: boolean;
setIsTrackingDrawerOpen: (open: boolean) => void;
orderId: string;
setIsUpdating: (isUpdating: boolean) => void;
}) => {
const [trackingCode, setTrackingCode] = useState("");
const navigate = useNavigate();
const { storeId } = useParams();
const { mutate: updateOrder, isPending: isUpdating } = useUpdateSellerOrder();
setIsUpdating(isUpdating);
const handleAddTracking = () => {
if (!trackingCode.trim()) return;
updateOrder(
{
orderId,
data: {
status: SellerOrderUpdateStatusEnum.Shipped,
trackingCode: trackingCode.trim(),
},
},
{
onSuccess: () => {
setIsTrackingDrawerOpen(false);
setTrackingCode("");
toast({
title: "کد رهگیری با موفقیت اضافه شد",
description: "سفارش به حالت ارسال شده تغییر یافت",
});
navigate(`/store/${storeId}/orders`);
},
}
);
};
return (
<Drawer open={isTrackingDrawerOpen} onOpenChange={setIsTrackingDrawerOpen}>
<DrawerTrigger asChild></DrawerTrigger>
<DrawerContent>
<DrawerHeader>
<DrawerTitle className="text-center">افزودن کد رهگیری</DrawerTitle>
<X
onClick={() => setIsTrackingDrawerOpen(false)}
className="absolute top-4 left-4 cursor-pointer"
/>
</DrawerHeader>
<div className="p-4 space-y-4">
<div>
<AppInput
inputTitle="کد رهگیری محصول ارسال شده"
inputPlaceholder="کد رهگیری را وارد کنید"
inputValue={trackingCode}
inputOnChange={(e) => setTrackingCode(e.target.value)}
className="w-full"
inputDir={trackingCode === "" ? "rtl" : "ltr"}
inputTitleFontSize="text-R14"
/>
</div>
</div>
<DrawerFooter>
<div className="flex gap-3">
<Button
onClick={handleAddTracking}
variant="dark"
size="xl"
disabled={!trackingCode.trim() || isUpdating}
className="flex-1"
>
{isUpdating ? "در حال ارسال..." : "ارسال"}
</Button>
<Button
variant="primary"
size="xl"
onClick={() => setIsTrackingDrawerOpen(false)}
className="flex-1"
>
انصراف
</Button>
</div>
</DrawerFooter>
</DrawerContent>
</Drawer>
);
};
const EditTrackingDrawer = ({
isEditTrackingDrawerOpen,
setIsEditTrackingDrawerOpen,
orderId,
initialTrackingCode,
setIsUpdating,
}: {
isEditTrackingDrawerOpen: boolean;
setIsEditTrackingDrawerOpen: (open: boolean) => void;
orderId: string;
initialTrackingCode: string;
setIsUpdating: (isUpdating: boolean) => void;
}) => {
const [trackingCode, setTrackingCode] = useState(initialTrackingCode);
// Update tracking code when modal opens or initial value changes
useEffect(() => {
if (isEditTrackingDrawerOpen) {
setTrackingCode(initialTrackingCode);
}
}, [isEditTrackingDrawerOpen, initialTrackingCode]);
const navigate = useNavigate();
const { storeId } = useParams();
const { mutate: updateOrder, isPending: isUpdating } = useUpdateSellerOrder();
setIsUpdating(isUpdating);
const handleEditTracking = () => {
if (!trackingCode.trim()) return;
updateOrder(
{
orderId,
data: {
trackingCode: trackingCode.trim(),
},
},
{
onSuccess: () => {
setIsEditTrackingDrawerOpen(false);
toast({
title: "کد رهگیری با موفقیت ویرایش شد",
description: "کد رهگیری سفارش به‌روزرسانی شد",
});
navigate(`/store/${storeId}/orders`);
},
}
);
};
return (
<Drawer
open={isEditTrackingDrawerOpen}
onOpenChange={setIsEditTrackingDrawerOpen}
>
<DrawerTrigger asChild></DrawerTrigger>
<DrawerContent>
<DrawerHeader>
<DrawerTitle className="text-center">ویرایش کد رهگیری</DrawerTitle>
<X
onClick={() => setIsEditTrackingDrawerOpen(false)}
className="absolute top-4 left-4 cursor-pointer"
/>
</DrawerHeader>
<div className="p-4 space-y-4">
<div>
<AppInput
inputTitle="کد رهگیری محصول ارسال شده"
inputPlaceholder="کد رهگیری را وارد کنید"
inputValue={trackingCode}
inputOnChange={(e) => setTrackingCode(e.target.value)}
className="w-full"
inputDir={trackingCode === "" ? "rtl" : "ltr"}
inputTitleFontSize="text-R14"
/>
</div>
</div>
<DrawerFooter>
<div className="flex gap-3">
<Button
onClick={handleEditTracking}
variant="dark"
size="xl"
disabled={!trackingCode.trim() || isUpdating}
className="flex-1"
>
{isUpdating ? "در حال ویرایش..." : "ویرایش"}
</Button>
<Button
variant="primary"
size="xl"
onClick={() => setIsEditTrackingDrawerOpen(false)}
className="flex-1"
>
انصراف
</Button>
</div>
</DrawerFooter>
</DrawerContent>
</Drawer>
);
};
const ReactivateOrderModal = ({
isReactivateModalOpen,
setIsReactivateModalOpen,
orderId,
setIsUpdating,
}: {
isReactivateModalOpen: boolean;
setIsReactivateModalOpen: (open: boolean) => void;
orderId: string;
setIsUpdating: (isUpdating: boolean) => void;
}) => {
const navigate = useNavigate();
const { storeId } = useParams();
const { mutate: updateOrder, isPending: isUpdating } = useUpdateSellerOrder();
setIsUpdating(isUpdating);
const handleReactivateOrder = () => {
updateOrder(
{
orderId,
data: {
status: SellerOrderUpdateStatusEnum.Confirmed,
},
},
{
onSuccess: () => {
setIsReactivateModalOpen(false);
toast({
title: "سفارش با موفقیت فعال شد",
description: "سفارش به حالت تایید شده تغییر یافت",
});
navigate(`/store/${storeId}/orders`);
},
}
);
};
return (
<Dialog
open={isReactivateModalOpen}
onOpenChange={setIsReactivateModalOpen}
>
<DialogOverlay className="bg-BLACK/50" />
<DialogContent className="p-4 bg-WHITE overflow-y-auto rounded-[15px] w-[calc(100%-40px)]">
<DialogHeader className="text-center space-y-4">
<div className="flex justify-center">
<div className="p-2 bg-green-100 rounded-full">
<Package className="h-6 w-6 text-green-600" />
</div>
</div>
<DialogTitle className="text-center">
فعال کردن مجدد سفارش
</DialogTitle>
<p className="text-sm text-BLACK2">
آیا از فعال کردن مجدد این سفارش اطمینان دارید؟
</p>
</DialogHeader>
<DialogFooter>
<div className="flex gap-3 w-full">
<Button
onClick={handleReactivateOrder}
disabled={isUpdating}
variant="dark"
size="xl"
className="flex-1"
>
{isUpdating ? "در حال پردازش..." : "تایید"}
</Button>
<Button
variant="primary"
size="xl"
onClick={() => setIsReactivateModalOpen(false)}
className="flex-1"
>
انصراف
</Button>
</div>
</DialogFooter>
</DialogContent>
</Dialog>
);
};