update frontend
This commit is contained in:
@@ -25,7 +25,7 @@ const { date } = toRefs(props);
|
||||
|
||||
// state
|
||||
|
||||
const createdAt = usePersianTimeAgo(new Date(date.value));
|
||||
const createdAt = usePersianTimeAgo(date.value);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// imports
|
||||
|
||||
import useDownloadInvoice from "~/composables/api/orders/useDownloadInvoice";
|
||||
import usePersianDate from "~/composables/global/usePersianDate";
|
||||
|
||||
// types
|
||||
|
||||
@@ -15,6 +16,10 @@ const props = defineProps<Props>();
|
||||
|
||||
const { data } = toRefs(props);
|
||||
|
||||
// state
|
||||
|
||||
const { formatToPersian } = usePersianDate();
|
||||
|
||||
// queries
|
||||
|
||||
const { downloadFn, downloadIsLoading } = useDownloadInvoice(String(data.value.id));
|
||||
@@ -30,7 +35,7 @@ const { downloadFn, downloadIsLoading } = useDownloadInvoice(String(data.value.i
|
||||
{{ data.order_id ? `${data.order_id}#` : "--" }}
|
||||
</td>
|
||||
<td class="w-3/12 px-6 py-6 text-xs lg:text-sm font-medium whitespace-pre shrink-0">
|
||||
{{ data.created_at ?? "--" }}
|
||||
{{ data.created_at ? formatToPersian(data.created_at) : "--" }}
|
||||
</td>
|
||||
<td class="w-2/12 px-6 py-6 text-xs lg:text-sm whitespace-pre shrink-0">
|
||||
{{ data.count ? data.count : "--" }}
|
||||
@@ -53,10 +58,25 @@ const { downloadFn, downloadIsLoading } = useDownloadInvoice(String(data.value.i
|
||||
</div>
|
||||
</td>
|
||||
<td class="w-1/12 px-6 py-6 shrink-0">
|
||||
<div class="flex items-center gap-2">
|
||||
<NuxtLink :to="{ name: 'profile-purchases-and-orders-id', params: { id: data.id } }">
|
||||
<button
|
||||
class="size-9 lg:size-10 flex-center border border-slate-200 rounded-md"
|
||||
aria-label="مشاهده جزئیات سفارش"
|
||||
>
|
||||
<Icon
|
||||
name="ci:eye-open"
|
||||
class="**:stroke-black"
|
||||
size="20"
|
||||
/>
|
||||
</button>
|
||||
</NuxtLink>
|
||||
<button
|
||||
v-if="data.is_paid"
|
||||
@click="!downloadIsLoading ? downloadFn() : undefined"
|
||||
:disabled="downloadIsLoading"
|
||||
class="size-9 lg:size-10 flex-center border border-slate-200 rounded-md"
|
||||
aria-label="دانلود فاکتور"
|
||||
>
|
||||
<Icon
|
||||
v-if="downloadIsLoading"
|
||||
@@ -71,6 +91,7 @@ const { downloadFn, downloadIsLoading } = useDownloadInvoice(String(data.value.i
|
||||
size="20"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
|
||||
@@ -23,7 +23,10 @@
|
||||
<Skeleton class="w-full !h-10 !rounded-sm" />
|
||||
</td>
|
||||
<td class="w-1/12 px-6 py-6 shrink-0">
|
||||
<div class="flex items-center gap-2">
|
||||
<Skeleton class="!size-10 !rounded-sm" />
|
||||
<Skeleton class="!size-10 !rounded-sm" />
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
|
||||
@@ -21,7 +21,7 @@ const { is_user, files, date } = toRefs(props);
|
||||
|
||||
// state
|
||||
|
||||
const timeAgo = usePersianTimeAgo(new Date(date.value));
|
||||
const timeAgo = usePersianTimeAgo(date.value);
|
||||
|
||||
// queries
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@ const { data } = toRefs(props);
|
||||
|
||||
// computed
|
||||
|
||||
const createdTimeAgo = usePersianTimeAgo(new Date(data.value.created_at));
|
||||
const updatedTimeAgo = usePersianTimeAgo(new Date(data.value.updated_at));
|
||||
const createdTimeAgo = usePersianTimeAgo(data.value.created_at);
|
||||
const updatedTimeAgo = usePersianTimeAgo(data.value.updated_at);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -26,7 +26,7 @@ const useGetAllOrders = () => {
|
||||
const handleGetAllOrders = async () => {
|
||||
const { data } = await axios.get<GetAllOrdersResponse>(API_ENDPOINTS.orders.get_all, {
|
||||
params: {
|
||||
sort: sort.value ?? "created_at",
|
||||
sort: sort.value ?? "-created_at",
|
||||
status: status.value,
|
||||
offset: Number(page.value) * 10 - 10,
|
||||
limit: 10,
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
// imports
|
||||
|
||||
import { useQuery } from "@tanstack/vue-query";
|
||||
import type { ComputedRef } from "vue";
|
||||
import { API_ENDPOINTS, QUERY_KEYS } from "~/constants";
|
||||
|
||||
// types
|
||||
|
||||
export type GetOrderResponse = OrderDetail;
|
||||
|
||||
const useGetOrder = (id: ComputedRef<string>) => {
|
||||
// state
|
||||
|
||||
const { $axios: axios } = useNuxtApp();
|
||||
|
||||
// methods
|
||||
|
||||
const handleGetOrder = async () => {
|
||||
const { data } = await axios.get<GetOrderResponse>(`${API_ENDPOINTS.orders.get_one}/${id.value}`);
|
||||
return data;
|
||||
};
|
||||
|
||||
return useQuery({
|
||||
queryKey: [QUERY_KEYS.order, id],
|
||||
queryFn: () => handleGetOrder(),
|
||||
enabled: computed(() => !!id.value),
|
||||
});
|
||||
};
|
||||
|
||||
export default useGetOrder;
|
||||
@@ -26,7 +26,7 @@ const useGetAllTickets = () => {
|
||||
const handleGetAllTickets = async () => {
|
||||
const { data } = await axios.get<GetAllTicketsResponse>(API_ENDPOINTS.tickets.get_all, {
|
||||
params: {
|
||||
sort: sort.value ?? "created_at",
|
||||
sort: sort.value ?? "-created_at",
|
||||
filter: status.value,
|
||||
offset: Number(page.value) * 7 - 7,
|
||||
limit: 7,
|
||||
|
||||
@@ -1,11 +1,24 @@
|
||||
// composables/usePersianDate.ts
|
||||
import { format, toDate } from "date-fns-jalali";
|
||||
import { format } from "date-fns-jalali";
|
||||
import { faIR } from "date-fns-jalali/locale";
|
||||
import { Jalali } from "jalali-ts";
|
||||
|
||||
export default function usePersianDate() {
|
||||
const formatToPersian = (isoDate: string): string => {
|
||||
try {
|
||||
const date = toDate(new Date(isoDate));
|
||||
const yearStr = isoDate.slice(0, 4);
|
||||
const year = Number(yearStr);
|
||||
|
||||
// jDateTimeField from django_jalali sends Jalali years (13XX/14XX).
|
||||
// Normal DateTimeField sends Gregorian (19XX/20XX). Detect by year
|
||||
// and use jalali-ts to convert when needed — date-fns-jalali's
|
||||
// parseISO doesn't actually do calendar conversion.
|
||||
const date =
|
||||
!Number.isNaN(year) && year < 1700
|
||||
? Jalali.parse(isoDate).date
|
||||
: new Date(isoDate);
|
||||
|
||||
if (isNaN(date.getTime())) return "Invalid date";
|
||||
|
||||
const persianDate = format(date, "yyyy/MM/dd", { locale: faIR });
|
||||
|
||||
|
||||
@@ -1,12 +1,44 @@
|
||||
// composables/usePersianTimeAgo.ts
|
||||
import { formatDistance, toDate } from "date-fns-jalali";
|
||||
import { formatDistance } from "date-fns-jalali";
|
||||
import { faIR } from "date-fns-jalali/locale";
|
||||
import { Jalali } from "jalali-ts";
|
||||
|
||||
export function usePersianTimeAgo(date: Date) {
|
||||
const toGregorianDate = (input: Date | string): Date | null => {
|
||||
if (input instanceof Date) {
|
||||
return isNaN(input.getTime()) ? null : input;
|
||||
}
|
||||
if (typeof input !== "string" || !input) return null;
|
||||
|
||||
const yearStr = input.slice(0, 4);
|
||||
const year = Number(yearStr);
|
||||
|
||||
// jDateTimeField from django_jalali serializes with the Jalali year
|
||||
// (typically 13XX or 14XX). Anything below ~1700 is treated as Jalali
|
||||
// and converted to the equivalent Gregorian moment via jalali-ts.
|
||||
// date-fns-jalali's parseISO can't be used here — it parses the year
|
||||
// numerically without calendar conversion.
|
||||
if (!Number.isNaN(year) && year < 1700) {
|
||||
try {
|
||||
return Jalali.parse(input).date;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const native = new Date(input);
|
||||
return isNaN(native.getTime()) ? null : native;
|
||||
};
|
||||
|
||||
export function usePersianTimeAgo(date: Date | string) {
|
||||
const timeAgo = ref("");
|
||||
|
||||
const updateTimeAgo = () => {
|
||||
timeAgo.value = formatDistance(toDate(date), new Date(), {
|
||||
const parsed = toGregorianDate(date);
|
||||
if (!parsed) {
|
||||
timeAgo.value = "";
|
||||
return;
|
||||
}
|
||||
timeAgo.value = formatDistance(parsed, new Date(), {
|
||||
addSuffix: true,
|
||||
locale: faIR,
|
||||
});
|
||||
|
||||
@@ -56,6 +56,7 @@ export const API_ENDPOINTS = {
|
||||
},
|
||||
orders: {
|
||||
get_all: "/order/all",
|
||||
get_one: "/order",
|
||||
cart: {
|
||||
download_invoice: "/order/invoice",
|
||||
get_all: "/order/cart",
|
||||
@@ -94,6 +95,7 @@ export const QUERY_KEYS = {
|
||||
tickets: "tickets",
|
||||
ticket: "ticket",
|
||||
orders: "orders",
|
||||
order: "order",
|
||||
cart: "cart",
|
||||
transaction: "transaction",
|
||||
notifications: "notifications",
|
||||
|
||||
@@ -0,0 +1,316 @@
|
||||
<script setup lang="ts">
|
||||
import useGetOrder from "~/composables/api/orders/useGetOrder";
|
||||
import useDownloadInvoice from "~/composables/api/orders/useDownloadInvoice";
|
||||
import usePersianDate from "~/composables/global/usePersianDate";
|
||||
|
||||
// meta
|
||||
|
||||
useSeoMeta({
|
||||
title: "پنل کاربری جزئیات سفارش",
|
||||
});
|
||||
|
||||
definePageMeta({
|
||||
middleware: "check-is-logged-in",
|
||||
layout: "profile",
|
||||
});
|
||||
|
||||
// state
|
||||
|
||||
const route = useRoute();
|
||||
|
||||
const { formatToPersian } = usePersianDate();
|
||||
|
||||
// computed
|
||||
|
||||
const orderId = computed(() => route.params.id as string);
|
||||
|
||||
// queries
|
||||
|
||||
const { data: order, isLoading: orderIsLoading } = useGetOrder(orderId);
|
||||
|
||||
const { downloadFn, downloadIsLoading } = useDownloadInvoice(orderId.value);
|
||||
|
||||
// computed
|
||||
|
||||
const statusVariant = computed(() => {
|
||||
const status = order.value?.status;
|
||||
if (!status) return "neutral";
|
||||
if (["ADMIN_PENDING", "PENDING"].includes(status)) return "warning";
|
||||
if (["POSTED", "RECEIVED"].includes(status)) return "success";
|
||||
if (["CANCELED", "REFUND", "REFUNDED"].includes(status)) return "danger";
|
||||
return "neutral";
|
||||
});
|
||||
|
||||
const statusClass = computed(() => {
|
||||
return {
|
||||
warning: "text-warning-600 bg-warning-100 border-warning-600",
|
||||
success: "text-success-600 bg-success-100 border-success-600",
|
||||
danger: "text-danger-600 bg-danger-100 border-danger-600",
|
||||
neutral: "text-slate-600 bg-slate-100 border-slate-300",
|
||||
}[statusVariant.value];
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="w-full flex flex-col gap-5">
|
||||
<ProfilePageTitle
|
||||
:title="`جزئیات سفارش ${order?.order_id ? `${order.order_id}#` : ''}`"
|
||||
icon="ci:bi-cart"
|
||||
/>
|
||||
|
||||
<div class="w-full flex flex-col gap-5 lg:px-5">
|
||||
<div class="flex items-center justify-between gap-3 flex-wrap">
|
||||
<NuxtLink :to="{ name: 'profile-purchases-and-orders' }">
|
||||
<Button
|
||||
end-icon="ci:bi-arrow-left"
|
||||
size="md"
|
||||
class="rounded-full"
|
||||
>
|
||||
<span class="whitespace-pre">بازگشت به سفارشات</span>
|
||||
</Button>
|
||||
</NuxtLink>
|
||||
|
||||
<Button
|
||||
v-if="order?.is_paid"
|
||||
@click="!downloadIsLoading ? downloadFn() : undefined"
|
||||
:disabled="downloadIsLoading"
|
||||
end-icon="ci:bi-download"
|
||||
size="md"
|
||||
class="rounded-full"
|
||||
>
|
||||
<span class="whitespace-pre">دانلود فاکتور</span>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="orderIsLoading"
|
||||
class="w-full grid grid-cols-1 lg:grid-cols-3 gap-5"
|
||||
>
|
||||
<Skeleton class="!w-full !h-40 !rounded-xl lg:col-span-2" />
|
||||
<Skeleton class="!w-full !h-40 !rounded-xl" />
|
||||
<Skeleton class="!w-full !h-60 !rounded-xl lg:col-span-2" />
|
||||
<Skeleton class="!w-full !h-60 !rounded-xl" />
|
||||
</div>
|
||||
|
||||
<Placeholder
|
||||
v-else-if="!order"
|
||||
class="!w-full !py-[5rem]"
|
||||
icon="ci:bi-cart"
|
||||
title="سفارشی یافت نشد"
|
||||
/>
|
||||
|
||||
<div
|
||||
v-else
|
||||
class="w-full grid grid-cols-1 lg:grid-cols-3 gap-5"
|
||||
>
|
||||
<div
|
||||
class="lg:col-span-2 w-full flex flex-col gap-4 p-5 border border-slate-200 rounded-xl bg-slate-50"
|
||||
>
|
||||
<div class="flex items-center justify-between gap-3 flex-wrap">
|
||||
<div class="flex items-center gap-3">
|
||||
<Icon
|
||||
name="ci:bi-cart"
|
||||
class="**:fill-black"
|
||||
size="20"
|
||||
/>
|
||||
<span class="text-sm font-semibold">اطلاعات سفارش</span>
|
||||
</div>
|
||||
<div
|
||||
class="rounded-full py-1.5 px-3 text-xs border"
|
||||
:class="statusClass"
|
||||
>
|
||||
{{ order.verbose_status ?? "--" }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3 text-xs lg:text-sm">
|
||||
<div class="flex items-center justify-between gap-2">
|
||||
<span class="text-dynamic-secondary">شماره سفارش:</span>
|
||||
<span class="font-medium text-cyan-600">{{ order.order_id ? `${order.order_id}#` : "--" }}</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between gap-2">
|
||||
<span class="text-dynamic-secondary">تاریخ ثبت:</span>
|
||||
<span class="font-medium">
|
||||
{{ order.created_at ? formatToPersian(order.created_at) : "--" }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between gap-2">
|
||||
<span class="text-dynamic-secondary">تعداد اقلام:</span>
|
||||
<span class="font-medium">{{ order.count ?? "--" }}</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between gap-2">
|
||||
<span class="text-dynamic-secondary">وضعیت پرداخت:</span>
|
||||
<span class="font-medium">
|
||||
{{ order.is_paid ? "پرداخت شده" : "پرداخت نشده" }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="w-full flex flex-col gap-4 p-5 border border-slate-200 rounded-xl bg-slate-50"
|
||||
>
|
||||
<div class="flex items-center gap-3">
|
||||
<Icon
|
||||
name="ci:bi-map"
|
||||
class="**:fill-black"
|
||||
size="20"
|
||||
/>
|
||||
<span class="text-sm font-semibold">آدرس تحویل</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="order.address"
|
||||
class="flex flex-col gap-2 text-xs lg:text-sm"
|
||||
>
|
||||
<div class="flex items-center justify-between gap-2">
|
||||
<span class="text-dynamic-secondary">گیرنده:</span>
|
||||
<span class="font-medium">{{ order.address.name ?? "--" }}</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between gap-2">
|
||||
<span class="text-dynamic-secondary">شماره تماس:</span>
|
||||
<span class="font-medium">{{ order.address.phone ?? "--" }}</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between gap-2">
|
||||
<span class="text-dynamic-secondary">استان / شهر:</span>
|
||||
<span class="font-medium">
|
||||
{{ order.address.province ?? "--" }} / {{ order.address.city ?? "--" }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between gap-2">
|
||||
<span class="text-dynamic-secondary">کد پستی:</span>
|
||||
<span class="font-medium">{{ order.address.postal_code ?? "--" }}</span>
|
||||
</div>
|
||||
<div class="text-dynamic-secondary leading-[180%]">
|
||||
{{ order.address.address ?? "--" }}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="text-xs text-dynamic-secondary"
|
||||
>
|
||||
آدرسی ثبت نشده است
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="lg:col-span-2 w-full flex flex-col gap-4 p-5 border border-slate-200 rounded-xl bg-slate-50"
|
||||
>
|
||||
<div class="flex items-center gap-3">
|
||||
<Icon
|
||||
name="ci:bi-box"
|
||||
class="**:fill-black"
|
||||
size="20"
|
||||
/>
|
||||
<span class="text-sm font-semibold">اقلام سفارش</span>
|
||||
</div>
|
||||
|
||||
<Placeholder
|
||||
v-if="!order.items?.length"
|
||||
class="!w-full !py-10"
|
||||
icon="ci:bi-box"
|
||||
title="کالایی در این سفارش ثبت نشده"
|
||||
/>
|
||||
|
||||
<ul
|
||||
v-else
|
||||
class="w-full flex flex-col divide-y divide-slate-200"
|
||||
>
|
||||
<li
|
||||
v-for="item in order.items"
|
||||
:key="item.id"
|
||||
class="w-full flex items-center gap-3 py-4"
|
||||
>
|
||||
<NuxtImg
|
||||
v-if="item.product?.image"
|
||||
:src="item.product.image"
|
||||
loading="lazy"
|
||||
fetch-priority="low"
|
||||
class="size-16 lg:size-20 rounded-100 border border-slate-200 object-cover"
|
||||
/>
|
||||
<div class="flex-1 flex flex-col gap-1">
|
||||
<NuxtLink
|
||||
v-if="item.product?.slug"
|
||||
:to="`/product/${item.product.slug}`"
|
||||
class="text-xs lg:text-sm font-semibold line-clamp-2 hover:text-cyan-600 transition-colors"
|
||||
>
|
||||
{{ item.product.title ?? "--" }}
|
||||
</NuxtLink>
|
||||
<span
|
||||
v-else
|
||||
class="text-xs lg:text-sm font-semibold line-clamp-2"
|
||||
>
|
||||
{{ item.product?.title ?? "--" }}
|
||||
</span>
|
||||
<span class="text-xs text-dynamic-secondary">
|
||||
تعداد: {{ item.quantity }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex flex-col items-end gap-1 text-xs lg:text-sm">
|
||||
<span class="font-medium whitespace-pre">{{ item.final_price }}</span>
|
||||
<span
|
||||
v-if="item.discount_percent && item.discount_percent > 0"
|
||||
class="text-dynamic-secondary line-through whitespace-pre"
|
||||
>
|
||||
{{ item.price }}
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="w-full flex flex-col gap-4 p-5 border border-slate-200 rounded-xl bg-slate-50 h-fit"
|
||||
>
|
||||
<div class="flex items-center gap-3">
|
||||
<Icon
|
||||
name="ci:bi-tag"
|
||||
class="**:fill-black"
|
||||
size="20"
|
||||
/>
|
||||
<span class="text-sm font-semibold">خلاصه فاکتور</span>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-3 text-xs lg:text-sm">
|
||||
<div
|
||||
v-if="order.cart_total"
|
||||
class="flex items-center justify-between gap-2 text-slate-800"
|
||||
>
|
||||
<span>جمع سبد:</span>
|
||||
<span>{{ order.cart_total }}</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="order.discount_amount"
|
||||
class="flex items-center justify-between gap-2 text-red-700"
|
||||
>
|
||||
<span>تخفیف:</span>
|
||||
<span>{{ order.discount_amount }}</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="order.special_discount_total"
|
||||
class="flex items-center justify-between gap-2 text-green-700"
|
||||
>
|
||||
<span>تخفیف ویژه:</span>
|
||||
<span>{{ order.special_discount_total }}</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="order.tax"
|
||||
class="flex items-center justify-between gap-2 text-slate-800"
|
||||
>
|
||||
<span>مالیات:</span>
|
||||
<span>{{ order.tax }}</span>
|
||||
</div>
|
||||
<div
|
||||
class="flex items-center justify-between gap-2 pt-3 border-t border-slate-200 text-slate-900 font-semibold"
|
||||
>
|
||||
<span>مبلغ نهایی:</span>
|
||||
<span>{{ order.final_price ?? "--" }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -26,11 +26,11 @@ const tableHeads = ref(["دسته بندی", "موضوع", "تاریخ ایجا
|
||||
const sortFilters = ref([
|
||||
{
|
||||
title: "جدید ترین",
|
||||
value: "created_at",
|
||||
value: "-created_at",
|
||||
},
|
||||
{
|
||||
title: "قدیمی ترین",
|
||||
value: "-created_at",
|
||||
value: "created_at",
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -76,8 +76,8 @@ const paginationData = computed(() => {
|
||||
// methods
|
||||
|
||||
const clearFilters = () => {
|
||||
sort.value = "";
|
||||
status.value = "";
|
||||
sort.value = undefined;
|
||||
status.value = undefined;
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
Vendored
+21
@@ -223,6 +223,27 @@ declare global {
|
||||
special_discount_total?: string;
|
||||
};
|
||||
|
||||
type OrderDetailItem = {
|
||||
id: number;
|
||||
product: CartItem["product"];
|
||||
quantity: number;
|
||||
price: string;
|
||||
final_price: string;
|
||||
discount: number;
|
||||
discount_amount: string;
|
||||
special_discount_amount: string | null;
|
||||
discount_percent?: number;
|
||||
};
|
||||
|
||||
type OrderDetail = Order & {
|
||||
items: OrderDetailItem[];
|
||||
address: Address | null;
|
||||
tax: number | string | null;
|
||||
cart_total: number | string | null;
|
||||
discount_code: DiscountCode | null;
|
||||
discount_amount: number | string | null;
|
||||
};
|
||||
|
||||
type DiscountCode = {
|
||||
code: string;
|
||||
percent: number;
|
||||
|
||||
Reference in New Issue
Block a user