161 lines
4.4 KiB
TypeScript
161 lines
4.4 KiB
TypeScript
import { Component, inject, signal } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { FormsModule } from '@angular/forms';
|
|
import { Store } from '@ngrx/store';
|
|
import { NgIcon, provideIcons } from '@ng-icons/core';
|
|
import {
|
|
lucideShield,
|
|
lucideBan,
|
|
lucideUserX,
|
|
lucideSettings,
|
|
lucideUsers,
|
|
lucideTrash2,
|
|
lucideCheck,
|
|
lucideX,
|
|
lucideLock,
|
|
lucideUnlock,
|
|
} from '@ng-icons/lucide';
|
|
|
|
import * as UsersActions from '../../../store/users/users.actions';
|
|
import * as RoomsActions from '../../../store/rooms/rooms.actions';
|
|
import { selectCurrentRoom } from '../../../store/rooms/rooms.selectors';
|
|
import {
|
|
selectBannedUsers,
|
|
selectIsCurrentUserAdmin,
|
|
selectCurrentUser,
|
|
} from '../../../store/users/users.selectors';
|
|
import { BanEntry, Room } from '../../../core/models';
|
|
|
|
type AdminTab = 'settings' | 'bans' | 'permissions';
|
|
|
|
@Component({
|
|
selector: 'app-admin-panel',
|
|
standalone: true,
|
|
imports: [CommonModule, FormsModule, NgIcon],
|
|
viewProviders: [
|
|
provideIcons({
|
|
lucideShield,
|
|
lucideBan,
|
|
lucideUserX,
|
|
lucideSettings,
|
|
lucideUsers,
|
|
lucideTrash2,
|
|
lucideCheck,
|
|
lucideX,
|
|
lucideLock,
|
|
lucideUnlock,
|
|
}),
|
|
],
|
|
templateUrl: './admin-panel.component.html',
|
|
})
|
|
export class AdminPanelComponent {
|
|
private store = inject(Store);
|
|
|
|
currentRoom = this.store.selectSignal(selectCurrentRoom);
|
|
currentUser = this.store.selectSignal(selectCurrentUser);
|
|
isAdmin = this.store.selectSignal(selectIsCurrentUserAdmin);
|
|
bannedUsers = this.store.selectSignal(selectBannedUsers);
|
|
|
|
activeTab = signal<AdminTab>('settings');
|
|
showDeleteConfirm = signal(false);
|
|
|
|
// Settings
|
|
roomName = '';
|
|
roomDescription = '';
|
|
isPrivate = signal(false);
|
|
maxUsers = 0;
|
|
|
|
// Permissions
|
|
allowVoice = true;
|
|
allowScreenShare = true;
|
|
allowFileUploads = true;
|
|
slowModeInterval = '0';
|
|
adminsManageRooms = false;
|
|
moderatorsManageRooms = false;
|
|
adminsManageIcon = false;
|
|
moderatorsManageIcon = false;
|
|
|
|
constructor() {
|
|
// Initialize from current room
|
|
const room = this.currentRoom();
|
|
if (room) {
|
|
this.roomName = room.name;
|
|
this.roomDescription = room.description || '';
|
|
this.isPrivate.set(room.isPrivate);
|
|
this.maxUsers = room.maxUsers || 0;
|
|
const perms = room.permissions || {};
|
|
this.allowVoice = perms.allowVoice !== false;
|
|
this.allowScreenShare = perms.allowScreenShare !== false;
|
|
this.allowFileUploads = perms.allowFileUploads !== false;
|
|
this.slowModeInterval = String(perms.slowModeInterval ?? 0);
|
|
this.adminsManageRooms = !!perms.adminsManageRooms;
|
|
this.moderatorsManageRooms = !!perms.moderatorsManageRooms;
|
|
this.adminsManageIcon = !!perms.adminsManageIcon;
|
|
this.moderatorsManageIcon = !!perms.moderatorsManageIcon;
|
|
}
|
|
}
|
|
|
|
togglePrivate(): void {
|
|
this.isPrivate.update((v) => !v);
|
|
}
|
|
|
|
saveSettings(): void {
|
|
const room = this.currentRoom();
|
|
if (!room) return;
|
|
|
|
this.store.dispatch(
|
|
RoomsActions.updateRoom({
|
|
roomId: room.id,
|
|
changes: {
|
|
name: this.roomName,
|
|
description: this.roomDescription,
|
|
isPrivate: this.isPrivate(),
|
|
maxUsers: this.maxUsers,
|
|
},
|
|
})
|
|
);
|
|
}
|
|
|
|
savePermissions(): void {
|
|
const room = this.currentRoom();
|
|
if (!room) return;
|
|
|
|
this.store.dispatch(
|
|
RoomsActions.updateRoomPermissions({
|
|
roomId: room.id,
|
|
permissions: {
|
|
allowVoice: this.allowVoice,
|
|
allowScreenShare: this.allowScreenShare,
|
|
allowFileUploads: this.allowFileUploads,
|
|
slowModeInterval: parseInt(this.slowModeInterval, 10),
|
|
adminsManageRooms: this.adminsManageRooms,
|
|
moderatorsManageRooms: this.moderatorsManageRooms,
|
|
adminsManageIcon: this.adminsManageIcon,
|
|
moderatorsManageIcon: this.moderatorsManageIcon,
|
|
},
|
|
})
|
|
);
|
|
}
|
|
|
|
unbanUser(ban: BanEntry): void {
|
|
this.store.dispatch(UsersActions.unbanUser({ oderId: ban.oderId }));
|
|
}
|
|
|
|
confirmDeleteRoom(): void {
|
|
this.showDeleteConfirm.set(true);
|
|
}
|
|
|
|
deleteRoom(): void {
|
|
const room = this.currentRoom();
|
|
if (!room) return;
|
|
|
|
this.store.dispatch(RoomsActions.deleteRoom({ roomId: room.id }));
|
|
this.showDeleteConfirm.set(false);
|
|
}
|
|
|
|
formatExpiry(timestamp: number): string {
|
|
const date = new Date(timestamp);
|
|
return date.toLocaleDateString() + ' ' + date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
|
}
|
|
}
|