Some checks failed
Deploy Web Apps / deploy (push) Successful in 5m52s
Build Android APK / build-android-apk (push) Failing after 23m15s
Queue Release Build / prepare (push) Successful in 1m42s
Queue Release Build / build-linux (push) Failing after 9m33s
Queue Release Build / build-windows (push) Successful in 26m5s
Queue Release Build / finalize (push) Has been skipped
167 lines
5.1 KiB
TypeScript
167 lines
5.1 KiB
TypeScript
/* eslint-disable @typescript-eslint/member-ordering */
|
|
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 {
|
|
private store = inject(Store);
|
|
private readonly i18n = inject(AppI18nService);
|
|
|
|
/** The currently selected server, passed from the parent. */
|
|
server = input<Room | null>(null);
|
|
/** Whether the current user is admin of this server. */
|
|
isAdmin = input(false);
|
|
accessRole = input<string | null>(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<RoomRole[]>(() => findAssignableRoles(this.normalizedServer()?.roles ?? []));
|
|
|
|
members = computed<ServerMemberView[]>(() => {
|
|
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')
|
|
};
|
|
});
|
|
});
|
|
|
|
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 }));
|
|
}
|
|
}
|