183 lines
4.9 KiB
TypeScript
183 lines
4.9 KiB
TypeScript
/* eslint-disable @typescript-eslint/member-ordering */
|
|
import {
|
|
Component,
|
|
inject,
|
|
OnInit,
|
|
signal
|
|
} from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { FormsModule } from '@angular/forms';
|
|
import { Router } from '@angular/router';
|
|
import { Store } from '@ngrx/store';
|
|
import {
|
|
debounceTime,
|
|
distinctUntilChanged,
|
|
Subject
|
|
} from 'rxjs';
|
|
import { NgIcon, provideIcons } from '@ng-icons/core';
|
|
import {
|
|
lucideSearch,
|
|
lucideUsers,
|
|
lucideLock,
|
|
lucideGlobe,
|
|
lucidePlus,
|
|
lucideSettings
|
|
} from '@ng-icons/lucide';
|
|
|
|
import { RoomsActions } from '../../store/rooms/rooms.actions';
|
|
import {
|
|
selectSearchResults,
|
|
selectIsSearching,
|
|
selectRoomsError,
|
|
selectSavedRooms
|
|
} from '../../store/rooms/rooms.selectors';
|
|
import { Room } from '../../core/models';
|
|
import { ServerInfo } from '../../core/models';
|
|
import { SettingsModalService } from '../../core/services/settings-modal.service';
|
|
|
|
@Component({
|
|
selector: 'app-server-search',
|
|
standalone: true,
|
|
imports: [CommonModule, FormsModule, NgIcon],
|
|
viewProviders: [
|
|
provideIcons({
|
|
lucideSearch,
|
|
lucideUsers,
|
|
lucideLock,
|
|
lucideGlobe,
|
|
lucidePlus,
|
|
lucideSettings
|
|
})
|
|
],
|
|
templateUrl: './server-search.component.html'
|
|
})
|
|
/**
|
|
* Server search and discovery view with server creation dialog.
|
|
* Allows users to search for, join, and create new servers.
|
|
*/
|
|
export class ServerSearchComponent implements OnInit {
|
|
private store = inject(Store);
|
|
private router = inject(Router);
|
|
private settingsModal = inject(SettingsModalService);
|
|
private searchSubject = new Subject<string>();
|
|
|
|
searchQuery = '';
|
|
searchResults = this.store.selectSignal(selectSearchResults);
|
|
isSearching = this.store.selectSignal(selectIsSearching);
|
|
error = this.store.selectSignal(selectRoomsError);
|
|
savedRooms = this.store.selectSignal(selectSavedRooms);
|
|
|
|
// Create dialog state
|
|
showCreateDialog = signal(false);
|
|
newServerName = signal('');
|
|
newServerDescription = signal('');
|
|
newServerTopic = signal('');
|
|
newServerPrivate = signal(false);
|
|
newServerPassword = signal('');
|
|
|
|
/** Initialize server search, load saved rooms, and set up debounced search. */
|
|
ngOnInit(): void {
|
|
// Initial load
|
|
this.store.dispatch(RoomsActions.searchServers({ query: '' }));
|
|
this.store.dispatch(RoomsActions.loadRooms());
|
|
|
|
// Setup debounced search
|
|
this.searchSubject.pipe(debounceTime(300), distinctUntilChanged()).subscribe((query) => {
|
|
this.store.dispatch(RoomsActions.searchServers({ query }));
|
|
});
|
|
}
|
|
|
|
/** Emit a search query to the debounced search subject. */
|
|
onSearchChange(query: string): void {
|
|
this.searchSubject.next(query);
|
|
}
|
|
|
|
/** Join a server from the search results. Redirects to login if unauthenticated. */
|
|
joinServer(server: ServerInfo): void {
|
|
const currentUserId = localStorage.getItem('metoyou_currentUserId');
|
|
|
|
if (!currentUserId) {
|
|
this.router.navigate(['/login']);
|
|
return;
|
|
}
|
|
|
|
this.store.dispatch(
|
|
RoomsActions.joinRoom({
|
|
roomId: server.id,
|
|
serverInfo: {
|
|
name: server.name,
|
|
description: server.description,
|
|
hostName: server.hostName
|
|
}
|
|
})
|
|
);
|
|
}
|
|
|
|
/** Open the create-server dialog. */
|
|
openCreateDialog(): void {
|
|
this.showCreateDialog.set(true);
|
|
}
|
|
|
|
/** Close the create-server dialog and reset the form. */
|
|
closeCreateDialog(): void {
|
|
this.showCreateDialog.set(false);
|
|
this.resetCreateForm();
|
|
}
|
|
|
|
/** Submit the new server creation form and dispatch the create action. */
|
|
createServer(): void {
|
|
if (!this.newServerName())
|
|
return;
|
|
|
|
const currentUserId = localStorage.getItem('metoyou_currentUserId');
|
|
|
|
if (!currentUserId) {
|
|
this.router.navigate(['/login']);
|
|
return;
|
|
}
|
|
|
|
this.store.dispatch(
|
|
RoomsActions.createRoom({
|
|
name: this.newServerName(),
|
|
description: this.newServerDescription() || undefined,
|
|
topic: this.newServerTopic() || undefined,
|
|
isPrivate: this.newServerPrivate(),
|
|
password: this.newServerPrivate() ? this.newServerPassword() : undefined
|
|
})
|
|
);
|
|
|
|
this.closeCreateDialog();
|
|
}
|
|
|
|
/** Open the unified settings modal to the Network page. */
|
|
openSettings(): void {
|
|
this.settingsModal.open('network');
|
|
}
|
|
|
|
/** Join a previously saved room by converting it to a ServerInfo payload. */
|
|
joinSavedRoom(room: Room): void {
|
|
this.joinServer(this.toServerInfo(room));
|
|
}
|
|
|
|
private toServerInfo(room: Room): ServerInfo {
|
|
return {
|
|
id: room.id,
|
|
name: room.name,
|
|
description: room.description,
|
|
hostName: room.hostId || 'Unknown',
|
|
userCount: room.userCount,
|
|
maxUsers: room.maxUsers ?? 50,
|
|
isPrivate: !!room.password,
|
|
createdAt: room.createdAt
|
|
};
|
|
}
|
|
|
|
private resetCreateForm(): void {
|
|
this.newServerName.set('');
|
|
this.newServerDescription.set('');
|
|
this.newServerTopic.set('');
|
|
this.newServerPrivate.set(false);
|
|
this.newServerPassword.set('');
|
|
}
|
|
}
|