add admin permission
This commit is contained in:
parent
3388eca2fe
commit
7ea73543b7
19 changed files with 1567 additions and 5 deletions
160
src/routes/(authed)/admin/users/data-table.svelte
Normal file
160
src/routes/(authed)/admin/users/data-table.svelte
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
<script lang="ts">
|
||||
import {
|
||||
type ColumnDef,
|
||||
type ColumnFiltersState,
|
||||
type FilterFn,
|
||||
getCoreRowModel,
|
||||
getFilteredRowModel,
|
||||
getPaginationRowModel,
|
||||
getSortedRowModel,
|
||||
type GlobalFilterTableState,
|
||||
type PaginationState,
|
||||
type SortingState
|
||||
} from '@tanstack/table-core';
|
||||
import { rankItem } from '@tanstack/match-sorter-utils';
|
||||
import { createSvelteTable, FlexRender } from '$lib/components/ui/data-table/index';
|
||||
import * as Table from '$lib/components/ui/table/index';
|
||||
import Button from '$lib/components/ui/button/button.svelte';
|
||||
import Input from '$lib/components/ui/input/input.svelte';
|
||||
import { SearchIcon } from '@lucide/svelte/icons';
|
||||
import type { AdminUser } from '$lib/core/admin/adminTypes';
|
||||
|
||||
let { data, columns }: { data: AdminUser[]; columns: ColumnDef<AdminUser>[] } = $props();
|
||||
|
||||
let pagination = $state<PaginationState>({ pageIndex: 0, pageSize: 10 });
|
||||
let sorting = $state<SortingState>([]);
|
||||
let columnFilter = $state<ColumnFiltersState>([]);
|
||||
let globalFilter = $state<GlobalFilterTableState>();
|
||||
|
||||
const fuzzyFilter: FilterFn<AdminUser> = (row, columnId, value, addMeta) => {
|
||||
const itemRank = rankItem(row.getValue(columnId), value);
|
||||
addMeta({ itemRank });
|
||||
return itemRank.passed;
|
||||
};
|
||||
|
||||
const table = createSvelteTable({
|
||||
get data() {
|
||||
return data;
|
||||
},
|
||||
columns,
|
||||
state: {
|
||||
get pagination() {
|
||||
return pagination;
|
||||
},
|
||||
get sorting() {
|
||||
return sorting;
|
||||
},
|
||||
get globalFilter() {
|
||||
return globalFilter;
|
||||
}
|
||||
},
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
getPaginationRowModel: getPaginationRowModel(),
|
||||
getSortedRowModel: getSortedRowModel(),
|
||||
getFilteredRowModel: getFilteredRowModel(),
|
||||
filterFns: {
|
||||
fuzzy: fuzzyFilter
|
||||
},
|
||||
globalFilterFn: fuzzyFilter,
|
||||
onSortingChange: (updater) => {
|
||||
if (typeof updater === 'function') {
|
||||
sorting = updater(sorting);
|
||||
} else {
|
||||
sorting = updater;
|
||||
}
|
||||
},
|
||||
onPaginationChange: (updater) => {
|
||||
if (typeof updater === 'function') {
|
||||
pagination = updater(pagination);
|
||||
} else {
|
||||
pagination = updater;
|
||||
}
|
||||
},
|
||||
onColumnFiltersChange: (updater) => {
|
||||
if (typeof updater === 'function') {
|
||||
columnFilter = updater(columnFilter);
|
||||
} else {
|
||||
columnFilter = updater;
|
||||
}
|
||||
},
|
||||
onGlobalFilterChange: (updater) => {
|
||||
if (typeof updater === 'function') {
|
||||
globalFilter = updater(globalFilter);
|
||||
} else {
|
||||
globalFilter = updater;
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<div class="flex items-center gap-2 py-4">
|
||||
<SearchIcon class="h-5 w-5 text-gray-500" />
|
||||
<Input
|
||||
type="text"
|
||||
placeholder="Search by name or email..."
|
||||
class="max-w-sm"
|
||||
onchange={(e) => {
|
||||
table.setGlobalFilter(e.currentTarget.value);
|
||||
}}
|
||||
oninput={(e) => {
|
||||
table.setGlobalFilter(e.currentTarget.value);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="rounded-md border">
|
||||
<Table.Root>
|
||||
<Table.Header>
|
||||
{#each table.getHeaderGroups() as headerGroup (headerGroup.id)}
|
||||
<Table.Row>
|
||||
{#each headerGroup.headers as header (header.id)}
|
||||
<Table.Head colspan={header.colSpan}>
|
||||
{#if !header.isPlaceholder}
|
||||
<FlexRender
|
||||
content={header.column.columnDef.header}
|
||||
context={header.getContext()}
|
||||
/>
|
||||
{/if}
|
||||
</Table.Head>
|
||||
{/each}
|
||||
</Table.Row>
|
||||
{/each}
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
{#each table.getRowModel().rows as row (row.id)}
|
||||
<Table.Row data-state={row.getIsSelected() && 'selected'}>
|
||||
{#each row.getVisibleCells() as cell (cell.id)}
|
||||
<Table.Cell>
|
||||
<FlexRender content={cell.column.columnDef.cell} context={cell.getContext()} />
|
||||
</Table.Cell>
|
||||
{/each}
|
||||
</Table.Row>
|
||||
{:else}
|
||||
<Table.Row>
|
||||
<Table.Cell colspan={columns.length} class="h-24 text-center">No users found.</Table.Cell>
|
||||
</Table.Row>
|
||||
{/each}
|
||||
</Table.Body>
|
||||
</Table.Root>
|
||||
<div class="mx-4 flex items-center justify-between py-4">
|
||||
<span class="text-muted-foreground text-sm">
|
||||
{table.getFilteredRowModel().rows.length} user(s) total
|
||||
</span>
|
||||
<div class="flex items-center space-x-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onclick={() => table.previousPage()}
|
||||
disabled={!table.getCanPreviousPage()}>Previous</Button
|
||||
>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onclick={() => table.nextPage()}
|
||||
disabled={!table.getCanNextPage()}>Next</Button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
Loading…
Add table
Add a link
Reference in a new issue