latest
This commit is contained in:
1 parent
d0834df8df
commit
6dc35134fa
171 files changed
+19241
-49
No files matched your search
@@ -0,0 +1,118 @@
|
||||
import { useState } from 'react'
|
||||
import { useQuery, useQueryClient } from '@tanstack/react-query'
|
||||
import { useConfirm } from '../../components/shared/ConfirmDialog'
|
||||
import { useToast } from '../../components/shared/Toast/ToastProvider'
|
||||
import { usePermission } from '../../hooks/usePermission'
|
||||
import { fetchUsers, deleteUser } from './usersApi'
|
||||
import { useUsersRealtime } from './useUsersRealtime'
|
||||
import { UserFormModal } from './UserFormModal'
|
||||
import { AssignRoleModal } from './AssignRoleModal'
|
||||
import type { User } from '../../types/user'
|
||||
|
||||
export function UsersListPageMobile() {
|
||||
const { can } = usePermission()
|
||||
const confirm = useConfirm()
|
||||
const toast = useToast()
|
||||
const queryClient = useQueryClient()
|
||||
useUsersRealtime()
|
||||
|
||||
const [page, setPage] = useState(1)
|
||||
const [formUser, setFormUser] = useState<User | null | undefined>(undefined)
|
||||
const [roleUser, setRoleUser] = useState<User | null>(null)
|
||||
|
||||
const { data, isLoading } = useQuery({
|
||||
queryKey: ['users', { page, sort: 'created_at', direction: 'desc' as const }],
|
||||
queryFn: () => fetchUsers({ page, sort: 'created_at', direction: 'desc' }),
|
||||
})
|
||||
|
||||
async function handleDelete(user: User) {
|
||||
const ok = await confirm({
|
||||
title: 'Delete user',
|
||||
message: `Delete ${user.name}? This cannot be undone.`,
|
||||
confirmLabel: 'Delete',
|
||||
danger: true,
|
||||
})
|
||||
if (!ok) return
|
||||
|
||||
await deleteUser(user.id)
|
||||
queryClient.invalidateQueries({ queryKey: ['users'] })
|
||||
toast.success(`${user.name} was deleted.`)
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="mb-4 flex items-center justify-between">
|
||||
<h1 className="text-lg font-semibold text-gray-900 dark:text-gray-100">Users</h1>
|
||||
{can('users.create') && (
|
||||
<button
|
||||
onClick={() => setFormUser(null)}
|
||||
className="rounded-md bg-blue-600 px-3 py-2 text-sm font-medium text-white hover:bg-blue-700"
|
||||
>
|
||||
Add
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{isLoading ? (
|
||||
<p className="text-sm text-gray-500">Loading…</p>
|
||||
) : (
|
||||
<div className="flex flex-col gap-3">
|
||||
{(data?.data ?? []).map((u) => (
|
||||
<div
|
||||
key={u.id}
|
||||
className="rounded-lg border border-gray-200 bg-white p-4 dark:border-gray-800 dark:bg-gray-900"
|
||||
>
|
||||
<p className="font-medium text-gray-900 dark:text-gray-100">{u.name}</p>
|
||||
<p className="text-sm text-gray-500 dark:text-gray-500">{u.email}</p>
|
||||
<p className="mt-1 text-xs text-gray-400 dark:text-gray-600">{u.roles.join(', ')}</p>
|
||||
<div className="mt-3 flex gap-4 text-sm">
|
||||
{u.can_edit && (
|
||||
<button onClick={() => setFormUser(u)} className="text-blue-600 dark:text-blue-400">
|
||||
Edit
|
||||
</button>
|
||||
)}
|
||||
{can('roles.assign') && (
|
||||
<button onClick={() => setRoleUser(u)} className="text-blue-600 dark:text-blue-400">
|
||||
Role
|
||||
</button>
|
||||
)}
|
||||
{u.can_delete && (
|
||||
<button onClick={() => handleDelete(u)} className="text-red-600 dark:text-red-400">
|
||||
Delete
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{data && data.meta.last_page > 1 && (
|
||||
<div className="mt-4 flex items-center justify-between text-sm">
|
||||
<button
|
||||
disabled={page <= 1}
|
||||
onClick={() => setPage((p) => p - 1)}
|
||||
className="text-gray-600 disabled:opacity-40 dark:text-gray-400"
|
||||
>
|
||||
Previous
|
||||
</button>
|
||||
<span className="text-gray-500">
|
||||
Page {page} of {data.meta.last_page}
|
||||
</span>
|
||||
<button
|
||||
disabled={page >= data.meta.last_page}
|
||||
onClick={() => setPage((p) => p + 1)}
|
||||
className="text-gray-600 disabled:opacity-40 dark:text-gray-400"
|
||||
>
|
||||
Next
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{formUser !== undefined && (
|
||||
<UserFormModal open onClose={() => setFormUser(undefined)} user={formUser ?? undefined} />
|
||||
)}
|
||||
{roleUser && <AssignRoleModal open onClose={() => setRoleUser(null)} user={roleUser} />}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in new issue
Block a user