import { Component, computed, inject, input } from '@angular/core'; import { CommonModule } from '@angular/common'; import { FormsModule } from '@angular/forms'; import { NgIcon, provideIcons } from '@ng-icons/core'; import { Store } from '@ngrx/store'; import { lucideUserX, lucideBan } from '@ng-icons/lucide'; import { Room, RoomMember, RoomRole } from '../../../../shared-kernel'; import { RoomsActions } from '../../../../store/rooms/rooms.actions'; import { UsersActions } from '../../../../store/users/users.actions'; import { selectCurrentUser, selectUsersEntities } from '../../../../store/users/users.selectors'; import { selectCurrentRoom } from '../../../../store/rooms/rooms.selectors'; import { UserAvatarComponent } from '../../../../shared'; import { canManageMember, findAssignableRoles, getDisplayRoleName, getRoleIdsForMember, normalizeRoomAccessControl, setRoleAssignmentsForMember } from '../../../../domains/access-control'; import { AppI18nService, APP_TRANSLATE_IMPORTS } from '../../../../core/i18n'; interface ServerMemberView extends RoomMember { assignedRoleIds: string[]; displayRoleName: string; isOnline: boolean; } @Component({ selector: 'app-members-settings', standalone: true, imports: [ CommonModule, FormsModule, NgIcon, UserAvatarComponent, ...APP_TRANSLATE_IMPORTS ], viewProviders: [ provideIcons({ lucideUserX, lucideBan }) ], templateUrl: './members-settings.component.html' }) export class MembersSettingsComponent { /** The currently selected server, passed from the parent. */ server = input(null); /** Whether the current user is admin of this server. */ isAdmin = input(false); accessRole = input(null); currentUser = this.store.selectSignal(selectCurrentUser); currentRoom = this.store.selectSignal(selectCurrentRoom); usersEntities = this.store.selectSignal(selectUsersEntities); normalizedServer = computed(() => { const room = this.server(); return room ? normalizeRoomAccessControl(room) : null; }); assignableRoles = computed(() => findAssignableRoles(this.normalizedServer()?.roles ?? [])); members = computed(() => { const room = this.normalizedServer(); const me = this.currentUser(); const currentRoom = this.currentRoom(); const usersEntities = this.usersEntities(); if (!room) return []; return (room.members ?? []) .filter((member) => member.id !== me?.id && member.oderId !== me?.oderId) .map((member) => { const liveUser = currentRoom?.id === room.id ? (usersEntities[member.id] || Object.values(usersEntities).find((user) => !!user && user.oderId === member.oderId) || null) : null; return { ...member, assignedRoleIds: getRoleIdsForMember(room, member), displayRoleName: getDisplayRoleName(room, member, (key) => this.i18n.instant(key)), avatarUrl: liveUser?.avatarUrl || member.avatarUrl, displayName: liveUser?.displayName || member.displayName, isOnline: !!liveUser && (liveUser.isOnline === true || liveUser.status !== 'offline') }; }); }); private store = inject(Store); private readonly i18n = inject(AppI18nService); canChangeRoles(member: ServerMemberView): boolean { const room = this.normalizedServer(); const currentUser = this.currentUser(); return !!room && !!currentUser && canManageMember(room, currentUser, member, 'manageRoles'); } canKickMembers(member: ServerMemberView): boolean { const room = this.normalizedServer(); const currentUser = this.currentUser(); return !!room && !!currentUser && canManageMember(room, currentUser, member, 'kickMembers'); } canBanMembers(member: ServerMemberView): boolean { const room = this.normalizedServer(); const currentUser = this.currentUser(); return !!room && !!currentUser && canManageMember(room, currentUser, member, 'banMembers'); } toggleRole(member: ServerMemberView, roleId: string, event: Event): void { const room = this.normalizedServer(); if (!room) return; const checkbox = event.target as HTMLInputElement; const nextRoleIds = checkbox.checked ? [...member.assignedRoleIds, roleId] : member.assignedRoleIds.filter((candidateRoleId) => candidateRoleId !== roleId); const roleAssignments = setRoleAssignmentsForMember(room.roleAssignments, member, nextRoleIds); this.store.dispatch(RoomsActions.updateRoomAccessControl({ roomId: room.id, changes: { roleAssignments } })); } kickMember(member: ServerMemberView): void { const room = this.normalizedServer(); if (!room) return; this.store.dispatch(UsersActions.kickUser({ userId: member.id, roomId: room.id })); } banMember(member: ServerMemberView): void { const room = this.normalizedServer(); if (!room) return; this.store.dispatch(UsersActions.banUser({ userId: member.id, roomId: room.id, displayName: member.displayName })); } }