95 lines
3.8 KiB
TypeScript
95 lines
3.8 KiB
TypeScript
import { Component, inject, 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 { NgIcon, provideIcons } from '@ng-icons/core';
|
|
import { lucideLogIn } from '@ng-icons/lucide';
|
|
|
|
import { AuthService } from '../../core/services/auth.service';
|
|
import { ServerDirectoryService } from '../../core/services/server-directory.service';
|
|
import * as UsersActions from '../../store/users/users.actions';
|
|
import { User } from '../../core/models';
|
|
|
|
@Component({
|
|
selector: 'app-login',
|
|
standalone: true,
|
|
imports: [CommonModule, FormsModule, NgIcon],
|
|
viewProviders: [provideIcons({ lucideLogIn })],
|
|
template: `
|
|
<div class="h-full grid place-items-center bg-background">
|
|
<div class="w-[360px] bg-card border border-border rounded-xl p-6 shadow-sm">
|
|
<div class="flex items-center gap-2 mb-4">
|
|
<ng-icon name="lucideLogIn" class="w-5 h-5 text-primary" />
|
|
<h1 class="text-lg font-semibold text-foreground">Login</h1>
|
|
</div>
|
|
|
|
<div class="space-y-3">
|
|
<div>
|
|
<label class="block text-xs text-muted-foreground mb-1">Username</label>
|
|
<input [(ngModel)]="username" type="text" class="w-full px-3 py-2 rounded border border-border bg-secondary text-foreground" />
|
|
</div>
|
|
<div>
|
|
<label class="block text-xs text-muted-foreground mb-1">Password</label>
|
|
<input [(ngModel)]="password" type="password" class="w-full px-3 py-2 rounded border border-border bg-secondary text-foreground" />
|
|
</div>
|
|
<div>
|
|
<label class="block text-xs text-muted-foreground mb-1">Server App</label>
|
|
<select [(ngModel)]="serverId" class="w-full px-3 py-2 rounded border border-border bg-secondary text-foreground">
|
|
<option *ngFor="let s of servers(); trackBy: trackById" [value]="s.id">{{ s.name }}</option>
|
|
</select>
|
|
</div>
|
|
<p *ngIf="error()" class="text-xs text-destructive">{{ error() }}</p>
|
|
<button (click)="submit()" class="w-full px-3 py-2 rounded bg-primary text-primary-foreground hover:bg-primary/90">Login</button>
|
|
<div class="text-xs text-muted-foreground text-center mt-2">
|
|
No account? <a class="text-primary hover:underline" (click)="goRegister()">Register</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`,
|
|
})
|
|
export class LoginComponent {
|
|
private auth = inject(AuthService);
|
|
private serversSvc = inject(ServerDirectoryService);
|
|
private store = inject(Store);
|
|
private router = inject(Router);
|
|
|
|
servers = this.serversSvc.servers;
|
|
username = '';
|
|
password = '';
|
|
serverId: string | undefined = this.serversSvc.activeServer()?.id;
|
|
error = signal<string | null>(null);
|
|
|
|
trackById(_index: number, item: { id: string }) { return item.id; }
|
|
|
|
submit() {
|
|
this.error.set(null);
|
|
const sid = this.serverId || this.serversSvc.activeServer()?.id;
|
|
this.auth.login({ username: this.username.trim(), password: this.password, serverId: sid }).subscribe({
|
|
next: (resp) => {
|
|
if (sid) this.serversSvc.setActiveServer(sid);
|
|
const user: User = {
|
|
id: resp.id,
|
|
oderId: resp.id,
|
|
username: resp.username,
|
|
displayName: resp.displayName,
|
|
status: 'online',
|
|
role: 'member',
|
|
joinedAt: Date.now(),
|
|
};
|
|
try { localStorage.setItem('metoyou_currentUserId', resp.id); } catch {}
|
|
this.store.dispatch(UsersActions.setCurrentUser({ user }));
|
|
this.router.navigate(['/search']);
|
|
},
|
|
error: (err) => {
|
|
this.error.set(err?.error?.error || 'Login failed');
|
|
},
|
|
});
|
|
}
|
|
|
|
goRegister() {
|
|
this.router.navigate(['/register']);
|
|
}
|
|
}
|