174 lines
5.4 KiB
TypeScript
174 lines
5.4 KiB
TypeScript
import React, { useMemo, useState } from 'react';
|
||
import { MessageSquare, Trash2 } from 'lucide-react';
|
||
import { PageContainer } from '@/components/ui/Typography';
|
||
import { PageHeader } from '@/components/layout/PageHeader';
|
||
import { Table } from '@/components/ui/Table';
|
||
import { TableColumn } from '@/types';
|
||
import { Pagination } from '@/components/ui/Pagination';
|
||
import { DeleteConfirmModal } from '@/components/common/DeleteConfirmModal';
|
||
import { englishToPersian } from '@/utils/numberUtils';
|
||
import { formatDateTime } from '@/utils/formatters';
|
||
import { useContactUsMessages, useDeleteContactUsMessage } from '../core/_hooks';
|
||
import { ContactUsFilters, ContactUsMessage } from '../core/_models';
|
||
|
||
const ContactUsListPage: React.FC = () => {
|
||
const [filters, setFilters] = useState<ContactUsFilters>({
|
||
limit: 20,
|
||
offset: 0,
|
||
});
|
||
const [deleteTarget, setDeleteTarget] = useState<ContactUsMessage | null>(
|
||
null
|
||
);
|
||
|
||
const { data, isLoading, error } = useContactUsMessages(filters);
|
||
const deleteMessageMutation = useDeleteContactUsMessage();
|
||
|
||
const messages = data?.messages || [];
|
||
const total = data?.total ?? messages.length;
|
||
const limit = filters.limit || 20;
|
||
const currentPage = Math.floor((filters.offset || 0) / limit) + 1;
|
||
const totalPages = total > 0 ? Math.ceil(total / limit) : 1;
|
||
|
||
const handlePageChange = (page: number) => {
|
||
setFilters((prev) => ({
|
||
...prev,
|
||
offset: (page - 1) * prev.limit,
|
||
}));
|
||
};
|
||
|
||
const handleDeleteConfirm = () => {
|
||
if (!deleteTarget) return;
|
||
deleteMessageMutation.mutate(deleteTarget.ID, {
|
||
onSuccess: () => setDeleteTarget(null),
|
||
});
|
||
};
|
||
|
||
const columns: TableColumn[] = useMemo(
|
||
() => [
|
||
{
|
||
key: 'id',
|
||
label: 'شناسه',
|
||
align: 'center',
|
||
render: (value: number) => englishToPersian(value),
|
||
},
|
||
{
|
||
key: 'name',
|
||
label: 'نام',
|
||
align: 'right',
|
||
render: (value: string) => value || '-',
|
||
},
|
||
{
|
||
key: 'phone',
|
||
label: 'شماره تماس',
|
||
align: 'left',
|
||
render: (value: string) => {
|
||
const display = value ? englishToPersian(value) : '-';
|
||
return <span dir="ltr">{display}</span>;
|
||
},
|
||
},
|
||
{
|
||
key: 'message',
|
||
label: 'پیام',
|
||
align: 'right',
|
||
render: (value: string) => {
|
||
if (!value) return '-';
|
||
return value.length > 120 ? `${value.slice(0, 120)}...` : value;
|
||
},
|
||
},
|
||
{
|
||
key: 'created_at',
|
||
label: 'تاریخ',
|
||
align: 'right',
|
||
render: (value: string) => formatDateTime(value),
|
||
},
|
||
{
|
||
key: 'actions',
|
||
label: 'عملیات',
|
||
align: 'center',
|
||
render: (_val: unknown, row: any) => (
|
||
<div className="flex items-center justify-center">
|
||
<button
|
||
onClick={() => setDeleteTarget(row.raw)}
|
||
className="text-red-600 hover:text-red-900 dark:text-red-400 dark:hover:text-red-300 p-1"
|
||
title="حذف پیام"
|
||
>
|
||
<Trash2 className="h-4 w-4" />
|
||
</button>
|
||
</div>
|
||
),
|
||
},
|
||
],
|
||
[]
|
||
);
|
||
|
||
const tableData = messages.map((message) => ({
|
||
id: message.ID,
|
||
name: message.Name || '-',
|
||
phone: message.PhoneNumber || '-',
|
||
message: message.Message || '-',
|
||
created_at: message.CreatedAt,
|
||
raw: message,
|
||
}));
|
||
|
||
if (error) {
|
||
return (
|
||
<PageContainer>
|
||
<div className="text-center py-12">
|
||
<p className="text-red-600">خطا در دریافت پیامهای تماس با ما</p>
|
||
</div>
|
||
</PageContainer>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<PageContainer>
|
||
<div className="space-y-6">
|
||
<PageHeader
|
||
title="پیامهای تماس با ما"
|
||
subtitle="لیست پیامهای ارسالشده توسط کاربران"
|
||
icon={MessageSquare}
|
||
/>
|
||
|
||
<div className="bg-white dark:bg-gray-800 shadow-sm border border-gray-200 dark:border-gray-700 rounded-lg overflow-hidden">
|
||
{isLoading ? (
|
||
<Table columns={columns} data={[]} loading={true} />
|
||
) : messages.length === 0 ? (
|
||
<div className="text-center py-12">
|
||
<MessageSquare className="h-12 w-12 text-gray-400 mx-auto mb-4" />
|
||
<h3 className="text-lg font-medium text-gray-900 dark:text-gray-100 mb-2">
|
||
پیامی یافت نشد
|
||
</h3>
|
||
<p className="text-gray-600 dark:text-gray-400">
|
||
هنوز پیامی برای نمایش وجود ندارد
|
||
</p>
|
||
</div>
|
||
) : (
|
||
<Table columns={columns} data={tableData} />
|
||
)}
|
||
</div>
|
||
|
||
{messages.length > 0 && totalPages > 1 && (
|
||
<Pagination
|
||
currentPage={currentPage}
|
||
totalPages={totalPages}
|
||
onPageChange={handlePageChange}
|
||
itemsPerPage={limit}
|
||
totalItems={total}
|
||
/>
|
||
)}
|
||
</div>
|
||
|
||
<DeleteConfirmModal
|
||
isOpen={!!deleteTarget}
|
||
onClose={() => setDeleteTarget(null)}
|
||
onConfirm={handleDeleteConfirm}
|
||
title="حذف پیام تماس با ما"
|
||
message="آیا از حذف این پیام اطمینان دارید؟ این عمل قابل بازگشت نیست."
|
||
isLoading={deleteMessageMutation.isPending}
|
||
/>
|
||
</PageContainer>
|
||
);
|
||
};
|
||
|
||
export default ContactUsListPage;
|