183 lines
7.4 KiB
TypeScript
183 lines
7.4 KiB
TypeScript
'use client';
|
|
import React from 'react';
|
|
import { Clock, XCircle, ReceiptText } from 'lucide-react';
|
|
import { useQuery } from '@tanstack/react-query';
|
|
import { useTranslations } from 'next-intl';
|
|
import { apiRequest } from '@/shared/request/apiRequest';
|
|
import { links } from '@/shared/request/links';
|
|
import PaymentStatus from '@/widgets/detail/paidStatus';
|
|
// import { toast } from 'react-toastify';
|
|
// import { PaymentModal } from '@/features/modals/paymentModal/ui/Paymentmodal';
|
|
|
|
// ─── Types ─────────────────────────────────────────────────────────────────────
|
|
|
|
type Inspection = {
|
|
created_at: string;
|
|
discount: string | null;
|
|
id: number;
|
|
state: 'paid' | 'unpaid' | null;
|
|
total_price: string;
|
|
turi: string;
|
|
};
|
|
|
|
// ─── Helpers ───────────────────────────────────────────────────────────────────
|
|
|
|
function formatDate(iso: string) {
|
|
return new Date(iso).toLocaleDateString('uz-UZ', {
|
|
year: 'numeric',
|
|
month: '2-digit',
|
|
day: '2-digit',
|
|
});
|
|
}
|
|
|
|
function formatPrice(price: string) {
|
|
return Number(price).toLocaleString('uz-UZ');
|
|
}
|
|
|
|
// ─── Component ─────────────────────────────────────────────────────────────────
|
|
|
|
export function PaymentsTable() {
|
|
const t = useTranslations('Cabinet');
|
|
// const [isPaymentOpen, setIsPaymentOpen] = useState(false);
|
|
const { data, isLoading } = useQuery({
|
|
queryKey: ['pay_history'],
|
|
queryFn: (): Promise<Inspection[]> =>
|
|
apiRequest('GET', links.pay_history).then(
|
|
(res) => res.data as Inspection[],
|
|
),
|
|
});
|
|
|
|
// const payment = useMutation({
|
|
// mutationKey: ['payload'],
|
|
// mutationFn: ({ order_id }: { order_id: number }) =>
|
|
// apiRequest<{ payment_link: string }>('POST', links.payment(order_id)),
|
|
// onSuccess: (res) => {
|
|
// window.open(res.data.payment_link, '_self');
|
|
// // setIsPaymentOpen(false);
|
|
// },
|
|
// onError: (err) => {
|
|
// const message =
|
|
// err instanceof Error ? err.message : 'An unexpected error occurred.';
|
|
// toast.error(message);
|
|
// // setIsPaymentOpen(false);
|
|
// },
|
|
// });
|
|
|
|
// const handleSubmit = ({ document_id }: { document_id: number }) => {
|
|
// if (document_id === 0) {
|
|
// toast.error('Id not found');
|
|
// return;
|
|
// }
|
|
// payment.mutate({ order_id: document_id });
|
|
// };
|
|
|
|
return (
|
|
<>
|
|
<div className="space-y-4">
|
|
<div>
|
|
<h2 className="text-xl font-bold text-slate-900">{t('payments')}</h2>
|
|
<p className="text-sm text-slate-500 mt-0.5">
|
|
{t('paymentsCount', { count: data?.length ?? 0 })}
|
|
</p>
|
|
</div>
|
|
|
|
<div className="bg-white rounded-2xl border border-slate-100 shadow-sm overflow-hidden">
|
|
{isLoading ? (
|
|
<div className="flex items-center justify-center py-16 gap-3 text-slate-400">
|
|
<Clock size={20} className="animate-spin" />
|
|
<span className="text-sm">{t('loading')}</span>
|
|
</div>
|
|
) : !data || data.length === 0 ? (
|
|
<div className="flex flex-col items-center justify-center py-16 gap-3 text-slate-400">
|
|
<ReceiptText size={40} strokeWidth={1.5} />
|
|
<p className="text-sm">{t('noPayments')}</p>
|
|
</div>
|
|
) : (
|
|
<div className="overflow-x-auto">
|
|
<table className="w-full text-sm">
|
|
<thead>
|
|
<tr className="bg-slate-50 border-b border-slate-100">
|
|
{[
|
|
t('tableNum'),
|
|
t('service'),
|
|
t('amount'),
|
|
t('discount'),
|
|
t('date'),
|
|
t('status'),
|
|
].map((h) => (
|
|
<th
|
|
key={h}
|
|
className="text-left px-5 py-3 text-[11px] font-semibold text-slate-400 uppercase tracking-wider whitespace-nowrap"
|
|
>
|
|
{h}
|
|
</th>
|
|
))}
|
|
</tr>
|
|
</thead>
|
|
<tbody className="divide-y divide-slate-50">
|
|
{data.map((row) => {
|
|
// const service_fee = row.total_price + row.discount;
|
|
return (
|
|
<tr
|
|
key={row.id}
|
|
className="hover:bg-slate-50/60 transition-colors"
|
|
>
|
|
<td className="px-5 py-3.5 text-slate-400 font-mono text-xs">
|
|
{String(row.id).padStart(2, '0')}
|
|
</td>
|
|
<td className="px-5 py-3.5 text-slate-800 font-medium whitespace-nowrap">
|
|
{row.turi}
|
|
</td>
|
|
<td className="px-5 py-3.5 text-slate-800 font-semibold tabular-nums whitespace-nowrap">
|
|
{formatPrice(row.total_price)} UZS
|
|
</td>
|
|
<td className="px-5 py-3.5 tabular-nums whitespace-nowrap">
|
|
{row.discount ? (
|
|
<span className="text-emerald-600 font-medium">
|
|
-{formatPrice(row.discount)} UZS
|
|
</span>
|
|
) : (
|
|
<span className="text-slate-300">—</span>
|
|
)}
|
|
</td>
|
|
<td className="px-5 py-3.5 text-slate-500 whitespace-nowrap">
|
|
{formatDate(row.created_at)}
|
|
</td>
|
|
<td className="px-5 py-3.5">
|
|
{row.state ? (
|
|
<span className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-lg text-xs font-medium text-emerald-600 bg-emerald-50">
|
|
<PaymentStatus status={row.state} />
|
|
</span>
|
|
) : (
|
|
<span className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-lg text-xs font-medium text-slate-400 bg-slate-50">
|
|
<XCircle size={12} />
|
|
{t('unknown')}
|
|
</span>
|
|
)}
|
|
</td>
|
|
{/* <PaymentModal
|
|
isOpen={isPaymentOpen}
|
|
onClose={() => setIsPaymentOpen(false)}
|
|
price={{
|
|
service_fee: Number(service_fee),
|
|
discount: Number(row.discount) || 0,
|
|
total_price: Number(row.total_price) || 0,
|
|
}}
|
|
onConfirmPayment={() => {
|
|
handleSubmit({ document_id: 0 });
|
|
}}
|
|
isLoading={payment.isPending}
|
|
/> */}
|
|
</tr>
|
|
);
|
|
})}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</>
|
|
);
|
|
}
|