fix(dashboard): transactions tab uses real payment fields + empty state
The transactions list/card read mock fields (appointment_details, row.amount, status 'received') and iterated user.turns.done. Pass the real payments array and read order_id/type/created_at/amount_rials/status from Payment.toArray(); map status to Persian labels, show rials→toman, and render an empty state when there are no transactions. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,39 +1,36 @@
|
|||||||
import CircularLoading from "@/app/component/loading/Circular";
|
|
||||||
import TextLoading from "@/app/component/loading/Text";
|
import TextLoading from "@/app/component/loading/Text";
|
||||||
import Image from "next/image";
|
import { convertTimestampToJalali } from "@/helper";
|
||||||
import { convertTimestampToJalali, convertTimestampToTime } from "@/helper";
|
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
|
||||||
|
const PAYMENT_STATUS = {
|
||||||
|
success: { label: "پرداخت شده", cls: "bg-[#E8FADD] text-[#75E22E]" },
|
||||||
|
pending: { label: "در انتظار", cls: "bg-[#FFF3DD] text-[#FDBA35]" },
|
||||||
|
failed: { label: "ناموفق", cls: "bg-[#FFE3E2] text-[#FF5450]" },
|
||||||
|
cancelled: { label: "لغو شده", cls: "bg-[#FFE3E2] text-[#FF5450]" },
|
||||||
|
refunded: { label: "بازگشت وجه", cls: "bg-[#EFEFEF] text-[#616161]" },
|
||||||
|
};
|
||||||
|
|
||||||
|
const TYPE_LABELS = {
|
||||||
|
appointment: "نوبت",
|
||||||
|
subscription: "اشتراک",
|
||||||
|
sms_wallet: "کیف پول پیامک",
|
||||||
|
};
|
||||||
|
|
||||||
function Card({ data, loading }) {
|
function Card({ data, loading }) {
|
||||||
|
const status = PAYMENT_STATUS[data.status] || { label: data.status, cls: "bg-[#FFE3E2] text-[#FF5450]" };
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li className="p-[12px] shadow-[0px_1px_24.8px_0px_rgba(204,_204,_204,_0.18)] bg-[#FFF] rounded-[8px]">
|
<li className="p-[12px] shadow-[0px_1px_24.8px_0px_rgba(204,_204,_204,_0.18)] bg-[#FFF] rounded-[8px]">
|
||||||
<div className="flex items-center justify-between w-full">
|
<div className="flex items-center justify-between w-full">
|
||||||
<div className="flex items-center justify-start gap-[8px]">
|
<TextLoading width={120} height={18} loading={loading}>
|
||||||
<TextLoading width={120} height={18} loading={loading}>
|
<p className="text-[#616161] text-[14px] font-medium">
|
||||||
<p className="text-[#616161] text-[14px] font-medium">
|
{TYPE_LABELS[data.type] || data.type || "--"}
|
||||||
{data.appointment_details?.doctor_name || "--"}
|
</p>
|
||||||
</p>
|
</TextLoading>
|
||||||
</TextLoading>
|
|
||||||
</div>
|
|
||||||
<TextLoading loading={loading} width={95} height={25}>
|
<TextLoading loading={loading} width={95} height={25}>
|
||||||
<Link href={`/payment/${data.uuid}`}>
|
<Link href={`/payment/${data.uuid}`}>
|
||||||
<div
|
<div className={`w-[100px] p-[4px] rounded-[4px] text-center text-[14px] font-medium cursor-pointer select-none ${status.cls}`}>
|
||||||
className={`
|
{status.label}
|
||||||
w-[100px] p-[4px] rounded-[4px] text-center text-[14px] font-medium cursor-pointer select-none
|
|
||||||
${data.status === "received"
|
|
||||||
? "bg-[#E8FADD] text-[#75E22E]"
|
|
||||||
: data.status === "pending"
|
|
||||||
? "bg-[#FFF3DD] text-[#FDBA35]"
|
|
||||||
: "bg-[#FFE3E2] text-[#FF5450]"
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
variant="text"
|
|
||||||
>
|
|
||||||
{data.status === "received"
|
|
||||||
? "پرداخت شده"
|
|
||||||
: data.status === "pending"
|
|
||||||
? "در انتظار"
|
|
||||||
: "لغو شده"}
|
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
</TextLoading>
|
</TextLoading>
|
||||||
@@ -44,43 +41,28 @@ function Card({ data, loading }) {
|
|||||||
<p className="text-[#7E7E7E] text-[14px] font-normal">شناسه:</p>
|
<p className="text-[#7E7E7E] text-[14px] font-normal">شناسه:</p>
|
||||||
</TextLoading>
|
</TextLoading>
|
||||||
<TextLoading loading={loading} width={90} height={18}>
|
<TextLoading loading={loading} width={90} height={18}>
|
||||||
<p className="text-[#616161] text-[14px] font-medium">{data.id}</p>
|
<p className="text-[#616161] text-[14px] font-medium">{data.order_id || "--"}</p>
|
||||||
</TextLoading>
|
</TextLoading>
|
||||||
</li>
|
</li>
|
||||||
<span className="block h-px w-[calc(100%-20px)] mx-auto bg-[#EFEFEF] my-[8px]"></span>
|
<span className="block h-px w-[calc(100%-20px)] mx-auto bg-[#EFEFEF] my-[8px]"></span>
|
||||||
<li className="flex items-center justify-between gap-[12px]">
|
<li className="flex items-center justify-between gap-[12px]">
|
||||||
<TextLoading loading={loading} width={90} height={18}>
|
<TextLoading loading={loading} width={90} height={18}>
|
||||||
<p className="text-[#7E7E7E] text-[14px] font-normal">
|
<p className="text-[#7E7E7E] text-[14px] font-normal">تاریخ:</p>
|
||||||
تاریخ نوبت:
|
|
||||||
</p>
|
|
||||||
</TextLoading>
|
</TextLoading>
|
||||||
<TextLoading loading={loading} width={80} height={18}>
|
<TextLoading loading={loading} width={80} height={18}>
|
||||||
<p className="text-[#616161] text-[14px] font-medium">
|
<p className="text-[#616161] text-[14px] font-medium">
|
||||||
{convertTimestampToJalali(data.appointment_details?.start_time)}
|
{convertTimestampToJalali(data.created_at)}
|
||||||
</p>
|
|
||||||
</TextLoading>
|
|
||||||
</li>
|
|
||||||
<span className="block h-px w-[calc(100%-20px)] mx-auto bg-[#EFEFEF] my-[8px]"></span>
|
|
||||||
<li className="flex items-center justify-between gap-[12px]">
|
|
||||||
<TextLoading loading={loading} width={80} height={18}>
|
|
||||||
<p className="text-[#7E7E7E] text-[14px] font-normal">ساعت نوبت:</p>
|
|
||||||
</TextLoading>
|
|
||||||
<TextLoading loading={loading} width={80} height={18}>
|
|
||||||
<p className="text-[#616161] text-[14px] font-medium">
|
|
||||||
{convertTimestampToTime(data.appointment_details?.start_time)}
|
|
||||||
</p>
|
</p>
|
||||||
</TextLoading>
|
</TextLoading>
|
||||||
</li>
|
</li>
|
||||||
<span className="block h-px w-[calc(100%-20px)] mx-auto bg-[#EFEFEF] my-[8px]"></span>
|
<span className="block h-px w-[calc(100%-20px)] mx-auto bg-[#EFEFEF] my-[8px]"></span>
|
||||||
<li className="flex items-center justify-between gap-[12px]">
|
<li className="flex items-center justify-between gap-[12px]">
|
||||||
<TextLoading loading={loading} width={110} height={18}>
|
<TextLoading loading={loading} width={110} height={18}>
|
||||||
<p className="text-[#7E7E7E] text-[14px] font-normal">
|
<p className="text-[#7E7E7E] text-[14px] font-normal">مبلغ:</p>
|
||||||
مبلغ:
|
|
||||||
</p>
|
|
||||||
</TextLoading>
|
</TextLoading>
|
||||||
<TextLoading loading={loading} width={80} height={18}>
|
<TextLoading loading={loading} width={80} height={18}>
|
||||||
<p className="text-[#616161] text-[14px] font-medium">
|
<p className="text-[#616161] text-[14px] font-medium">
|
||||||
{data.amount ? data.amount.toLocaleString('fa-IR') : "--"} تومان
|
{data.amount_rials ? Math.round(data.amount_rials / 10).toLocaleString("fa-IR") : "--"} تومان
|
||||||
</p>
|
</p>
|
||||||
</TextLoading>
|
</TextLoading>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -5,42 +5,57 @@ import Card from "./Card";
|
|||||||
import TextLoading from "@/app/component/loading/Text";
|
import TextLoading from "@/app/component/loading/Text";
|
||||||
import CustomLoading from "@/app/component/loading/Custom";
|
import CustomLoading from "@/app/component/loading/Custom";
|
||||||
import CircularLoading from "@/app/component/loading/Circular";
|
import CircularLoading from "@/app/component/loading/Circular";
|
||||||
import { convertTimestampToJalali, convertTimestampToTime } from "@/helper";
|
import { convertTimestampToJalali } from "@/helper";
|
||||||
import Pagination from "@/app/component/Pagination";
|
import Pagination from "@/app/component/Pagination";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
|
||||||
function List({ user, loading, page, totalPages, onPageChange }) {
|
const PAYMENT_STATUS = {
|
||||||
const tableHead = [
|
success: { label: "پرداخت شده", cls: "bg-[#E8FADD] text-[#75E22E]" },
|
||||||
"ردیف",
|
pending: { label: "در انتظار", cls: "bg-[#FFF3DD] text-[#FDBA35]" },
|
||||||
"شناسه",
|
failed: { label: "ناموفق", cls: "bg-[#FFE3E2] text-[#FF5450]" },
|
||||||
"نام پزشک",
|
cancelled: { label: "لغو شده", cls: "bg-[#FFE3E2] text-[#FF5450]" },
|
||||||
"تاریخ",
|
refunded: { label: "بازگشت وجه", cls: "bg-[#EFEFEF] text-[#616161]" },
|
||||||
"ساعت",
|
};
|
||||||
"مبلغ (تومان)",
|
|
||||||
"وضعیت",
|
const TYPE_LABELS = {
|
||||||
];
|
appointment: "نوبت",
|
||||||
|
subscription: "اشتراک",
|
||||||
|
sms_wallet: "کیف پول پیامک",
|
||||||
|
};
|
||||||
|
|
||||||
|
function List({ payments, loading, page, totalPages, onPageChange }) {
|
||||||
|
const rows = Array.isArray(payments) ? payments : [];
|
||||||
|
const tableHead = ["ردیف", "شناسه پرداخت", "نوع", "تاریخ", "مبلغ (تومان)", "وضعیت"];
|
||||||
const centerTable = [0, 4, 5];
|
const centerTable = [0, 4, 5];
|
||||||
|
|
||||||
|
if (!loading && rows.length === 0) {
|
||||||
|
return (
|
||||||
|
<p className="text-[#7E7E7E] text-[14px] md:text-[16px] font-medium text-center py-[56px]">
|
||||||
|
تراکنشی ثبت نشده است.
|
||||||
|
</p>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="!mt-[32px]">
|
<div className="!mt-[32px]">
|
||||||
<div className="hidden md:block w-full">
|
<div className="hidden md:block w-full">
|
||||||
<CustomTable tableHead={tableHead} centerTable={centerTable}>
|
<CustomTable tableHead={tableHead} centerTable={centerTable}>
|
||||||
{user.turns.done.map((row, idx) => (
|
{rows.map((row, idx) => (
|
||||||
<TableRow
|
<TableRow
|
||||||
key={idx}
|
key={idx}
|
||||||
className="!border-0 !border-b !border-[#DBDBDB]"
|
className="!border-0 !border-b !border-[#DBDBDB]"
|
||||||
>
|
>
|
||||||
<TableCell className="!pr-[18px] !text-nowrap" align="center">
|
<TableCell className="!pr-[18px] !text-nowrap" align="center">
|
||||||
<TextLoading width={15} height={18} loading={loading}>
|
<TextLoading width={15} height={18} loading={loading}>
|
||||||
{idx + 1}
|
{(page - 1) * 10 + idx + 1}
|
||||||
</TextLoading>
|
</TextLoading>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell
|
<TableCell
|
||||||
className="!text-start !pr-[18px] !text-nowrap"
|
className="!text-start !pr-[18px] !text-nowrap"
|
||||||
align="right"
|
align="right"
|
||||||
>
|
>
|
||||||
<TextLoading width={30} height={18} loading={loading}>
|
<TextLoading width={120} height={18} loading={loading}>
|
||||||
{row.id}
|
{row.order_id || "--"}
|
||||||
</TextLoading>
|
</TextLoading>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell
|
<TableCell
|
||||||
@@ -48,8 +63,8 @@ function List({ user, loading, page, totalPages, onPageChange }) {
|
|||||||
component="th"
|
component="th"
|
||||||
scope="row"
|
scope="row"
|
||||||
>
|
>
|
||||||
<TextLoading width={120} height={18} loading={loading}>
|
<TextLoading width={80} height={18} loading={loading}>
|
||||||
{row.appointment_details?.doctor_name || "--"}
|
{TYPE_LABELS[row.type] || row.type || "--"}
|
||||||
</TextLoading>
|
</TextLoading>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell
|
<TableCell
|
||||||
@@ -57,7 +72,7 @@ function List({ user, loading, page, totalPages, onPageChange }) {
|
|||||||
align="right"
|
align="right"
|
||||||
>
|
>
|
||||||
<TextLoading width={80} height={18} loading={loading}>
|
<TextLoading width={80} height={18} loading={loading}>
|
||||||
{convertTimestampToJalali(row.appointment_details?.start_time)}
|
{convertTimestampToJalali(row.created_at)}
|
||||||
</TextLoading>
|
</TextLoading>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell
|
<TableCell
|
||||||
@@ -65,37 +80,16 @@ function List({ user, loading, page, totalPages, onPageChange }) {
|
|||||||
align="right"
|
align="right"
|
||||||
>
|
>
|
||||||
<TextLoading width={50} height={18} loading={loading}>
|
<TextLoading width={50} height={18} loading={loading}>
|
||||||
{convertTimestampToTime(row.appointment_details?.start_time)}
|
{row.amount_rials ? Math.round(row.amount_rials / 10).toLocaleString("fa-IR") : "--"}
|
||||||
</TextLoading>
|
|
||||||
</TableCell>
|
|
||||||
<TableCell
|
|
||||||
className="!text-center !pr-[18px] !text-nowrap"
|
|
||||||
align="right"
|
|
||||||
>
|
|
||||||
<TextLoading width={50} height={18} loading={loading}>
|
|
||||||
{row.amount ? row.amount.toLocaleString('fa-IR') : "--"}
|
|
||||||
</TextLoading>
|
</TextLoading>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className="!pr-[18px] !text-nowrap" align="right">
|
<TableCell className="!pr-[18px] !text-nowrap" align="right">
|
||||||
<CustomLoading width={80} height={22} loading={loading}>
|
<CustomLoading width={80} height={22} loading={loading}>
|
||||||
<Link href={`/payment/${row.uuid}`}>
|
<Link href={`/payment/${row.uuid}`}>
|
||||||
<div
|
<div
|
||||||
className={`
|
className={`w-[124px] py-[4px] px-[4px] rounded-[4px] text-center text-[16px] font-medium select-none cursor-pointer ${(PAYMENT_STATUS[row.status] || PAYMENT_STATUS.failed).cls}`}
|
||||||
w-[124px] py-[4px] px-[4px] rounded-[4px] text-center text-[16px] font-medium select-none cursor-pointer
|
|
||||||
${row.status === "received"
|
|
||||||
? "bg-[#E8FADD] text-[#75E22E]"
|
|
||||||
: row.status === "pending"
|
|
||||||
? "bg-[#FFF3DD] text-[#FDBA35]"
|
|
||||||
: "bg-[#FFE3E2] text-[#FF5450]"
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
variant="text"
|
|
||||||
>
|
>
|
||||||
{row.status === "received"
|
{(PAYMENT_STATUS[row.status] || { label: row.status }).label}
|
||||||
? "پرداخت شده"
|
|
||||||
: row.status === "pending"
|
|
||||||
? "در انتظار"
|
|
||||||
: "لغو شده"}
|
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
</CustomLoading>
|
</CustomLoading>
|
||||||
@@ -105,7 +99,7 @@ function List({ user, loading, page, totalPages, onPageChange }) {
|
|||||||
</CustomTable>
|
</CustomTable>
|
||||||
</div>
|
</div>
|
||||||
<ul className="flex md:hidden flex-col gap-y-[24px]">
|
<ul className="flex md:hidden flex-col gap-y-[24px]">
|
||||||
{user.turns.done.map((row, idx) => (
|
{rows.map((row, idx) => (
|
||||||
<Card key={idx} data={row} loading={loading} />
|
<Card key={idx} data={row} loading={loading} />
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ function Transactions({ user, loading }) {
|
|||||||
</p>
|
</p>
|
||||||
<Head status={status} setStatus={handleStatusChange} />
|
<Head status={status} setStatus={handleStatusChange} />
|
||||||
<List
|
<List
|
||||||
user={{ ...user, turns: { done: payments } }}
|
payments={payments}
|
||||||
loading={isLoading}
|
loading={isLoading}
|
||||||
page={page}
|
page={page}
|
||||||
totalPages={totalPages}
|
totalPages={totalPages}
|
||||||
|
|||||||
Reference in New Issue
Block a user