feat: add Settlements, SMS, User detail, and Users management pages

- Implement SettlementsPage for managing settlement requests with approval and rejection functionalities.
- Create SmsPage for handling SMS templates, including creation, approval, rejection, and logging.
- Add UserDetailPage to display detailed information about users.
- Develop UsersPage for listing users with search, view, edit, and delete options.
- Introduce new types for User, SmsTemplate, SmsLog, and Settlement to support the new features.
This commit is contained in:
hamed
2026-06-09 22:53:26 +03:30
parent e522c741b8
commit f619449167
30 changed files with 3870 additions and 0 deletions
+72
View File
@@ -0,0 +1,72 @@
import React from 'react';
import { ChevronRightIcon, ChevronLeftIcon } from '@heroicons/react/24/outline';
import { formatNumber } from '../../lib/utils';
interface Props {
page: number;
total: number;
limit: number;
onPageChange: (page: number) => void;
}
export default function Pagination({ page, total, limit, onPageChange }: Props) {
const totalPages = Math.ceil(total / limit);
if (totalPages <= 1) return null;
const from = (page - 1) * limit + 1;
const to = Math.min(page * limit, total);
const pages: (number | '...')[] = [];
if (totalPages <= 7) {
for (let i = 1; i <= totalPages; i++) pages.push(i);
} else {
pages.push(1);
if (page > 3) pages.push('...');
for (let i = Math.max(2, page - 1); i <= Math.min(totalPages - 1, page + 1); i++) {
pages.push(i);
}
if (page < totalPages - 2) pages.push('...');
pages.push(totalPages);
}
return (
<div className="flex items-center justify-between mt-4 text-sm">
<span className="text-gray-500">
نمایش {formatNumber(from)}{formatNumber(to)} از {formatNumber(total)}
</span>
<div className="flex items-center gap-1">
<button
onClick={() => onPageChange(page - 1)}
disabled={page === 1}
className="p-1.5 rounded-lg hover:bg-gray-100 disabled:opacity-40 disabled:cursor-not-allowed transition-colors"
>
<ChevronRightIcon className="w-4 h-4" />
</button>
{pages.map((p, i) =>
p === '...' ? (
<span key={`dots-${i}`} className="px-2 text-gray-400">...</span>
) : (
<button
key={p}
onClick={() => onPageChange(p as number)}
className={`w-8 h-8 rounded-lg text-sm transition-colors ${
p === page
? 'bg-primary-600 text-white font-semibold'
: 'text-gray-600 hover:bg-gray-100'
}`}
>
{formatNumber(p as number)}
</button>
)
)}
<button
onClick={() => onPageChange(page + 1)}
disabled={page === totalPages}
className="p-1.5 rounded-lg hover:bg-gray-100 disabled:opacity-40 disabled:cursor-not-allowed transition-colors"
>
<ChevronLeftIcon className="w-4 h-4" />
</button>
</div>
</div>
);
}