channel list

This commit is contained in:
BENEDEK László 2025-06-03 12:53:45 +02:00
parent 9729d8a253
commit 9981c634ea
18 changed files with 178 additions and 4 deletions

View File

@ -1,10 +1,16 @@
import { Routes } from '@angular/router';
import { IsLoggedInCanActivate } from './services/auth.service';
export const routes: Routes = [
{
path: 'auth',
loadChildren: () => import('./auth/auth.module').then(m => m.AuthModule)
},
{
path: 'chat',
loadChildren: () => import('./chat/chat.module').then(m => m.ChatModule),
canActivate: [IsLoggedInCanActivate]
},
{ path: '', redirectTo: 'auth', pathMatch: 'full' },
{ path: '**', redirectTo: '/', pathMatch: 'full' }
{ path: '**/*', redirectTo: '', pathMatch: 'full' }
];

View File

@ -44,7 +44,7 @@ export class LoginComponent implements OnInit {
timeOut: 3000,
closeButton: true
});
this.router.navigateByUrl('/feed');
this.router.navigateByUrl('chat');
}
},
error: _ => {

View File

@ -0,0 +1,13 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { ChatComponent } from './chat/chat.component';
const routes: Routes = [
{ path: '', component: ChatComponent },
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class ChatRoutingModule { }

View File

@ -0,0 +1,23 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ChatRoutingModule } from './chat-routing.module';
import { ChatComponent } from './chat/chat.component';
import { ChannelListComponent } from './chat/channel-list/channel-list.component';
import { FeedComponent } from './chat/feed/feed.component';
import { ChannelEntryComponent } from './chat/channel-list/channel-entry/channel-entry.component';
@NgModule({
declarations: [
ChatComponent,
ChannelListComponent,
FeedComponent,
ChannelEntryComponent
],
imports: [
CommonModule,
ChatRoutingModule
]
})
export class ChatModule { }

View File

@ -0,0 +1 @@
<div [title]="channel.description" [class.selected]="selected">{{channel.name}}</div>

View File

@ -0,0 +1,10 @@
div {
padding: 5px 10px;
cursor: pointer;
}
.selected {
color: var(--mat-sys-on-secondary);
background-color: var(--mat-sys-secondary);
transition: all .3s ease-in-out;
}

View File

@ -0,0 +1,13 @@
import { Component, Input } from '@angular/core';
import { Channel } from '../../../../models/channel';
@Component({
selector: 'app-channel-entry',
standalone: false,
templateUrl: './channel-entry.component.html',
styleUrl: './channel-entry.component.scss'
})
export class ChannelEntryComponent {
@Input("channel") public channel!: Channel;
@Input("selected") public selected!: boolean;
}

View File

@ -0,0 +1,6 @@
<app-channel-entry
*ngFor="let channel of this.channels; let i = index"
[channel]="channels[i]"
(click)="Select(i)"
[selected]="channels[i].id == selectedChannel.id"
/>

View File

@ -0,0 +1,4 @@
:host {
color: var(--mat-sys-on-surface);
background-color: var(--mat-sys-surface);
}

View File

@ -0,0 +1,39 @@
import { Component, EventEmitter, OnInit, Output } from '@angular/core';
import { Channel } from '../../../models/channel';
@Component({
selector: 'app-channel-list',
standalone: false,
templateUrl: './channel-list.component.html',
styleUrl: './channel-list.component.scss'
})
export class ChannelListComponent implements OnInit {
@Output("select") selectEmitter: EventEmitter<Channel> = new EventEmitter<Channel>();
public channels: Channel[] = [
{
id: 0,
name: 'default',
description: 'this is the default channel'
},
{
id: 1,
name: 'gaming',
description: 'this is another channel'
},
];
public selectedChannel!: Channel;
constructor() { }
ngOnInit() {
// TODO: query list of channels
this.selectedChannel = this.channels[0];
}
public Select(index: number): void {
this.selectEmitter.emit(this.selectedChannel = this.channels[index]);
}
}

View File

@ -0,0 +1,4 @@
<div id="container">
<app-channel-list (select)="Select($event)"></app-channel-list>
<app-feed></app-feed>
</div>

View File

@ -0,0 +1,5 @@
#container {
display: grid;
grid-template-columns: minmax(auto, 200px) 1fr;
height: 100%;
}

View File

@ -0,0 +1,14 @@
import { Component } from '@angular/core';
import { Channel } from '../../models/channel';
@Component({
selector: 'app-chat',
standalone: false,
templateUrl: './chat.component.html',
styleUrl: './chat.component.scss'
})
export class ChatComponent {
public Select(channel: Channel): void {
// TODO: update feed
}
}

View File

@ -0,0 +1 @@
<p>feed works!</p>

View File

@ -0,0 +1,11 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-feed',
standalone: false,
templateUrl: './feed.component.html',
styleUrl: './feed.component.scss'
})
export class FeedComponent {
}

View File

@ -0,0 +1,5 @@
export class Channel {
public id!: number;
public name!: string;
public description!: string;
}

View File

@ -1,7 +1,8 @@
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { inject, Injectable } from '@angular/core';
import { catchError, map, Observable, of } from 'rxjs';
import { LoginResponse, RegisterResponse } from './responses/auth';
import { ActivatedRouteSnapshot, CanActivateFn, RouterStateSnapshot } from '@angular/router';
@Injectable({
providedIn: 'root'
@ -9,6 +10,7 @@ import { LoginResponse, RegisterResponse } from './responses/auth';
export class AuthService {
private readonly API_BASE: string = "http://localhost:5000"
private readonly SESSION_COOKIE: string = "session";
private readonly USERNAME_FIELD: string = "username";
private readonly PASSWORD_FIELD: string = "password";
private readonly REPEAT_PASSWORD_FIELD: string = "repeatPassword";
@ -53,4 +55,21 @@ export class AuthService {
catchError(() => of(false))
);
}
public IsLoggedIn(): boolean {
let cookies = document.cookie.split(';');
let found = false;
cookies.forEach(cookie => {
cookie = cookie.trim();
found = found || cookie.startsWith(this.SESSION_COOKIE + "=") && cookie.split('=', 2)[1] != '';
});
return found;
}
}
export const IsLoggedInCanActivate: CanActivateFn = (
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
) => {
return inject(AuthService).IsLoggedIn();
}