From f5c20a8d21ed74b6e46e59de88a900b6f9045ffe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?BENEDEK=20L=C3=A1szl=C3=B3?= Date: Sun, 8 Jun 2025 17:30:22 +0200 Subject: [PATCH] sidebar, user component --- src/app/chat/chat.module.ts | 4 +- .../channel-entry.component.scss | 4 +- .../channel-list/channel-list.component.scss | 3 - .../channel-list/channel-list.component.ts | 7 +- src/app/chat/chat/chat.component.html | 33 ++++-- src/app/chat/chat/chat.component.scss | 37 ++----- src/app/chat/chat/chat.component.ts | 3 + .../chat/feed/message/message.component.html | 2 +- .../chat/feed/message/message.component.scss | 5 + .../message-bar/message-bar.component.scss | 6 +- src/app/common/toolbar/toolbar.component.html | 22 ++-- src/app/common/toolbar/toolbar.component.scss | 20 +++- src/app/common/toolbar/toolbar.component.ts | 4 +- src/app/directives/back-button.directive.ts | 15 +++ src/app/services/auth.service.ts | 1 + src/app/user/user.module.ts | 23 +++- src/app/user/user/user.component.html | 103 +++++++++++++++++- src/app/user/user/user.component.scss | 54 +++++++++ src/app/user/user/user.component.ts | 76 ++++++++++++- src/styles.scss | 27 +++++ 20 files changed, 377 insertions(+), 72 deletions(-) create mode 100644 src/app/directives/back-button.directive.ts diff --git a/src/app/chat/chat.module.ts b/src/app/chat/chat.module.ts index fe4fc1e..b813f60 100644 --- a/src/app/chat/chat.module.ts +++ b/src/app/chat/chat.module.ts @@ -17,6 +17,7 @@ import { MessageBarComponent } from './chat/message-bar/message-bar.component'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; import { ReactiveFormsModule } from '@angular/forms'; +import { MatSidenavModule } from '@angular/material/sidenav'; @NgModule({ declarations: [ @@ -38,7 +39,8 @@ import { ReactiveFormsModule } from '@angular/forms'; MatIconModule, MatFormFieldModule, MatInputModule, - ReactiveFormsModule + ReactiveFormsModule, + MatSidenavModule ] }) export class ChatModule { } diff --git a/src/app/chat/chat/channel-list/channel-entry/channel-entry.component.scss b/src/app/chat/chat/channel-list/channel-entry/channel-entry.component.scss index 4fa2a70..4d3c914 100644 --- a/src/app/chat/chat/channel-list/channel-entry/channel-entry.component.scss +++ b/src/app/chat/chat/channel-list/channel-entry/channel-entry.component.scss @@ -1,5 +1,5 @@ button { - width: 95%; + min-width: 80%; display: block; - margin: 5px auto; + margin: 10px auto; } \ No newline at end of file diff --git a/src/app/chat/chat/channel-list/channel-list.component.scss b/src/app/chat/chat/channel-list/channel-list.component.scss index e7a6dca..e69de29 100644 --- a/src/app/chat/chat/channel-list/channel-list.component.scss +++ b/src/app/chat/chat/channel-list/channel-list.component.scss @@ -1,3 +0,0 @@ -:host { - background-color: var(--mat-sys-surface-container); -} \ No newline at end of file diff --git a/src/app/chat/chat/channel-list/channel-list.component.ts b/src/app/chat/chat/channel-list/channel-list.component.ts index 9f166bb..c6c7df1 100644 --- a/src/app/chat/chat/channel-list/channel-list.component.ts +++ b/src/app/chat/chat/channel-list/channel-list.component.ts @@ -10,12 +10,13 @@ import { ChannelEntryComponent } from './channel-entry/channel-entry.component'; }) export class ChannelListComponent { @Input('channels') public channels!: Channel[]; - @Output("select") selectEmitter: EventEmitter = new EventEmitter(); + @Output("select") public selectEmitter: EventEmitter = new EventEmitter(); + @Output('close') public close: EventEmitter = new EventEmitter(); @ViewChildren("entry") entries!: QueryList; private selectedChannel?: number; - public get SelectedChannel() : number { + public get SelectedChannel(): number { return this.selectedChannel ?? 0; } @@ -26,6 +27,6 @@ export class ChannelListComponent { } public Notify(channel: number): void { - this.entries.find(entry=>entry.channel.id == channel)?.Notify() + this.entries.find(entry => entry.channel.id == channel)?.Notify() } } diff --git a/src/app/chat/chat/chat.component.html b/src/app/chat/chat/chat.component.html index 4de38f6..4024057 100644 --- a/src/app/chat/chat/chat.component.html +++ b/src/app/chat/chat/chat.component.html @@ -1,11 +1,28 @@ -
- + - + + - -
\ No newline at end of file +

Channels

+ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/app/chat/chat/chat.component.scss b/src/app/chat/chat/chat.component.scss index 4ea2f6f..445eefc 100644 --- a/src/app/chat/chat/chat.component.scss +++ b/src/app/chat/chat/chat.component.scss @@ -1,35 +1,12 @@ -#container { +mat-drawer-container { + height: 100%; +} + +mat-drawer-content { height: 100%; display: grid; - grid-template-columns: 150px 1fr; - grid-template-rows: 65px 1fr auto; + grid-template-columns: 1fr; + grid-template-rows: auto 1fr auto; gap: 0px; - - app-toolbar { - grid-column: span 2 / span 2; - - } - - app-channel-list { - grid-row: span 2 / span 2; - grid-row-start: 2; - } - - app-feed { - grid-row-start: 2; - - border-left: 2px solid var(--mat-sys-surface-variant); - border-top: 2px solid var(--mat-sys-surface-variant); - border-radius: 10px 0 0 0; - - background-color: var(--mat-sys-background); - } - - app-message-bar { - grid-column-start: 2; - grid-row-start: 3; - - border-left: 2px solid var(--mat-sys-surface-variant); - } } \ No newline at end of file diff --git a/src/app/chat/chat/chat.component.ts b/src/app/chat/chat/chat.component.ts index b4a669f..f985878 100644 --- a/src/app/chat/chat/chat.component.ts +++ b/src/app/chat/chat/chat.component.ts @@ -5,6 +5,7 @@ import { ChatService } from '../../services/chat.service'; import { ToastrService } from 'ngx-toastr'; import { FeedComponent } from './feed/feed.component'; import { ChannelListComponent } from './channel-list/channel-list.component'; +import { MatDrawer } from '@angular/material/sidenav'; @Component({ selector: 'app-chat', @@ -16,6 +17,7 @@ export class ChatComponent implements OnInit { public selectedChannel: number = 0; public channels: { channel: Channel, messages: Message[] }[] = []; + @ViewChild("drawer") drawer!: MatDrawer; @ViewChild("feed") feed!: FeedComponent; @ViewChild("channelList") channelList!: ChannelListComponent; @@ -59,5 +61,6 @@ export class ChatComponent implements OnInit { public Select(channel: number): void { this.selectedChannel = channel; this.feed.ScrollEventHandler(); + this.drawer.close(); } } diff --git a/src/app/chat/chat/feed/message/message.component.html b/src/app/chat/chat/feed/message/message.component.html index 8d3a5db..a99d9c9 100644 --- a/src/app/chat/chat/feed/message/message.component.html +++ b/src/app/chat/chat/feed/message/message.component.html @@ -2,7 +2,7 @@
-
{{this.message.sender_name}}
+
{{this.message.content}}
diff --git a/src/app/chat/chat/feed/message/message.component.scss b/src/app/chat/chat/feed/message/message.component.scss index fae8a42..4ee43da 100644 --- a/src/app/chat/chat/feed/message/message.component.scss +++ b/src/app/chat/chat/feed/message/message.component.scss @@ -32,4 +32,9 @@ app-profile-picture { height: fit-content; } } +} + +a { + text-decoration: none; + color: inherit; } \ No newline at end of file diff --git a/src/app/chat/chat/message-bar/message-bar.component.scss b/src/app/chat/chat/message-bar/message-bar.component.scss index 282de69..bce7f9b 100644 --- a/src/app/chat/chat/message-bar/message-bar.component.scss +++ b/src/app/chat/chat/message-bar/message-bar.component.scss @@ -1,9 +1,11 @@ +:host { + background-color: var(--mat-sys-surface-container); +} + form { align-items: center; - padding: 10px; - display: grid; grid-template-columns: 1fr auto; diff --git a/src/app/common/toolbar/toolbar.component.html b/src/app/common/toolbar/toolbar.component.html index 8c788a4..274cb09 100644 --- a/src/app/common/toolbar/toolbar.component.html +++ b/src/app/common/toolbar/toolbar.component.html @@ -1,18 +1,20 @@ - - chatChat -
- + + + - + + + \ No newline at end of file diff --git a/src/app/common/toolbar/toolbar.component.scss b/src/app/common/toolbar/toolbar.component.scss index 9d8ba15..45d1548 100644 --- a/src/app/common/toolbar/toolbar.component.scss +++ b/src/app/common/toolbar/toolbar.component.scss @@ -2,10 +2,20 @@ mat-toolbar { background-color: var(--mat-sys-surface-container); } -.toolbar-right-side { - width: 100%; - - button { - float: right; +#sidebar-button { + mat-icon { + width: fit-content; + margin: auto; + padding: 0; } +} + +#logo { + display: block; + margin: auto; + width: fit-content; +} + +button { + float: right; } \ No newline at end of file diff --git a/src/app/common/toolbar/toolbar.component.ts b/src/app/common/toolbar/toolbar.component.ts index c6cb5c0..e13d81f 100644 --- a/src/app/common/toolbar/toolbar.component.ts +++ b/src/app/common/toolbar/toolbar.component.ts @@ -1,4 +1,4 @@ -import { Component } from '@angular/core'; +import { Component, EventEmitter, Input, Output } from '@angular/core'; import { MatToolbarModule } from '@angular/material/toolbar'; import { MatIconModule } from '@angular/material/icon'; import { MatButtonModule } from '@angular/material/button'; @@ -14,6 +14,8 @@ import { NgIf } from '@angular/common'; styleUrl: './toolbar.component.scss' }) export class ToolbarComponent { + @Output('sidebar') sidebar: EventEmitter = new EventEmitter(); + constructor( public authService: AuthService, private toastrService: ToastrService, diff --git a/src/app/directives/back-button.directive.ts b/src/app/directives/back-button.directive.ts new file mode 100644 index 0000000..69dff12 --- /dev/null +++ b/src/app/directives/back-button.directive.ts @@ -0,0 +1,15 @@ +import { Directive, HostListener } from '@angular/core'; + +@Directive({ + selector: '[back-button]' +}) +export class BackButtonDirective { + + constructor() { } + + @HostListener('click') + onClick(): void { + window.history.back(); + } + +} diff --git a/src/app/services/auth.service.ts b/src/app/services/auth.service.ts index 1c3c588..9249454 100644 --- a/src/app/services/auth.service.ts +++ b/src/app/services/auth.service.ts @@ -46,6 +46,7 @@ export class AuthService { let url = `${environment.apiBase}/auth/logout`; localStorage.removeItem(this.LOCAL_USERNAME); + this.loggedIn = false; return this.http.get(url, { withCredentials: true }).pipe( map(() => true), diff --git a/src/app/user/user.module.ts b/src/app/user/user.module.ts index 50fdd5a..a2d7092 100644 --- a/src/app/user/user.module.ts +++ b/src/app/user/user.module.ts @@ -3,7 +3,16 @@ import { CommonModule } from '@angular/common'; import { UserRoutingModule } from './user-routing.module'; import { UserComponent } from './user/user.component'; - +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatInputModule } from '@angular/material/input'; +import { MatIconModule } from '@angular/material/icon'; +import { MatButtonModule } from '@angular/material/button'; +import { MatSidenavModule } from '@angular/material/sidenav'; +import { MatCardModule } from '@angular/material/card'; +import { ReactiveFormsModule } from '@angular/forms'; +import { ToolbarComponent } from "../common/toolbar/toolbar.component"; +import { BackButtonDirective } from '../directives/back-button.directive'; +import { MatDividerModule } from '@angular/material/divider'; @NgModule({ declarations: [ @@ -11,7 +20,17 @@ import { UserComponent } from './user/user.component'; ], imports: [ CommonModule, - UserRoutingModule + UserRoutingModule, + MatFormFieldModule, + MatInputModule, + MatIconModule, + MatButtonModule, + MatSidenavModule, + MatCardModule, + ReactiveFormsModule, + ToolbarComponent, + BackButtonDirective, + MatDividerModule ] }) export class UserModule { } diff --git a/src/app/user/user/user.component.html b/src/app/user/user/user.component.html index 6b2f937..25e65f4 100644 --- a/src/app/user/user/user.component.html +++ b/src/app/user/user/user.component.html @@ -1 +1,102 @@ -

{{username}}

+ + + + + +

Options

+ + + +
+ + + + + + + + + +

{{'@'}}{{this.user?.username}}

+ +

Status

+

{{this.user?.status}}

+ +

Bio

+

{{this.user?.bio}}

+ +
+ + + + + +

{{'@'}}{{this.user?.username}}

+ +
+

Change password

+ + + New password + + + + + Repeat new password + + + + + Current password + + + + + +
+ + + +
+

Change status

+ + + Status + + + + + +
+ + + +
+

Change bio

+ + + Bio + + + + + +
+ +
+ +
+ +
\ No newline at end of file diff --git a/src/app/user/user/user.component.scss b/src/app/user/user/user.component.scss index e69de29..fbd3b7b 100644 --- a/src/app/user/user/user.component.scss +++ b/src/app/user/user/user.component.scss @@ -0,0 +1,54 @@ +mat-drawer-container { + height: 100%; + + mat-drawer-content { + overflow-y: scroll; + } +} + +.option { + min-width: 80%; + display: block; + margin: 10px auto; +} + +mat-card { + margin: 30px auto; + max-width: 70%; + padding: 20px; + + img { + width: 30%; + aspect-ratio: 1; + border-radius: 50%; + border: 2px solid var(--mat-sys-on-surface); + margin: 10px auto; + + text-align: center; + } + + h1 { + margin: auto; + } + + p { + margin: 0 30px; + } +} + +#edit-card { + form { + padding: 10px; + margin: 0; + + * { + width: 100%; + } + + button { + display: block; + margin: 10px auto; + width: fit-content; + } + } +} \ No newline at end of file diff --git a/src/app/user/user/user.component.ts b/src/app/user/user/user.component.ts index 0f0b0f2..e01621f 100644 --- a/src/app/user/user/user.component.ts +++ b/src/app/user/user/user.component.ts @@ -1,5 +1,11 @@ -import { Component } from '@angular/core'; +import { Component, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; +import { User } from '../../models/user'; +import { UserService } from '../../services/user.service'; +import { ToastrService } from 'ngx-toastr'; +import { Subscription } from 'rxjs'; +import { AuthService } from '../../services/auth.service'; +import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; @Component({ selector: 'app-user', @@ -7,12 +13,76 @@ import { ActivatedRoute } from '@angular/router'; templateUrl: './user.component.html', styleUrl: './user.component.scss' }) -export class UserComponent { +export class UserComponent implements OnInit, OnDestroy { public username!: string; + public user?: User; - constructor(private route: ActivatedRoute) { + private sub?: Subscription; + + public passwordForm!: FormGroup; + public statusForm!: FormGroup; + public bioForm!: FormGroup; + + constructor( + private route: ActivatedRoute, + private userService: UserService, + public authService: AuthService, + private toastrService: ToastrService, + private formBuilder: FormBuilder) { this.route.paramMap.subscribe(params => { this.username = params.get('username')!; }); } + + ngOnInit(): void { + this.passwordForm = this.formBuilder.group({ + newPassword: new FormControl('', [ + Validators.required, + Validators.minLength(6), + Validators.maxLength(32) + ]), + repeatNewPassword: new FormControl('', [ + Validators.required, + Validators.minLength(6), + Validators.maxLength(32) + ]), + password: new FormControl('', [ + Validators.required + ]) + }); + + this.statusForm = this.formBuilder.group({ + status: new FormControl('', [ + Validators.required, + Validators.minLength(0), + Validators.maxLength(200) + ]), + }); + + this.bioForm = this.formBuilder.group({ + bio: new FormControl('', [ + Validators.required, + Validators.minLength(0), + Validators.maxLength(300) + ]), + }); + + this.sub = this.userService.GetUser(this.username) + .subscribe({ + next: user => { + this.user = user; + this.statusForm.setValue({ "status": user.status }); + this.bioForm.setValue({ "bio": user.bio }); + }, + error: () => this.toastrService.error("Failed to fectch user info.", "Error"), + }); + } + + ngOnDestroy(): void { + this.sub?.unsubscribe(); + } + + public ChangePassword(): void { } + public ChangeStatus(): void { } + public ChangeBio(): void { } } diff --git a/src/styles.scss b/src/styles.scss index 2d6b8c0..b394c26 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -21,4 +21,31 @@ body { .force-dark-mode { color-scheme: dark !important; +} + +h1, +h2, +h3, +h4 { + margin: 30px 30px 10px; + width: fit-content; +} + +#logo { + margin-top: 30px; + + h1 { + display: inline; + } + + button { + float: right; + margin-right: 10px; + + mat-icon { + width: fit-content; + margin: auto; + padding: 0; + } + } } \ No newline at end of file