79 lines
2.0 KiB
TypeScript
79 lines
2.0 KiB
TypeScript
'use client';
|
|
|
|
import { AsyncCombobox, usePaginatedLookup } from '@/components/async-combobox';
|
|
import type { AsyncComboboxOption } from '@/components/async-combobox';
|
|
import { roleService } from '@/services/api';
|
|
import type { Role } from '@/types';
|
|
|
|
import { roleKeys } from '@/app/(modules)/roles/queries/roleKeys';
|
|
import type { RoleComboboxProps } from './RoleCombobox.types';
|
|
|
|
const ROLE_PAGE_SIZE = 20;
|
|
|
|
function parseRoleId(value: string) {
|
|
const roleId = Number(value);
|
|
return Number.isFinite(roleId) ? roleId : null;
|
|
}
|
|
|
|
function mapRoleOption(role: Role): AsyncComboboxOption {
|
|
return {
|
|
value: String(role.id),
|
|
label: role.display_name || role.name,
|
|
};
|
|
}
|
|
|
|
export function RoleCombobox({
|
|
value,
|
|
onValueChange,
|
|
enabled = true,
|
|
disabled = false,
|
|
portalContainer,
|
|
}: RoleComboboxProps) {
|
|
const lookup = usePaginatedLookup<Role>({
|
|
enabled,
|
|
selectedValue: value,
|
|
pageSize: ROLE_PAGE_SIZE,
|
|
queryKey: (searchTerm) =>
|
|
[
|
|
...roleKeys.lists(),
|
|
'async-lookup',
|
|
searchTerm,
|
|
ROLE_PAGE_SIZE,
|
|
] as const,
|
|
queryFn: ({ searchTerm, skip, limit }) =>
|
|
roleService.getRoles({
|
|
search_term: searchTerm || undefined,
|
|
skip,
|
|
limit,
|
|
effective_status: true,
|
|
sort_by: 'display_name',
|
|
sort_order: 'asc',
|
|
}),
|
|
mapOption: mapRoleOption,
|
|
resolveSelected: (roleId) => {
|
|
const numericRoleId = parseRoleId(roleId);
|
|
return numericRoleId
|
|
? roleService.getRoleById(numericRoleId)
|
|
: Promise.resolve(null);
|
|
},
|
|
resolveSelectedQueryKey: (roleId) => {
|
|
const numericRoleId = parseRoleId(roleId);
|
|
return numericRoleId
|
|
? roleKeys.detail(numericRoleId)
|
|
: [...roleKeys.details(), 'invalid', roleId];
|
|
},
|
|
});
|
|
|
|
return (
|
|
<AsyncCombobox
|
|
lookup={lookup}
|
|
onValueChange={onValueChange}
|
|
disabled={disabled}
|
|
placeholder="Select role"
|
|
searchPlaceholder="Search roles..."
|
|
emptyMessage="No roles found."
|
|
portalContainer={portalContainer}
|
|
/>
|
|
);
|
|
}
|