erp-platform/ui/src/views/admin/role-management/RolesPermission.tsx
Sedat Öztürk d10763c4ea Hr Expense
2025-10-26 23:27:01 +03:00

340 lines
11 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import Container from '@/components/shared/Container'
import { Button, Checkbox, Dialog, Input, Menu, toast } from '@/components/ui'
import { useConfig } from '@/components/ui/ConfigProvider'
import Notification from '@/components/ui/Notification'
import {
GetPermissionListResultDto,
PermissionGrantInfoDto,
PermissionGroupDto,
PermissionWithGroupName,
PermissionWithStyle,
UpdatePermissionDto,
} from '@/proxy/admin/models'
import { getPermissions, updatePermissions } from '@/services/identity.service'
import { useStoreActions, useStoreState } from '@/store'
import { useLocalization } from '@/utils/hooks/useLocalization'
import { ChangeEvent, useEffect, useMemo, useState } from 'react'
function RolesPermission({
open,
onDialogClose,
name,
}: {
open: boolean
onDialogClose: () => void
name: string
}) {
const providerName = 'R'
const { translate } = useLocalization()
const { getConfig } = useStoreActions((a) => a.abpConfig)
const [isLoading, setIsLoading] = useState(false)
const [permissionList, setPermissionList] = useState<GetPermissionListResultDto>()
const [selectedGroup, setSelectedGroup] = useState<PermissionGroupDto | undefined>()
const [selectedGroupPermissions, setSelectedGroupPermissions] = useState<PermissionWithStyle[]>(
[],
)
const [searchTerm, setSearchTerm] = useState('')
const mode = useStoreState((state) => state.theme.mode)
const tenant = useStoreState((state) => state.auth.tenant)
const { direction } = useConfig()
const className = `m${direction[0]}-`
const fetchDataPermissions = async () => {
if (!name) return
const response = await getPermissions(providerName, name)
const data = response.data
const tenantGroup = tenant?.menuGroup?.trim()
if (!tenantGroup) {
console.warn('Tenant menuGroup boş, tüm izinler gösterilecek')
setPermissionList(data)
return
}
const filteredGroups = data.groups
.map((group: any) => {
const filteredPermissions = group.permissions.filter(
(perm: any) => Array.isArray(perm.menuGroup) && perm.menuGroup.includes(tenantGroup),
)
return { ...group, permissions: filteredPermissions }
})
.filter((group: any) => group.permissions.length > 0)
const filteredData = { ...data, groups: filteredGroups }
console.log('Filtered permissions by tenant group:', tenantGroup, filteredData)
setPermissionList(filteredData)
}
const changeGroup = (groupName?: string) => {
const group = permissionList?.groups.find((a: any) => a.name === groupName)
if (!group) {
setSelectedGroup(undefined)
setSelectedGroupPermissions([])
return
}
setSelectedGroup(group)
const selectedGroupPerm = group.permissions.map(
(permission: any) =>
({
...permission,
class: className + findMargin(group.permissions, permission) * 4,
}) as PermissionWithStyle,
)
setSelectedGroupPermissions(selectedGroupPerm)
}
const onDialogOk = async () => {
setIsLoading(true)
setTimeout(async () => {
if (permissionList?.groups && name) {
const listPermissions = await getPermissions(providerName, name)
const unChangedPermissions = getPermissionsWithGroupName(listPermissions.data?.groups)
const changedPermissions = getPermissionsWithGroupName(permissionList.groups)
const updatePermList: UpdatePermissionDto[] = changedPermissions
.filter((per) =>
(unChangedPermissions.find((unChanged) => unChanged.name === per.name) || {})
.isGranted === per.isGranted
? false
: true,
)
.map(({ name, isGranted }) => ({ name, isGranted }))
updatePermissions(providerName, name, { permissions: updatePermList })
toast.push(<Notification title={'Permission updated'} type="success" />, {
placement: 'top-end',
})
}
onDialogClose()
setIsLoading(false)
}, 1000)
setTimeout(async () => {
getConfig(true)
}, 6000)
}
function getPermissionsWithGroupName(groups: PermissionGroupDto[]): PermissionWithGroupName[] {
return groups.reduce(
(acc, val) => [
...acc,
...val.permissions.map<PermissionWithGroupName>((p: any) => ({
...p,
groupName: val.name || '',
})),
],
[] as PermissionWithGroupName[],
)
}
function findMargin(
permissions: PermissionGrantInfoDto[],
permission: PermissionGrantInfoDto,
level = 0,
): number {
const parentPermission = permissions.find((per) => per.name === permission.parentName)
if (parentPermission) {
return findMargin(permissions, parentPermission, level + 1)
} else {
return level
}
}
const isAllSelected = useMemo(
() =>
permissionList?.groups.every((group: any) =>
group.permissions.every((permission: any) => permission.isGranted),
),
[permissionList],
)
const isAllSelectedForGroup = useMemo(
() => selectedGroupPermissions.every((permission) => permission.isGranted),
[selectedGroupPermissions],
)
const filteredPermissions = useMemo(() => {
if (!searchTerm) {
return selectedGroupPermissions
}
const lowerTerm = searchTerm.toLowerCase()
// 1⃣ Sadece 1. kırınımdakileri (parent olmayanları değil) ara
const topLevelMatches = selectedGroupPermissions.filter(
(p) =>
!p.parentName && // parentName yoksa bu 1. kırınım demektir
translate('::' + p.displayName)
.toLowerCase()
.includes(lowerTerm),
)
// 2⃣ Her bulunan parentın altındaki child izinleri ekle
const result: PermissionWithStyle[] = []
topLevelMatches.forEach((parent) => {
result.push(parent)
// Alt kırılımları bul
const children = selectedGroupPermissions.filter((child) => child.parentName === parent.name)
result.push(...children)
})
return result
}, [selectedGroupPermissions, searchTerm, translate])
const onSelectAll = (value: boolean, e: ChangeEvent<HTMLInputElement>) => {
if (!permissionList) {
return
}
const currentGroupName = selectedGroup?.name
setSelectedGroup(undefined)
setSelectedGroupPermissions([])
if (e.target.name === 'group') {
permissionList?.groups
.find((group: any) => group.name === selectedGroup?.name)
?.permissions.forEach((permission: any) => {
permission.isGranted = value
})
} else {
permissionList?.groups.forEach((group: any) => {
group.permissions.forEach((permission: any) => {
permission.isGranted = value
})
})
}
setPermissionList({ ...permissionList })
changeGroup(currentGroupName)
}
function onClickCheckbox(clickedPermission: PermissionGrantInfoDto) {
if (!permissionList) {
return
}
const groupPerm = selectedGroupPermissions.map((per) => {
if (clickedPermission.name === per.name) {
return { ...per, isGranted: !per.isGranted }
} else if (clickedPermission.name === per.parentName && clickedPermission.isGranted) {
return { ...per, isGranted: false }
} else if (clickedPermission.parentName === per.name && !clickedPermission.isGranted) {
return { ...per, isGranted: true }
}
return per
})
const permGroup = permissionList?.groups.find((a: any) => a.name === selectedGroup?.name)
if (permGroup) {
permGroup.permissions = groupPerm
}
setPermissionList({ ...permissionList })
setSelectedGroupPermissions(groupPerm)
}
useEffect(() => {
fetchDataPermissions()
}, [name])
return permissionList ? (
<Container>
<Dialog
width="60%"
isOpen={open}
onAfterOpen={() => changeGroup(permissionList?.groups[0].name)}
onClose={onDialogClose}
onRequestClose={onDialogClose}
>
<h5 className="mb-1">
{translate('::Permission')} - {name}
</h5>
<hr className="mt-1 mb-1"></hr>
<div className="flex flex-col md:flex-row gap-4 mb-1">
<div style={{ width: '30%' }}>
<Checkbox name="all" checked={isAllSelected} onChange={onSelectAll}>
{translate('AbpPermissionManagement::SelectAllInAllTabs')}
</Checkbox>
</div>
<div style={{ width: '70%' }}>
<Checkbox name="group" checked={isAllSelectedForGroup} onChange={onSelectAll}>
{translate('AbpPermissionManagement::SelectAllInThisTab')}
</Checkbox>
</div>
</div>
<div className="flex flex-col md:flex-row gap-4">
<div style={{ width: '30%' }} className="max-h-[470px] overflow-y-auto">
<hr className="mb-2"></hr>
<Menu
className="w-full"
variant={mode}
defaultActiveKeys={[selectedGroup?.displayName ?? '']}
>
{permissionList?.groups.map((group: any) => (
<Menu.MenuItem
key={group.name}
className="break-all whitespace-normal"
eventKey={group.name}
onSelect={changeGroup}
>
{translate('::' + group.displayName)} (
{group.permissions.filter((a: any) => a.isGranted).length})
</Menu.MenuItem>
))}
</Menu>
</div>
<div style={{ width: '70%' }} className="max-h-[470px] overflow-y-auto">
<hr className="mb-2"></hr>
<Input
size="sm"
className="mb-2"
placeholder="Yetkiler içinde ara..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
<div className="my-1">
{filteredPermissions.map((permission) => (
<div key={permission.name}>
<Checkbox
name={permission.name}
className={permission.class}
checked={permission.isGranted}
onChange={() => onClickCheckbox(permission)}
>
{translate('::' + permission.displayName)}
</Checkbox>
</div>
))}
</div>
</div>
</div>
<div className="text-right mt-6">
<Button className="ltr:mr-2 rtl:ml-2" variant="plain" onClick={onDialogClose}>
{translate('::Cancel')}
</Button>
<Button variant="solid" loading={isLoading} onClick={onDialogOk}>
{isLoading ? translate('::SavingWithThreeDot') : translate('::Save')}
</Button>
</div>
</Dialog>
</Container>
) : (
<></>
)
}
export default RolesPermission