Files
resolutionflow/frontend/src/components/admin/Pagination.tsx
chihlasm a71f082e25 feat: extract admin account management rework from PR 124 (#138)
* feat: reorganize admin panel around accounts

* feat: expand admin customer account controls

* feat: add admin account detail management

* fix: remove unused admin account icon import

* refactor: design critique fixes for account pages

- Admin accounts: replace dense card grid with compact DataTable
- Account settings: remove redundant hero card, stat grid, header pills
- Fix bg-accent (orange) misuse on decorative elements across 7 files
- Add ConfirmButton for destructive actions (deactivate, remove member)
- Replace single-field modals with inline editing (plan, trial)
- Add contextual help: display code tooltip, improved empty states
- Non-owner aside explanation for hidden owner-only sections
- Admin sidebar: group 11 items into 5 labeled sections
- Rename UsersPage.tsx → AccountsPage.tsx to match route
- Fix border radius consistency, hide zero-count badges

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: use get_admin_db for all new admin account endpoints

All admin endpoints query across tenants without a tenant context.
get_db (app-role, subject to RLS) was never imported and would crash
at runtime — replace all 6 occurrences with get_admin_db (BYPASSRLS).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 04:44:51 -04:00

82 lines
2.5 KiB
TypeScript

import { ChevronLeft, ChevronRight } from 'lucide-react'
import { cn } from '@/lib/utils'
interface PaginationProps {
page: number
totalPages: number
total: number
pageSize: number
onPageChange: (page: number) => void
}
export function Pagination({ page, totalPages, total, pageSize, onPageChange }: PaginationProps) {
const start = (page - 1) * pageSize + 1
const end = Math.min(page * pageSize, total)
const getPageNumbers = (): (number | 'ellipsis')[] => {
if (totalPages <= 7) {
return Array.from({ length: totalPages }, (_, i) => i + 1)
}
const pages: (number | 'ellipsis')[] = [1]
if (page > 3) pages.push('ellipsis')
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('ellipsis')
pages.push(totalPages)
return pages
}
if (totalPages <= 1) return null
const btnBase = cn(
'inline-flex h-8 min-w-8 items-center justify-center rounded-md text-sm font-medium',
'transition-colors disabled:opacity-50 disabled:pointer-events-none'
)
return (
<div className="flex items-center justify-between gap-4 pt-4">
<span className="text-sm text-muted-foreground">
Showing {start}-{end} of {total}
</span>
<div className="flex items-center gap-1">
<button
onClick={() => onPageChange(page - 1)}
disabled={page <= 1}
className={cn(btnBase, 'px-2 text-muted-foreground hover:bg-elevated hover:text-foreground')}
>
<ChevronLeft className="h-4 w-4" />
</button>
{getPageNumbers().map((p, i) =>
p === 'ellipsis' ? (
<span key={`e${i}`} className="px-1 text-muted-foreground">...</span>
) : (
<button
key={p}
onClick={() => onPageChange(p)}
className={cn(
btnBase,
'px-2',
p === page
? 'bg-primary text-white'
: 'text-muted-foreground hover:bg-elevated hover:text-foreground'
)}
>
{p}
</button>
)
)}
<button
onClick={() => onPageChange(page + 1)}
disabled={page >= totalPages}
className={cn(btnBase, 'px-2 text-muted-foreground hover:bg-elevated hover:text-foreground')}
>
<ChevronRight className="h-4 w-4" />
</button>
</div>
</div>
)
}
export default Pagination