feat: add isActive status support to roles with filtering and management UI
This commit is contained in:
parent
f480979020
commit
b0fe466a3d
@ -10,6 +10,7 @@ import {
|
||||
PrimaryButton,
|
||||
SecondaryButton,
|
||||
FormTextArea,
|
||||
FormSelect,
|
||||
} from "@/components/shared";
|
||||
import type { Role, UpdateRoleRequest } from "@/types/role";
|
||||
import { useAppSelector } from "@/hooks/redux-hooks";
|
||||
@ -74,6 +75,7 @@ const editRoleSchema = z.object({
|
||||
"Code must be lowercase and use '_' for separation (e.g. abc_def)",
|
||||
),
|
||||
description: z.string().min(1, "Description is required"),
|
||||
is_active: z.boolean(),
|
||||
permissions: z
|
||||
.array(
|
||||
z.object({
|
||||
@ -124,7 +126,7 @@ export const EditRoleModal = ({
|
||||
register,
|
||||
handleSubmit,
|
||||
setValue,
|
||||
// watch,
|
||||
watch,
|
||||
reset,
|
||||
setError,
|
||||
clearErrors,
|
||||
@ -132,10 +134,13 @@ export const EditRoleModal = ({
|
||||
} = useForm<EditRoleFormData>({
|
||||
resolver: zodResolver(editRoleSchema),
|
||||
defaultValues: {
|
||||
is_active: true,
|
||||
permissions: [],
|
||||
},
|
||||
});
|
||||
|
||||
const statusValue = watch("is_active");
|
||||
|
||||
// const nameValue = watch("name");
|
||||
|
||||
// Auto-generate code from name - Only during creation (handled in parent or different component)
|
||||
@ -310,6 +315,7 @@ export const EditRoleModal = ({
|
||||
name: role.name,
|
||||
code: role.code,
|
||||
description: role.description || "",
|
||||
is_active: role.is_active ?? true,
|
||||
permissions: rolePermissions,
|
||||
});
|
||||
} catch (err: any) {
|
||||
@ -331,6 +337,7 @@ export const EditRoleModal = ({
|
||||
name: "",
|
||||
code: "",
|
||||
description: "",
|
||||
is_active: true,
|
||||
permissions: [],
|
||||
});
|
||||
setLoadError(null);
|
||||
@ -505,6 +512,20 @@ export const EditRoleModal = ({
|
||||
rows={4}
|
||||
/>
|
||||
|
||||
<div className="pb-4">
|
||||
<FormSelect
|
||||
label="Status"
|
||||
required
|
||||
options={[
|
||||
{ value: "true", label: "Active" },
|
||||
{ value: "false", label: "Inactive" },
|
||||
]}
|
||||
value={String(statusValue)}
|
||||
onValueChange={(value) => setValue("is_active", value === "true", { shouldValidate: true })}
|
||||
error={errors.is_active?.message}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Permissions Section */}
|
||||
<div className="pb-4">
|
||||
<div
|
||||
|
||||
@ -153,8 +153,8 @@ export const EditUserModal = ({
|
||||
// Load roles for dropdown - ensure selected role is included
|
||||
const loadRoles = async (page: number, limit: number) => {
|
||||
const response = defaultTenantId
|
||||
? await roleService.getByTenant(defaultTenantId, page, limit)
|
||||
: await roleService.getAll(page, limit);
|
||||
? await roleService.getByTenant(defaultTenantId, page, limit, undefined, undefined, true)
|
||||
: await roleService.getAll(page, limit, undefined, undefined, undefined, true);
|
||||
return {
|
||||
options: response.data.map((role) => ({
|
||||
value: role.id,
|
||||
|
||||
@ -10,6 +10,7 @@ import {
|
||||
PrimaryButton,
|
||||
SecondaryButton,
|
||||
FormTextArea,
|
||||
FormSelect,
|
||||
} from "@/components/shared";
|
||||
import type { CreateRoleRequest } from "@/types/role";
|
||||
import { useAppSelector } from "@/hooks/redux-hooks";
|
||||
@ -74,6 +75,7 @@ const newRoleSchema = z.object({
|
||||
"Code must be lowercase and use '_' for separation (e.g. abc_def)",
|
||||
),
|
||||
description: z.string().min(1, "Description is required"),
|
||||
is_active: z.boolean(),
|
||||
permissions: z
|
||||
.array(
|
||||
z.object({
|
||||
@ -125,10 +127,13 @@ export const NewRoleModal = ({
|
||||
resolver: zodResolver(newRoleSchema),
|
||||
defaultValues: {
|
||||
code: undefined,
|
||||
is_active: true,
|
||||
permissions: [],
|
||||
},
|
||||
});
|
||||
|
||||
const statusValue = watch("is_active");
|
||||
|
||||
const nameValue = watch("name");
|
||||
|
||||
// Auto-generate code from name
|
||||
@ -146,6 +151,7 @@ export const NewRoleModal = ({
|
||||
name: "",
|
||||
code: undefined,
|
||||
description: "",
|
||||
is_active: true,
|
||||
permissions: [],
|
||||
});
|
||||
setSelectedPermissions([]);
|
||||
@ -153,6 +159,11 @@ export const NewRoleModal = ({
|
||||
}
|
||||
}, [isOpen, reset, clearErrors]);
|
||||
|
||||
const statusOptions = [
|
||||
{ value: "true", label: "Active" },
|
||||
{ value: "false", label: "Inactive" },
|
||||
];
|
||||
|
||||
// Build available resources and actions based on user permissions
|
||||
const availableResourcesAndActions = useMemo(() => {
|
||||
const resourceMap = new Map<string, Set<string>>();
|
||||
@ -395,6 +406,17 @@ export const NewRoleModal = ({
|
||||
rows={4}
|
||||
/>
|
||||
|
||||
<div className="pb-4">
|
||||
<FormSelect
|
||||
label="Status"
|
||||
required
|
||||
options={statusOptions}
|
||||
value={String(statusValue)}
|
||||
onValueChange={(value) => setValue("is_active", value === "true", { shouldValidate: true })}
|
||||
error={errors.is_active?.message}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Permissions Section */}
|
||||
<div className="pb-4">
|
||||
<div
|
||||
|
||||
@ -126,8 +126,8 @@ export const NewUserModal = ({
|
||||
|
||||
const loadRoles = async (page: number, limit: number) => {
|
||||
const response = defaultTenantId
|
||||
? await roleService.getByTenant(defaultTenantId, page, limit)
|
||||
: await roleService.getAll(page, limit);
|
||||
? await roleService.getByTenant(defaultTenantId, page, limit, undefined, undefined, true)
|
||||
: await roleService.getAll(page, limit, undefined, undefined, undefined, true);
|
||||
return {
|
||||
options: response.data.map((role) => ({ value: role.id, label: role.name })),
|
||||
pagination: response.pagination,
|
||||
|
||||
@ -116,6 +116,14 @@ export const ViewRoleModal = ({
|
||||
</StatusBadge>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-xs font-medium text-[#6b7280] mb-1 block">Status</label>
|
||||
<div className="mt-1">
|
||||
<StatusBadge variant={role.is_active !== false ? 'success' : 'failure'}>
|
||||
{role.is_active !== false ? 'Active' : 'Inactive'}
|
||||
</StatusBadge>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-xs font-medium text-[#6b7280] mb-1 block">Role ID</label>
|
||||
<p className="text-sm text-[#0e1b2a] font-mono">{role.id}</p>
|
||||
|
||||
@ -22,6 +22,8 @@ import {
|
||||
Modal,
|
||||
FormField,
|
||||
FormTextArea,
|
||||
FormSelect,
|
||||
StatusBadge,
|
||||
// DeleteConfirmationModal,
|
||||
type Column,
|
||||
} from "@/components/shared";
|
||||
@ -99,6 +101,7 @@ const newPlatformRoleSchema = z.object({
|
||||
"Code must be lowercase and use '_' for separation (e.g. abc_def)",
|
||||
),
|
||||
description: z.string().min(1, "Description is required"),
|
||||
is_active: z.boolean(),
|
||||
permissions: z
|
||||
.array(
|
||||
z.object({
|
||||
@ -123,6 +126,7 @@ const editPlatformRoleSchema = z.object({
|
||||
"Code must be lowercase and use '_' for separation (e.g. abc_def)",
|
||||
),
|
||||
description: z.string().min(1, "Description is required"),
|
||||
is_active: z.boolean(),
|
||||
permissions: z
|
||||
.array(
|
||||
z.object({
|
||||
@ -168,11 +172,13 @@ const NewPlatformRoleModal = ({
|
||||
resolver: zodResolver(newPlatformRoleSchema),
|
||||
defaultValues: {
|
||||
code: undefined,
|
||||
is_active: true,
|
||||
permissions: [],
|
||||
},
|
||||
});
|
||||
|
||||
const nameValue = watch("name");
|
||||
const statusValue = watch("is_active");
|
||||
|
||||
// Auto-generate code from name
|
||||
useEffect(() => {
|
||||
@ -189,6 +195,7 @@ const NewPlatformRoleModal = ({
|
||||
name: "",
|
||||
code: undefined,
|
||||
description: "",
|
||||
is_active: true,
|
||||
permissions: [],
|
||||
});
|
||||
setSelectedPermissions([]);
|
||||
@ -381,6 +388,20 @@ const NewPlatformRoleModal = ({
|
||||
rows={4}
|
||||
/>
|
||||
|
||||
<div className="pb-4">
|
||||
<FormSelect
|
||||
label="Status"
|
||||
required
|
||||
options={[
|
||||
{ value: "true", label: "Active" },
|
||||
{ value: "false", label: "Inactive" },
|
||||
]}
|
||||
value={String(statusValue)}
|
||||
onValueChange={(value) => setValue("is_active", value === "true", { shouldValidate: true })}
|
||||
error={errors.is_active?.message}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="pb-4">
|
||||
<div className="flex flex-col items-start gap-3 self-stretch p-4 rounded-[8px] border border-[#D1D5DB] bg-white">
|
||||
<div className="flex flex-col items-start self-stretch">
|
||||
@ -510,6 +531,7 @@ const EditPlatformRoleModal = ({
|
||||
register,
|
||||
handleSubmit,
|
||||
setValue,
|
||||
watch,
|
||||
reset,
|
||||
setError,
|
||||
clearErrors,
|
||||
@ -517,10 +539,13 @@ const EditPlatformRoleModal = ({
|
||||
} = useForm<EditPlatformRoleFormData>({
|
||||
resolver: zodResolver(editPlatformRoleSchema),
|
||||
defaultValues: {
|
||||
is_active: true,
|
||||
permissions: [],
|
||||
},
|
||||
});
|
||||
|
||||
const statusValue = watch("is_active");
|
||||
|
||||
// Build available resources and actions based on user permissions
|
||||
const availableResourcesAndActions = useMemo(() => {
|
||||
const resourceMap = new Map<string, Set<string>>();
|
||||
@ -608,6 +633,7 @@ const EditPlatformRoleModal = ({
|
||||
name: role.name,
|
||||
code: role.code,
|
||||
description: role.description || "",
|
||||
is_active: role.is_active ?? true,
|
||||
permissions: rolePermissions,
|
||||
});
|
||||
} catch (err: any) {
|
||||
@ -628,6 +654,7 @@ const EditPlatformRoleModal = ({
|
||||
name: "",
|
||||
code: "",
|
||||
description: "",
|
||||
is_active: true,
|
||||
permissions: [],
|
||||
});
|
||||
setLoadError(null);
|
||||
@ -769,6 +796,20 @@ const EditPlatformRoleModal = ({
|
||||
rows={4}
|
||||
/>
|
||||
|
||||
<div className="pb-4">
|
||||
<FormSelect
|
||||
label="Status"
|
||||
required
|
||||
options={[
|
||||
{ value: "true", label: "Active" },
|
||||
{ value: "false", label: "Inactive" },
|
||||
]}
|
||||
value={String(statusValue)}
|
||||
onValueChange={(value) => setValue("is_active", value === "true", { shouldValidate: true })}
|
||||
error={errors.is_active?.message}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="pb-4">
|
||||
<div className="flex flex-col items-start gap-3 self-stretch p-4 rounded-[8px] border border-[#D1D5DB] bg-white">
|
||||
<div className="flex flex-col items-start self-stretch">
|
||||
@ -909,6 +950,7 @@ export const PlatformRolesTable = forwardRef<PlatformRolesTableRef, {}>(
|
||||
|
||||
// Filter and Search state
|
||||
const [orderBy, setOrderBy] = useState<string[] | null>(null);
|
||||
const [statusFilter, setStatusFilter] = useState<string | null>(null);
|
||||
const [search, setSearch] = useState<string>("");
|
||||
const [debouncedSearch, setDebouncedSearch] = useState<string>("");
|
||||
|
||||
@ -924,7 +966,7 @@ export const PlatformRolesTable = forwardRef<PlatformRolesTableRef, {}>(
|
||||
useImperativeHandle(ref, () => ({
|
||||
openNewModal: () => setIsCreateOpen(true),
|
||||
refresh: () =>
|
||||
fetchPlatformRoles(currentPage, limit, orderBy, debouncedSearch),
|
||||
fetchPlatformRoles(currentPage, limit, orderBy, debouncedSearch, statusFilter),
|
||||
}));
|
||||
|
||||
const fetchPlatformRoles = async (
|
||||
@ -932,10 +974,12 @@ export const PlatformRolesTable = forwardRef<PlatformRolesTableRef, {}>(
|
||||
itemsPerPage: number,
|
||||
sortBy: string[] | null = null,
|
||||
searchQuery: string | null = null,
|
||||
statusValStr: string | null = null,
|
||||
) => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
setError(null);
|
||||
const statusVal = statusValStr === "true" ? true : statusValStr === "false" ? false : null;
|
||||
// Load roles filtered by scope=platform
|
||||
const response = await roleService.getAll(
|
||||
page,
|
||||
@ -943,6 +987,7 @@ export const PlatformRolesTable = forwardRef<PlatformRolesTableRef, {}>(
|
||||
sortBy,
|
||||
searchQuery,
|
||||
"platform",
|
||||
statusVal,
|
||||
);
|
||||
if (response.success) {
|
||||
setRoles(response.data);
|
||||
@ -970,8 +1015,8 @@ export const PlatformRolesTable = forwardRef<PlatformRolesTableRef, {}>(
|
||||
}, [search]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchPlatformRoles(currentPage, limit, orderBy, debouncedSearch);
|
||||
}, [currentPage, limit, orderBy, debouncedSearch]);
|
||||
fetchPlatformRoles(currentPage, limit, orderBy, debouncedSearch, statusFilter);
|
||||
}, [currentPage, limit, orderBy, debouncedSearch, statusFilter]);
|
||||
|
||||
const handleCreateRole = async (data: CreateRoleRequest) => {
|
||||
try {
|
||||
@ -986,7 +1031,7 @@ export const PlatformRolesTable = forwardRef<PlatformRolesTableRef, {}>(
|
||||
response.message || "Platform role created successfully",
|
||||
);
|
||||
setIsCreateOpen(false);
|
||||
fetchPlatformRoles(currentPage, limit, orderBy, debouncedSearch);
|
||||
fetchPlatformRoles(currentPage, limit, orderBy, debouncedSearch, statusFilter);
|
||||
} catch (err: any) {
|
||||
throw err;
|
||||
} finally {
|
||||
@ -1008,7 +1053,7 @@ export const PlatformRolesTable = forwardRef<PlatformRolesTableRef, {}>(
|
||||
);
|
||||
setEditModalOpen(false);
|
||||
setSelectedRoleId(null);
|
||||
fetchPlatformRoles(currentPage, limit, orderBy, debouncedSearch);
|
||||
fetchPlatformRoles(currentPage, limit, orderBy, debouncedSearch, statusFilter);
|
||||
} catch (err: any) {
|
||||
throw err;
|
||||
} finally {
|
||||
@ -1064,6 +1109,15 @@ export const PlatformRolesTable = forwardRef<PlatformRolesTableRef, {}>(
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: "is_active",
|
||||
label: "Status",
|
||||
render: (role) => (
|
||||
<StatusBadge variant={role.is_active !== false ? "success" : "failure"}>
|
||||
{role.is_active !== false ? "Active" : "Inactive"}
|
||||
</StatusBadge>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: "user_count",
|
||||
label: "Assigned Users",
|
||||
@ -1120,6 +1174,20 @@ export const PlatformRolesTable = forwardRef<PlatformRolesTableRef, {}>(
|
||||
placeholder="Search platform roles..."
|
||||
/>
|
||||
|
||||
<FilterDropdown
|
||||
label="Status"
|
||||
options={[
|
||||
{ value: "true", label: "Active" },
|
||||
{ value: "false", label: "Inactive" },
|
||||
]}
|
||||
value={statusFilter}
|
||||
onChange={(value) => {
|
||||
setStatusFilter(Array.isArray(value) ? null : value || null);
|
||||
setCurrentPage(1);
|
||||
}}
|
||||
placeholder="All Statuses"
|
||||
/>
|
||||
|
||||
<FilterDropdown
|
||||
label="Sort by"
|
||||
options={[
|
||||
|
||||
@ -683,6 +683,7 @@ export const PlatformUsersTable = forwardRef<PlatformUsersTableRef>(
|
||||
null,
|
||||
null,
|
||||
"platform",
|
||||
true,
|
||||
);
|
||||
if (response.success) {
|
||||
setRoles(response.data);
|
||||
|
||||
@ -63,12 +63,6 @@ export const RolesTable = forwardRef<RolesTableRef, RolesTableProps>(
|
||||
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
|
||||
const [isCreating, setIsCreating] = useState<boolean>(false);
|
||||
|
||||
// Expose imperative methods
|
||||
useImperativeHandle(ref, () => ({
|
||||
openNewModal: () => setIsModalOpen(true),
|
||||
refresh: () => fetchRoles(currentPage, limit, orderBy, debouncedSearch),
|
||||
}));
|
||||
|
||||
// Pagination state
|
||||
const [currentPage, setCurrentPage] = useState<number>(1);
|
||||
const [limit, setLimit] = useState<number>(5);
|
||||
@ -89,6 +83,13 @@ export const RolesTable = forwardRef<RolesTableRef, RolesTableProps>(
|
||||
// Filter state
|
||||
// const [scopeFilter, setScopeFilter] = useState<string | null>(null);
|
||||
const [orderBy, setOrderBy] = useState<string[] | null>(null);
|
||||
const [statusFilter, setStatusFilter] = useState<string | null>(null);
|
||||
|
||||
// Expose imperative methods
|
||||
useImperativeHandle(ref, () => ({
|
||||
openNewModal: () => setIsModalOpen(true),
|
||||
refresh: () => fetchRoles(currentPage, limit, orderBy, debouncedSearch, statusFilter),
|
||||
}));
|
||||
|
||||
// Search state
|
||||
const [search, setSearch] = useState<string>("");
|
||||
@ -106,13 +107,14 @@ export const RolesTable = forwardRef<RolesTableRef, RolesTableProps>(
|
||||
const fetchRoles = async (
|
||||
page: number,
|
||||
itemsPerPage: number,
|
||||
// scope: string | null = null,
|
||||
sortBy: string[] | null = null,
|
||||
searchQuery: string | null = null,
|
||||
statusValStr: string | null = null,
|
||||
): Promise<void> => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
setError(null);
|
||||
const statusVal = statusValStr === "true" ? true : statusValStr === "false" ? false : null;
|
||||
const response = tenantId
|
||||
? await roleService.getByTenant(
|
||||
tenantId,
|
||||
@ -120,8 +122,16 @@ export const RolesTable = forwardRef<RolesTableRef, RolesTableProps>(
|
||||
itemsPerPage,
|
||||
sortBy,
|
||||
searchQuery,
|
||||
statusVal,
|
||||
)
|
||||
: await roleService.getAll(page, itemsPerPage, sortBy, searchQuery);
|
||||
: await roleService.getAll(
|
||||
page,
|
||||
itemsPerPage,
|
||||
sortBy,
|
||||
searchQuery,
|
||||
null,
|
||||
statusVal,
|
||||
);
|
||||
if (response.success) {
|
||||
setRoles(response.data);
|
||||
setPagination(response.pagination);
|
||||
@ -145,8 +155,8 @@ export const RolesTable = forwardRef<RolesTableRef, RolesTableProps>(
|
||||
}, [search]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchRoles(currentPage, limit, orderBy, debouncedSearch);
|
||||
}, [currentPage, limit, orderBy, debouncedSearch, tenantId]);
|
||||
fetchRoles(currentPage, limit, orderBy, debouncedSearch, statusFilter);
|
||||
}, [currentPage, limit, orderBy, debouncedSearch, statusFilter, tenantId]);
|
||||
|
||||
const handleCreateRole = async (data: CreateRoleRequest): Promise<void> => {
|
||||
try {
|
||||
@ -158,7 +168,7 @@ export const RolesTable = forwardRef<RolesTableRef, RolesTableProps>(
|
||||
: `${data.name} has been added`;
|
||||
showToast.success(message, description);
|
||||
setIsModalOpen(false);
|
||||
await fetchRoles(currentPage, limit, orderBy);
|
||||
await fetchRoles(currentPage, limit, orderBy, debouncedSearch, statusFilter);
|
||||
} catch (err: any) {
|
||||
throw err;
|
||||
} finally {
|
||||
@ -197,7 +207,7 @@ export const RolesTable = forwardRef<RolesTableRef, RolesTableProps>(
|
||||
setEditModalOpen(false);
|
||||
setSelectedRoleId(null);
|
||||
// setSelectedRoleName("");
|
||||
await fetchRoles(currentPage, limit, orderBy);
|
||||
await fetchRoles(currentPage, limit, orderBy, debouncedSearch, statusFilter);
|
||||
} catch (err: any) {
|
||||
throw err;
|
||||
} finally {
|
||||
@ -282,6 +292,15 @@ export const RolesTable = forwardRef<RolesTableRef, RolesTableProps>(
|
||||
</StatusBadge>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: "is_active",
|
||||
label: "Status",
|
||||
render: (role) => (
|
||||
<StatusBadge variant={role.is_active !== false ? "success" : "failure"}>
|
||||
{role.is_active !== false ? "Active" : "Inactive"}
|
||||
</StatusBadge>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: "user_count",
|
||||
label: "Users",
|
||||
@ -357,6 +376,14 @@ export const RolesTable = forwardRef<RolesTableRef, RolesTableProps>(
|
||||
</StatusBadge>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<span className="text-[#9aa6b2]">Status:</span>
|
||||
<div className="mt-1">
|
||||
<StatusBadge variant={role.is_active !== false ? "success" : "failure"}>
|
||||
{role.is_active !== false ? "Active" : "Inactive"}
|
||||
</StatusBadge>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<span className="text-[#9aa6b2]">Users:</span>
|
||||
<p className="text-[#0f1724] font-normal mt-1">
|
||||
@ -394,6 +421,19 @@ export const RolesTable = forwardRef<RolesTableRef, RolesTableProps>(
|
||||
onChange={setSearch}
|
||||
placeholder="Search..."
|
||||
/>
|
||||
<FilterDropdown
|
||||
label="Status"
|
||||
options={[
|
||||
{ value: "true", label: "Active" },
|
||||
{ value: "false", label: "Inactive" },
|
||||
]}
|
||||
value={statusFilter}
|
||||
onChange={(value) => {
|
||||
setStatusFilter(Array.isArray(value) ? null : value || null);
|
||||
setCurrentPage(1);
|
||||
}}
|
||||
placeholder="All Statuses"
|
||||
/>
|
||||
{isTenantAdmin && (
|
||||
<PrimaryButton
|
||||
size="default"
|
||||
@ -499,6 +539,21 @@ export const RolesTable = forwardRef<RolesTableRef, RolesTableProps>(
|
||||
placeholder="Search by name or code..."
|
||||
/>
|
||||
|
||||
{/* Status Filter */}
|
||||
<FilterDropdown
|
||||
label="Status"
|
||||
options={[
|
||||
{ value: "true", label: "Active" },
|
||||
{ value: "false", label: "Inactive" },
|
||||
]}
|
||||
value={statusFilter}
|
||||
onChange={(value) => {
|
||||
setStatusFilter(Array.isArray(value) ? null : value || null);
|
||||
setCurrentPage(1);
|
||||
}}
|
||||
placeholder="All Statuses"
|
||||
/>
|
||||
|
||||
{/* Sort Filter */}
|
||||
<FilterDropdown
|
||||
label="Sort by"
|
||||
|
||||
@ -15,7 +15,8 @@ export const roleService = {
|
||||
limit: number = 20,
|
||||
orderBy?: string[] | null,
|
||||
search?: string | null,
|
||||
scope?: string | null
|
||||
scope?: string | null,
|
||||
isActive?: boolean | null
|
||||
): Promise<RolesResponse> => {
|
||||
const params = new URLSearchParams();
|
||||
params.append('page', String(page));
|
||||
@ -26,6 +27,9 @@ export const roleService = {
|
||||
if (scope) {
|
||||
params.append('scope', scope);
|
||||
}
|
||||
if (isActive !== undefined && isActive !== null) {
|
||||
params.append('is_active', String(isActive));
|
||||
}
|
||||
if (orderBy && Array.isArray(orderBy) && orderBy.length === 2) {
|
||||
params.append('orderBy[]', orderBy[0]);
|
||||
params.append('orderBy[]', orderBy[1]);
|
||||
@ -38,7 +42,8 @@ export const roleService = {
|
||||
page: number = 1,
|
||||
limit: number = 20,
|
||||
orderBy?: string[] | null,
|
||||
search?: string | null
|
||||
search?: string | null,
|
||||
isActive?: boolean | null
|
||||
): Promise<RolesResponse> => {
|
||||
const params = new URLSearchParams();
|
||||
params.append('page', String(page));
|
||||
@ -47,6 +52,9 @@ export const roleService = {
|
||||
if (search) {
|
||||
params.append('search', search);
|
||||
}
|
||||
if (isActive !== undefined && isActive !== null) {
|
||||
params.append('is_active', String(isActive));
|
||||
}
|
||||
if (orderBy && Array.isArray(orderBy) && orderBy.length === 2) {
|
||||
params.append('orderBy[]', orderBy[0]);
|
||||
params.append('orderBy[]', orderBy[1]);
|
||||
|
||||
@ -5,6 +5,7 @@ export interface Role {
|
||||
description?: string;
|
||||
scope: 'platform' | 'tenant' | 'module';
|
||||
is_system?: boolean;
|
||||
is_active?: boolean;
|
||||
tenant_id?: string | null;
|
||||
module_ids?: string[] | null;
|
||||
modules?: string[] | null;
|
||||
@ -37,6 +38,7 @@ export interface CreateRoleRequest {
|
||||
name: string;
|
||||
code: string;
|
||||
description: string;
|
||||
is_active?: boolean;
|
||||
tenant_id?: string | null;
|
||||
module_ids?: string[] | null;
|
||||
modules?: string[] | null;
|
||||
@ -58,6 +60,7 @@ export interface UpdateRoleRequest {
|
||||
name?: string;
|
||||
code?: string;
|
||||
description?: string;
|
||||
is_active?: boolean;
|
||||
tenant_id?: string | null;
|
||||
module_ids?: string[] | null;
|
||||
modules?: string[] | null;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user