Skip to content

Commit 15324cb

Browse files
committed
Add RoleDetailsModal
1 parent 1bbabd3 commit 15324cb

3 files changed

Lines changed: 123 additions & 0 deletions

File tree

src/contexts/api/auth/AuthContext.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,9 @@ export interface AuthContextValue {
8989
/** Deletes a role */
9090
deleteRole(id: number): Promise<Result<void>>;
9191

92+
/** Get all users of a role */
93+
getUsersOfRole(id: number): Promise<Result<User[]>>;
94+
9295
/** Adds a user to a role */
9396
addUserToRole(userid: number, roleid: number): Promise<Result<void>>;
9497

@@ -136,6 +139,8 @@ export const AuthContext = createContext<AuthContextValue>({
136139
createRole: async () => errorResult('No auth context for creating role'),
137140
updateRole: async () => errorResult('No auth context for updating role'),
138141
deleteRole: async () => errorResult('No auth context for deleting role'),
142+
getUsersOfRole: async () =>
143+
errorResult('No auth context for fetching users of role'),
139144
addUserToRole: async () =>
140145
errorResult('No auth context for adding user to role'),
141146
removeUserFromRole: async () =>
@@ -414,6 +419,17 @@ export function AuthContextProvider({ children }: AuthContextProviderProps) {
414419
}
415420
},
416421

422+
async getUsersOfRole(id: number) {
423+
try {
424+
const apiUsersResponse = await apiRef.current.roles.usersDetail(id);
425+
return okResult(apiUsersResponse.data.map(convert.userFromApi));
426+
} catch (error) {
427+
return errorResult(
428+
`Fetching users of role with id ${id} failed: ${await formatError(error)}`
429+
);
430+
}
431+
},
432+
417433
async addUserToRole(userid: number, roleid: number) {
418434
try {
419435
await apiRef.current.roles.usersUpdate(roleid, userid);

src/modals/RoleDetailsModal.tsx

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import { AuthContext } from '@luna/contexts/api/auth/AuthContext';
2+
import {
3+
newUninitializedRole,
4+
Role,
5+
User,
6+
} from '@luna/contexts/api/auth/types';
7+
import {
8+
Button,
9+
Input,
10+
Modal,
11+
ModalBody,
12+
ModalContent,
13+
ModalFooter,
14+
ModalHeader,
15+
Table,
16+
TableBody,
17+
TableCell,
18+
TableColumn,
19+
TableHeader,
20+
TableRow,
21+
} from '@heroui/react';
22+
import { useContext, useEffect, useState } from 'react';
23+
24+
export interface RoleShowModalProps {
25+
id: number;
26+
isOpen: boolean;
27+
setOpen: (open: boolean) => void;
28+
}
29+
30+
export function RoleDetailsModal({ id, isOpen, setOpen }: RoleShowModalProps) {
31+
const [role, setRole] = useState<Role>(newUninitializedRole());
32+
const [users, setUsers] = useState<User[]>([]);
33+
const auth = useContext(AuthContext);
34+
35+
// initialize modal state
36+
useEffect(() => {
37+
if (!isOpen) return;
38+
const fetchRole = async () => {
39+
const roleResult = await auth.getRoleById(id);
40+
if (roleResult.ok) {
41+
setRole(roleResult.value);
42+
} else {
43+
console.log('Failed to fetch role:', roleResult.error);
44+
setRole(newUninitializedRole());
45+
}
46+
const usersResult = await auth.getUsersOfRole(id);
47+
if (usersResult.ok) {
48+
setUsers(usersResult.value);
49+
} else {
50+
console.log('Failed to fetch users of role:', usersResult.error);
51+
setRole(newUninitializedRole());
52+
}
53+
};
54+
fetchRole();
55+
}, [auth, id, isOpen]);
56+
57+
return (
58+
<Modal isOpen={isOpen} onOpenChange={setOpen}>
59+
<ModalContent>
60+
{onClose => (
61+
<>
62+
<ModalHeader>Role</ModalHeader>
63+
<ModalBody>
64+
<Input label="ID" value={id.toString()} isDisabled />
65+
<Input label="Name" value={role.name} />
66+
Users:
67+
<Table>
68+
<TableHeader>
69+
<TableColumn key="id" allowsSorting>
70+
ID
71+
</TableColumn>
72+
<TableColumn key="id" allowsSorting>
73+
Username
74+
</TableColumn>
75+
</TableHeader>
76+
<TableBody items={users}>
77+
{user => (
78+
<TableRow key={user.username}>
79+
<TableCell>{user.id}</TableCell>
80+
<TableCell>{user.username}</TableCell>
81+
</TableRow>
82+
)}
83+
</TableBody>
84+
</Table>
85+
</ModalBody>
86+
<ModalFooter>
87+
<Button onPress={onClose}>Cancel</Button>
88+
</ModalFooter>
89+
</>
90+
)}
91+
</ModalContent>
92+
</Modal>
93+
);
94+
}

src/screens/home/admin/RolesView.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import { useContext, useState } from 'react';
2626
import { RoleAddModal } from '@luna/modals/RoleAddModal';
2727
import { RoleDeleteModal } from '@luna/modals/RoleDeleteModal';
2828
import { RoleEditModal } from '@luna/modals/RoleEditModal';
29+
import { RoleDetailsModal } from '@luna/modals/RoleDetailsModal';
2930

3031
export function RolesView() {
3132
const auth = useContext(AuthContext);
@@ -79,6 +80,11 @@ export function RolesView() {
7980
}
8081
>
8182
<RoleAddModal isOpen={showRoleAddModal} setOpen={setShowRoleAddModal} />
83+
<RoleDetailsModal
84+
id={roleId}
85+
isOpen={showRoleDetailsModal}
86+
setOpen={setShowRoleDetailsModal}
87+
/>
8288
<RoleEditModal
8389
id={roleId}
8490
isOpen={showRoleEditModal}
@@ -120,6 +126,13 @@ export function RolesView() {
120126
<TableCell>{role.updatedAt.toLocaleString()}</TableCell>
121127
<TableCell>
122128
<div className="relative flex items-center gap-2">
129+
<IconEye
130+
className="text-lg cursor-pointer active:opacity-50"
131+
onClick={() => {
132+
setRoleId(role.id);
133+
setShowRoleDetailsModal(true);
134+
}}
135+
/>
123136
<Tooltip content="Edit role">
124137
<IconPencil
125138
className="text-lg cursor-pointer active:opacity-50"

0 commit comments

Comments
 (0)