|
|
@@ -1,9 +1,10 @@
|
|
|
-import { useEffect } from 'react'
|
|
|
+import { useEffect, useMemo } from 'react'
|
|
|
import { z } from 'zod'
|
|
|
import { useForm } from 'react-hook-form'
|
|
|
import { zodResolver } from '@hookform/resolvers/zod'
|
|
|
import { toast } from 'sonner'
|
|
|
import { getApiErrorMessage } from '@/lib/api-error'
|
|
|
+import { useActivityFields } from '@/hooks/activity-fields/useActivityFields'
|
|
|
import { usePermissionModules } from '@/hooks/permissions/usePermissionModules'
|
|
|
import { useCreateRole } from '@/hooks/roles/useCreateRole'
|
|
|
import { useRole } from '@/hooks/roles/useRole'
|
|
|
@@ -25,13 +26,16 @@ import {
|
|
|
FormMessage,
|
|
|
} from '@/components/ui/form'
|
|
|
import { Input } from '@/components/ui/input'
|
|
|
-import { ScrollArea } from '@/components/ui/scroll-area'
|
|
|
+import { ActivityFieldPicker } from './activity-field-picker'
|
|
|
import { PermissionPicker } from './permission-picker'
|
|
|
import { useRolesContext } from './roles-provider'
|
|
|
|
|
|
const schema = z.object({
|
|
|
name: z.string().trim().min(1, 'نام نقش الزامی است'),
|
|
|
permissions: z.array(z.string()).min(1, 'حداقل یک دسترسی را انتخاب کنید'),
|
|
|
+ activity_field_ids: z
|
|
|
+ .array(z.number())
|
|
|
+ .min(1, 'حداقل یک رشته را انتخاب کنید'),
|
|
|
})
|
|
|
|
|
|
type FormValues = z.infer<typeof schema>
|
|
|
@@ -46,6 +50,7 @@ export function RolesActionDialog() {
|
|
|
|
|
|
const roleQuery = useRole(opened && !isAdd ? currentRow?.id : undefined)
|
|
|
const modulesQuery = usePermissionModules(opened)
|
|
|
+ const activityFieldsQuery = useActivityFields(opened)
|
|
|
const createMutation = useCreateRole()
|
|
|
const updateMutation = useUpdateRole()
|
|
|
const isPending = createMutation.isPending || updateMutation.isPending
|
|
|
@@ -55,6 +60,7 @@ export function RolesActionDialog() {
|
|
|
defaultValues: {
|
|
|
name: '',
|
|
|
permissions: [],
|
|
|
+ activity_field_ids: [],
|
|
|
},
|
|
|
})
|
|
|
|
|
|
@@ -62,7 +68,7 @@ export function RolesActionDialog() {
|
|
|
if (!opened) return
|
|
|
|
|
|
if (isAdd) {
|
|
|
- form.reset({ name: '', permissions: [] })
|
|
|
+ form.reset({ name: '', permissions: [], activity_field_ids: [] })
|
|
|
return
|
|
|
}
|
|
|
|
|
|
@@ -73,13 +79,16 @@ export function RolesActionDialog() {
|
|
|
permissions: roleQuery.data.permissions.map(
|
|
|
(permission) => permission.name
|
|
|
),
|
|
|
+ activity_field_ids: roleQuery.data.activity_field_ids?.length
|
|
|
+ ? roleQuery.data.activity_field_ids
|
|
|
+ : (roleQuery.data.activity_fields ?? []).map((field) => field.id),
|
|
|
})
|
|
|
}, [opened, isAdd, roleQuery.data, form])
|
|
|
|
|
|
const handleClose = () => {
|
|
|
setOpen(null)
|
|
|
setCurrentRow(null)
|
|
|
- form.reset({ name: '', permissions: [] })
|
|
|
+ form.reset({ name: '', permissions: [], activity_field_ids: [] })
|
|
|
}
|
|
|
|
|
|
const onSubmit = (values: FormValues) => {
|
|
|
@@ -88,6 +97,7 @@ export function RolesActionDialog() {
|
|
|
const payload = {
|
|
|
name: values.name.trim(),
|
|
|
permissions: values.permissions,
|
|
|
+ activity_field_ids: values.activity_field_ids,
|
|
|
}
|
|
|
|
|
|
if (isAdd) {
|
|
|
@@ -118,8 +128,24 @@ export function RolesActionDialog() {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ const activityFieldOptions = useMemo(() => {
|
|
|
+ const options = new Map<number, string>()
|
|
|
+
|
|
|
+ for (const field of activityFieldsQuery.data ?? []) {
|
|
|
+ options.set(field.id, field.name)
|
|
|
+ }
|
|
|
+
|
|
|
+ for (const field of roleQuery.data?.activity_fields ?? []) {
|
|
|
+ if (!options.has(field.id)) options.set(field.id, field.name)
|
|
|
+ }
|
|
|
+
|
|
|
+ return [...options.entries()].map(([id, name]) => ({ id, name }))
|
|
|
+ }, [activityFieldsQuery.data, roleQuery.data])
|
|
|
+
|
|
|
const isLoading =
|
|
|
- modulesQuery.isLoading || ((isEdit || isView) && roleQuery.isLoading)
|
|
|
+ modulesQuery.isLoading ||
|
|
|
+ activityFieldsQuery.isLoading ||
|
|
|
+ ((isEdit || isView) && roleQuery.isLoading)
|
|
|
|
|
|
return (
|
|
|
<Dialog open={opened} onOpenChange={(state) => !state && handleClose()}>
|
|
|
@@ -142,7 +168,7 @@ export function RolesActionDialog() {
|
|
|
<Form {...form}>
|
|
|
<form
|
|
|
onSubmit={form.handleSubmit(onSubmit)}
|
|
|
- className='flex min-h-0 flex-1 flex-col gap-4'
|
|
|
+ className='flex min-h-0 flex-1 flex-col gap-4 overflow-hidden'
|
|
|
>
|
|
|
<FormField
|
|
|
control={form.control}
|
|
|
@@ -162,26 +188,53 @@ export function RolesActionDialog() {
|
|
|
)}
|
|
|
/>
|
|
|
|
|
|
+ <FormField
|
|
|
+ control={form.control}
|
|
|
+ name='activity_field_ids'
|
|
|
+ render={({ field }) => (
|
|
|
+ <FormItem className='shrink-0'>
|
|
|
+ <FormLabel>رشتهها</FormLabel>
|
|
|
+ {activityFieldsQuery.isError ? (
|
|
|
+ <p className='text-sm text-destructive'>
|
|
|
+ دریافت رشتهها ممکن نشد.
|
|
|
+ </p>
|
|
|
+ ) : activityFieldOptions.length === 0 ? (
|
|
|
+ <p className='text-sm text-muted-foreground'>
|
|
|
+ رشتهای برای انتخاب وجود ندارد.
|
|
|
+ </p>
|
|
|
+ ) : (
|
|
|
+ <ActivityFieldPicker
|
|
|
+ fields={activityFieldOptions}
|
|
|
+ value={field.value}
|
|
|
+ onChange={field.onChange}
|
|
|
+ disabled={readOnly}
|
|
|
+ />
|
|
|
+ )}
|
|
|
+ <FormMessage />
|
|
|
+ </FormItem>
|
|
|
+ )}
|
|
|
+ />
|
|
|
+
|
|
|
<FormField
|
|
|
control={form.control}
|
|
|
name='permissions'
|
|
|
render={({ field }) => (
|
|
|
- <FormItem className='min-h-0 flex-1'>
|
|
|
+ <FormItem className='flex min-h-0 flex-1 flex-col'>
|
|
|
<FormLabel>دسترسیها</FormLabel>
|
|
|
- <ScrollArea className='h-[50vh] rounded-md border p-3'>
|
|
|
+ <div className='min-h-48 flex-1 overflow-y-auto rounded-md border p-3'>
|
|
|
<PermissionPicker
|
|
|
modules={modulesQuery.data ?? []}
|
|
|
value={field.value}
|
|
|
onChange={field.onChange}
|
|
|
disabled={readOnly}
|
|
|
/>
|
|
|
- </ScrollArea>
|
|
|
+ </div>
|
|
|
<FormMessage />
|
|
|
</FormItem>
|
|
|
)}
|
|
|
/>
|
|
|
|
|
|
- <DialogFooter>
|
|
|
+ <DialogFooter className='shrink-0'>
|
|
|
<Button type='button' variant='outline' onClick={handleClose}>
|
|
|
{readOnly ? 'بستن' : 'انصراف'}
|
|
|
</Button>
|