This commit is contained in:
@@ -4,6 +4,7 @@ import {
|
|||||||
PaymentMethodsResponse,
|
PaymentMethodsResponse,
|
||||||
CreateOrderResponse,
|
CreateOrderResponse,
|
||||||
OrderDetailResponse,
|
OrderDetailResponse,
|
||||||
|
PayOrderResponse,
|
||||||
} from "../types/Types";
|
} from "../types/Types";
|
||||||
|
|
||||||
export const getShipmentMethod = async (): Promise<ShipmentMethodsResponse> => {
|
export const getShipmentMethod = async (): Promise<ShipmentMethodsResponse> => {
|
||||||
@@ -81,7 +82,7 @@ export const cancelOrder = async (id: string) => {
|
|||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const confirmOrder = async (id: string) => {
|
export const confirmOrder = async (id: string): Promise<PayOrderResponse> => {
|
||||||
const { data } = await api.get(`/public/payments/pay-order/${id}`);
|
const { data } = await api.get<PayOrderResponse>(`/public/payments/pay-order/${id}`);
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -272,6 +272,12 @@ export interface CreateOrderData {
|
|||||||
|
|
||||||
export type CreateOrderResponse = BaseResponse<CreateOrderData>;
|
export type CreateOrderResponse = BaseResponse<CreateOrderData>;
|
||||||
|
|
||||||
|
export interface PayOrderData {
|
||||||
|
paymentUrl?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type PayOrderResponse = BaseResponse<PayOrderData>;
|
||||||
|
|
||||||
export interface OrderDetailUser {
|
export interface OrderDetailUser {
|
||||||
id: string;
|
id: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import clsx from "clsx";
|
|||||||
import { Clock } from "iconsax-react";
|
import { Clock } from "iconsax-react";
|
||||||
import { useParams, useRouter } from "next/navigation";
|
import { useParams, useRouter } from "next/navigation";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useCancelOrder, useGetOrderDetail } from "../../checkout/hooks/useOrderData";
|
import { useCancelOrder, useConfirmOrder, useGetOrderDetail } from "../../checkout/hooks/useOrderData";
|
||||||
import type { OrderDetailItem } from "../../checkout/types/Types";
|
import type { OrderDetailItem } from "../../checkout/types/Types";
|
||||||
|
|
||||||
const orderItemToProduct = (item: OrderDetailItem): Product => {
|
const orderItemToProduct = (item: OrderDetailItem): Product => {
|
||||||
@@ -107,6 +107,31 @@ function OrderTrackingPage() {
|
|||||||
const { state: cancelModal, toggle: toggleCancelModal } = useToggle();
|
const { state: cancelModal, toggle: toggleCancelModal } = useToggle();
|
||||||
const { data: orderDetail, isLoading } = useGetOrderDetail(id as string);
|
const { data: orderDetail, isLoading } = useGetOrderDetail(id as string);
|
||||||
const { mutate: cancelOrder } = useCancelOrder();
|
const { mutate: cancelOrder } = useCancelOrder();
|
||||||
|
const { mutate: payOrder, isPending: isPaying } = useConfirmOrder();
|
||||||
|
|
||||||
|
const orderStatus = orderDetail?.data?.status;
|
||||||
|
const showPayButton = orderStatus === "pendingPayment" || orderStatus === "needConfirmation";
|
||||||
|
const isPayDisabled = orderStatus === "needConfirmation";
|
||||||
|
|
||||||
|
const onPayOrder = () => {
|
||||||
|
if (!id || isPayDisabled) return;
|
||||||
|
|
||||||
|
payOrder(id as string, {
|
||||||
|
onSuccess: (data) => {
|
||||||
|
const paymentUrl = data?.data?.paymentUrl;
|
||||||
|
if (paymentUrl) {
|
||||||
|
toast("در حال ریدایرکت به صفحه پرداخت...", "success");
|
||||||
|
window.location.href = paymentUrl;
|
||||||
|
} else {
|
||||||
|
queryClient.invalidateQueries({ queryKey: ["order-detail", id] });
|
||||||
|
toast("پرداخت با موفقیت انجام شد", "success");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onError: (error) => {
|
||||||
|
toast(extractErrorMessage(error), "error");
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const onCancelOrder = (e: React.MouseEvent | null) => {
|
const onCancelOrder = (e: React.MouseEvent | null) => {
|
||||||
if (!e || !id) return;
|
if (!e || !id) return;
|
||||||
@@ -199,7 +224,7 @@ function OrderTrackingPage() {
|
|||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
{orderDetail.data.items.map((item) => {
|
{orderDetail.data.items.map((item) => {
|
||||||
const product = orderItemToProduct(item);
|
const product = orderItemToProduct(item);
|
||||||
const showPendingBadge = isVariablePricing(product);
|
const needsConfirmation = isVariablePricing(product) || product.needAdminAcceptance;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MenuItemRenderer key={item.id}>
|
<MenuItemRenderer key={item.id}>
|
||||||
@@ -208,11 +233,18 @@ function OrderTrackingPage() {
|
|||||||
variantId={item.variant.id}
|
variantId={item.variant.id}
|
||||||
variantValue={item.variant.value}
|
variantValue={item.variant.value}
|
||||||
readOnly
|
readOnly
|
||||||
|
displayQuantity={item.quantity}
|
||||||
badge={
|
badge={
|
||||||
showPendingBadge ? (
|
needsConfirmation ? (
|
||||||
<span className="inline-block rounded-lg bg-orange-50 dark:bg-orange-950/40 px-3 py-1.5 text-xs text-orange-600 dark:text-orange-400">
|
item.status === "confirmed" ? (
|
||||||
{ordersTranslations.itemStatus.needConfirmation}
|
<span className="inline-block rounded-lg bg-green-50 dark:bg-green-950/40 px-3 py-1.5 text-xs text-green-600 dark:text-green-400">
|
||||||
</span>
|
{ordersTranslations.itemStatus.confirmed}
|
||||||
|
</span>
|
||||||
|
) : (
|
||||||
|
<span className="inline-block rounded-lg bg-orange-50 dark:bg-orange-950/40 px-3 py-1.5 text-xs text-orange-600 dark:text-orange-400">
|
||||||
|
{ordersTranslations.itemStatus.needConfirmation}
|
||||||
|
</span>
|
||||||
|
)
|
||||||
) : undefined
|
) : undefined
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
@@ -237,17 +269,28 @@ function OrderTrackingPage() {
|
|||||||
|
|
||||||
<div className="p-4 border-t border-border bg-container">
|
<div className="p-4 border-t border-border bg-container">
|
||||||
<div className="max-w-2xl mx-auto grid grid-cols-2 gap-4">
|
<div className="max-w-2xl mx-auto grid grid-cols-2 gap-4">
|
||||||
<Button className="dark:bg-white dark:text-black! dark:hover:bg-gray-100" onClick={() => router.push(`/${name}`)} type="button">
|
<Button className="bg-disabled! text-foreground!" onClick={() => router.push(`/${name}`)} type="button">
|
||||||
بازگشت به منو
|
بازگشت به منو
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
{showPayButton ? (
|
||||||
type="submit"
|
<Button
|
||||||
onClick={toggleCancelModal}
|
type="button"
|
||||||
className="bg-disabled! text-foreground!"
|
onClick={onPayOrder}
|
||||||
disabled={orderDetail?.data?.status === "cancelled" || orderDetail?.data?.status === "delivered" || orderDetail?.data?.status === "delivering"}
|
disabled={isPayDisabled}
|
||||||
>
|
pending={isPaying}
|
||||||
لغو سفارش
|
>
|
||||||
</Button>
|
پرداخت
|
||||||
|
</Button>
|
||||||
|
) : (
|
||||||
|
<Button
|
||||||
|
type="submit"
|
||||||
|
onClick={toggleCancelModal}
|
||||||
|
className="bg-disabled! text-foreground!"
|
||||||
|
disabled={orderDetail?.data?.status === "cancelled" || orderDetail?.data?.status === "delivered" || orderDetail?.data?.status === "delivering"}
|
||||||
|
>
|
||||||
|
لغو سفارش
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
import { useCart } from "@/app/[name]/(Dialogs)/cart/hook/useCart";
|
import { useCart } from "@/app/[name]/(Dialogs)/cart/hook/useCart";
|
||||||
import type { Product, ProductImage } from "@/app/[name]/(Main)/types/Types";
|
import type { Product, ProductImage } from "@/app/[name]/(Main)/types/Types";
|
||||||
import { getPrimaryVariantId, getProductEffectivePrice, getPurchaseUnitLabel, hasVariants, isVariablePricing } from "@/app/[name]/(Main)/types/Types";
|
import { formatPurchaseQuantity, getPrimaryVariantId, getProductEffectivePrice, getPurchaseUnitLabel, hasVariants, isVariablePricing } from "@/app/[name]/(Main)/types/Types";
|
||||||
import { CartQuantityControl } from "@/components/CartQuantityControl";
|
import { CartQuantityControl } from "@/components/CartQuantityControl";
|
||||||
import { ArrowLeft } from "iconsax-react";
|
import { ArrowLeft } from "iconsax-react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
@@ -22,11 +22,13 @@ interface MenuItemProps {
|
|||||||
viewMode?: MenuItemViewMode;
|
viewMode?: MenuItemViewMode;
|
||||||
/** فقط نمایش اطلاعات بدون دکمههای افزودن/جزئیات */
|
/** فقط نمایش اطلاعات بدون دکمههای افزودن/جزئیات */
|
||||||
readOnly?: boolean;
|
readOnly?: boolean;
|
||||||
|
/** تعداد انتخابشده — در حالت readOnly نمایش داده میشود */
|
||||||
|
displayQuantity?: number;
|
||||||
/** برچسب اختیاری بالای آیتم */
|
/** برچسب اختیاری بالای آیتم */
|
||||||
badge?: ReactNode;
|
badge?: ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MenuItem = ({ product, variantId: variantIdProp, variantValue: variantValueProp, viewMode = "list", readOnly = false, badge }: MenuItemProps) => {
|
const MenuItem = ({ product, variantId: variantIdProp, variantValue: variantValueProp, viewMode = "list", readOnly = false, displayQuantity, badge }: MenuItemProps) => {
|
||||||
const { items, addToCart, removeFromCart, isCartMutating } = useCart();
|
const { items, addToCart, removeFromCart, isCartMutating } = useCart();
|
||||||
const params = useParams<{ name: string }>();
|
const params = useParams<{ name: string }>();
|
||||||
const name = params?.name || "";
|
const name = params?.name || "";
|
||||||
@@ -102,6 +104,14 @@ const MenuItem = ({ product, variantId: variantIdProp, variantValue: variantValu
|
|||||||
|
|
||||||
const hasDiscount = useMemo(() => (product.discount || 0) > 0, [product.discount]);
|
const hasDiscount = useMemo(() => (product.discount || 0) > 0, [product.discount]);
|
||||||
|
|
||||||
|
const quantityLabel = useMemo(() => {
|
||||||
|
if (displayQuantity == null) return null;
|
||||||
|
if (withVariablePricing) {
|
||||||
|
return formatPurchaseQuantity(displayQuantity, product.purchaseUnit);
|
||||||
|
}
|
||||||
|
return `${displayQuantity.toLocaleString("fa-IR")}×`;
|
||||||
|
}, [displayQuantity, withVariablePricing, product.purchaseUnit]);
|
||||||
|
|
||||||
const handleAddToCart = () => {
|
const handleAddToCart = () => {
|
||||||
if (variantId) addToCart(variantId);
|
if (variantId) addToCart(variantId);
|
||||||
};
|
};
|
||||||
@@ -185,7 +195,11 @@ const MenuItem = ({ product, variantId: variantIdProp, variantValue: variantValu
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{!readOnly && (
|
{readOnly && quantityLabel ? (
|
||||||
|
<div className="flex flex-col justify-end shrink-0">
|
||||||
|
<span className="text-sm font-semibold text-foreground">{quantityLabel}</span>
|
||||||
|
</div>
|
||||||
|
) : !readOnly ? (
|
||||||
<div className="flex flex-col justify-end shrink-0">
|
<div className="flex flex-col justify-end shrink-0">
|
||||||
{showDetailsInsteadOfAdd ? (
|
{showDetailsInsteadOfAdd ? (
|
||||||
<div className="w-[115px]">
|
<div className="w-[115px]">
|
||||||
@@ -200,7 +214,7 @@ const MenuItem = ({ product, variantId: variantIdProp, variantValue: variantValu
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
// export const API_BASE_URL = "https://dmenuplus-api.dev.danakcorp.com";
|
// export const API_BASE_URL = "https://dmenuplus-api.dev.danakcorp.com";
|
||||||
// export const API_BASE_URL = "https://dkala-api.danakcorp.com";
|
export const API_BASE_URL = "https://dkala-api.danakcorp.com";
|
||||||
export const API_BASE_URL = "http://192.168.99.131:4000";
|
// export const API_BASE_URL = "http://192.168.99.131:4000";
|
||||||
export const TOKEN_NAME = "dkala-t";
|
export const TOKEN_NAME = "dkala-t";
|
||||||
export const REFRESH_TOKEN_NAME = "dkala-rt";
|
export const REFRESH_TOKEN_NAME = "dkala-rt";
|
||||||
|
|||||||
@@ -20,7 +20,8 @@
|
|||||||
"Wallet": "پرداخت با کیف پول"
|
"Wallet": "پرداخت با کیف پول"
|
||||||
},
|
},
|
||||||
"itemStatus": {
|
"itemStatus": {
|
||||||
"needConfirmation": "در انتظار تایید قیمت نهایی"
|
"needConfirmation": "در انتظار تایید قیمت نهایی",
|
||||||
|
"confirmed": "تایید شده"
|
||||||
},
|
},
|
||||||
"status": {
|
"status": {
|
||||||
"new": "سفارش جدید",
|
"new": "سفارش جدید",
|
||||||
|
|||||||
Reference in New Issue
Block a user