compelete variable
deploy to danak / build_and_deploy (push) Has been cancelled

This commit is contained in:
hamid zarghami
2026-06-29 09:37:07 +03:30
parent a269266897
commit cc27bce1b2
6 changed files with 89 additions and 24 deletions
@@ -4,6 +4,7 @@ import {
PaymentMethodsResponse,
CreateOrderResponse,
OrderDetailResponse,
PayOrderResponse,
} from "../types/Types";
export const getShipmentMethod = async (): Promise<ShipmentMethodsResponse> => {
@@ -81,7 +82,7 @@ export const cancelOrder = async (id: string) => {
return data;
};
export const confirmOrder = async (id: string) => {
const { data } = await api.get(`/public/payments/pay-order/${id}`);
export const confirmOrder = async (id: string): Promise<PayOrderResponse> => {
const { data } = await api.get<PayOrderResponse>(`/public/payments/pay-order/${id}`);
return data;
};
@@ -272,6 +272,12 @@ export interface CreateOrderData {
export type CreateOrderResponse = BaseResponse<CreateOrderData>;
export interface PayOrderData {
paymentUrl?: string;
}
export type PayOrderResponse = BaseResponse<PayOrderData>;
export interface OrderDetailUser {
id: string;
createdAt: string;
@@ -16,7 +16,7 @@ import clsx from "clsx";
import { Clock } from "iconsax-react";
import { useParams, useRouter } from "next/navigation";
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";
const orderItemToProduct = (item: OrderDetailItem): Product => {
@@ -107,6 +107,31 @@ function OrderTrackingPage() {
const { state: cancelModal, toggle: toggleCancelModal } = useToggle();
const { data: orderDetail, isLoading } = useGetOrderDetail(id as string);
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) => {
if (!e || !id) return;
@@ -199,7 +224,7 @@ function OrderTrackingPage() {
<div className="flex flex-col gap-4">
{orderDetail.data.items.map((item) => {
const product = orderItemToProduct(item);
const showPendingBadge = isVariablePricing(product);
const needsConfirmation = isVariablePricing(product) || product.needAdminAcceptance;
return (
<MenuItemRenderer key={item.id}>
@@ -208,11 +233,18 @@ function OrderTrackingPage() {
variantId={item.variant.id}
variantValue={item.variant.value}
readOnly
displayQuantity={item.quantity}
badge={
showPendingBadge ? (
<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>
needsConfirmation ? (
item.status === "confirmed" ? (
<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">
{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
}
/>
@@ -237,17 +269,28 @@ function OrderTrackingPage() {
<div className="p-4 border-t border-border bg-container">
<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
type="submit"
onClick={toggleCancelModal}
className="bg-disabled! text-foreground!"
disabled={orderDetail?.data?.status === "cancelled" || orderDetail?.data?.status === "delivered" || orderDetail?.data?.status === "delivering"}
>
لغو سفارش
</Button>
{showPayButton ? (
<Button
type="button"
onClick={onPayOrder}
disabled={isPayDisabled}
pending={isPaying}
>
پرداخت
</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>
+18 -4
View File
@@ -3,7 +3,7 @@
import { useCart } from "@/app/[name]/(Dialogs)/cart/hook/useCart";
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 { ArrowLeft } from "iconsax-react";
import Link from "next/link";
@@ -22,11 +22,13 @@ interface MenuItemProps {
viewMode?: MenuItemViewMode;
/** فقط نمایش اطلاعات بدون دکمه‌های افزودن/جزئیات */
readOnly?: boolean;
/** تعداد انتخاب‌شده — در حالت readOnly نمایش داده می‌شود */
displayQuantity?: number;
/** برچسب اختیاری بالای آیتم */
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 params = useParams<{ name: string }>();
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 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 = () => {
if (variantId) addToCart(variantId);
};
@@ -185,7 +195,11 @@ const MenuItem = ({ product, variantId: variantIdProp, variantValue: variantValu
)}
</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">
{showDetailsInsteadOfAdd ? (
<div className="w-[115px]">
@@ -200,7 +214,7 @@ const MenuItem = ({ product, variantId: variantIdProp, variantValue: variantValu
</div>
)}
</div>
)}
) : null}
</div>
</>
);
+2 -2
View File
@@ -1,5 +1,5 @@
// 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 = "http://192.168.99.131:4000";
export const API_BASE_URL = "https://dkala-api.danakcorp.com";
// export const API_BASE_URL = "http://192.168.99.131:4000";
export const TOKEN_NAME = "dkala-t";
export const REFRESH_TOKEN_NAME = "dkala-rt";
+2 -1
View File
@@ -20,7 +20,8 @@
"Wallet": "پرداخت با کیف پول"
},
"itemStatus": {
"needConfirmation": "در انتظار تایید قیمت نهایی"
"needConfirmation": "در انتظار تایید قیمت نهایی",
"confirmed": "تایید شده"
},
"status": {
"new": "سفارش جدید",