Skip to content

Commit

Permalink
Merge pull request #210 from dancier/feature/improve-chat
Browse files Browse the repository at this point in the history
improve UI of chat, fix most bugs by loading chat data only when the …
  • Loading branch information
halbekanne authored Dec 18, 2023
2 parents 7866f17 + c2b4a63 commit 9c7083a
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 16 deletions.
12 changes: 8 additions & 4 deletions src/app/chat/data-access/chat-state.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { chatStateAdapter } from './chat-state.adapter';
import { TimerService } from '@shared/util/time/timer.service';
import { startWith } from 'rxjs/operators';
import { ActivatedRoute } from '@angular/router';
import { AuthStorageService } from '@shared/data-access/auth/auth-storage.service';

export type SingleChatState = {
id: string;
Expand All @@ -27,13 +28,15 @@ export type ChatAdaptState = {
newMessageSent: boolean;
};

@Injectable({
providedIn: 'root',
})
@Injectable()
export class ChatStateService {
private readonly storePath = 'chat';
private activatedRoute = inject(ActivatedRoute);
private authStorageService = inject(AuthStorageService);

private userLoggedOut$ = this.authStorageService.hasLoggedOut$.pipe(
toSource('[Chat] userLoggedOut')
);
// either we have a chat open with that DancerId or we create a new one
// TODO: logic can possibly be simplified when we do this only after the initial fetch
openChatWith$ = this.activatedRoute.queryParams.pipe(
Expand Down Expand Up @@ -71,7 +74,7 @@ export class ChatStateService {
const fetchChatsSources = getRequestSources(
'[Chat] fetchChats',
merge(
timerService.interval('chatFetchTrigger', 5000),
timerService.interval('chatFetchTrigger', 20000),
store.chatCreated$.pipe(filter((hasCreated) => !!hasCreated))
).pipe(
startWith(-1),
Expand Down Expand Up @@ -158,6 +161,7 @@ export class ChatStateService {
chatCreatedError: createChatSource.error$,
messageSent: sendMessageSource.success$,
messageSentError: sendMessageSource.error$,
reset: this.userLoggedOut$,
};
}
);
Expand Down
15 changes: 11 additions & 4 deletions src/app/chat/feature/chat-page/chat-page.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ import { ChatConversationListComponent } from '../../ui/conversation-list/chat-c
import { AsyncPipe, NgFor, NgIf } from '@angular/common';
import { ChatStateService } from '../../data-access/chat-state.service';
import { ChatConversationHeaderComponent } from '../../ui/chat-conversation-header.component';
import { interval, take } from 'rxjs';

@Component({
selector: 'app-chat-page',
template: `<!-- eslint-disable @angular-eslint/template/cyclomatic-complexity -->
<div class="m-10">
<div class="mx-auto my-12 max-w-[1200px] px-4 md:px-10">
<h1 class="page-header">Deine Chats</h1>
<ng-container *ngIf="chatState.chatsFetchState() === 'loaded'">
Expand All @@ -21,7 +22,7 @@ import { ChatConversationHeaderComponent } from '../../ui/chat-conversation-head
>
<div class="flex h-[600px] border">
<app-chat-conversation-list
class="min-w-[300px] overflow-y-auto max-md:flex-1 md:flex-none"
class="min-w-[300px] overflow-y-auto border-r border-gray-300 py-2 max-md:flex-1 md:flex-none"
[class.max-md:hidden]="chatState.activeChatId() !== null"
></app-chat-conversation-list>
<div
Expand Down Expand Up @@ -66,7 +67,12 @@ import { ChatConversationHeaderComponent } from '../../ui/chat-conversation-head
</app-alert>
</ng-container>
<ng-container *ngIf="chatState.chatsFetchState() === 'loading'">
<ng-container
*ngIf="
(delayLoading$ | async) === 0 &&
chatState.chatsFetchState() === 'loading'
"
>
<div class="flex rounded border bg-gray-100">
<div class="w-[300px] flex-col">
<div *ngFor="let _ of [].constructor(4)" class="flex items-center">
Expand All @@ -84,7 +90,7 @@ import { ChatConversationHeaderComponent } from '../../ui/chat-conversation-head
</ng-container>
</div>`,
styleUrls: ['./chat-page.component.scss'],
providers: [],
providers: [ChatStateService],
changeDetection: ChangeDetectionStrategy.Default,
standalone: true,
imports: [
Expand All @@ -101,4 +107,5 @@ import { ChatConversationHeaderComponent } from '../../ui/chat-conversation-head
})
export class ChatPageComponent {
chatState = inject(ChatStateService);
delayLoading$ = interval(100).pipe(take(1));
}
9 changes: 8 additions & 1 deletion src/app/chat/ui/chat-messages/chat-messages.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { map } from 'rxjs';
template: `
<div
*ngIf="ownUserId()"
class="flex h-[500px] flex-col-reverse overflow-auto p-10"
class="flex h-[500px] flex-col-reverse overflow-auto p-8"
>
<!-- Messages: {{ messagesIterative | json }}-->
<div class="flex flex-col gap-8">
Expand All @@ -33,6 +33,13 @@ import { map } from 'rxjs';
'self-end': message.authorId === ownUserId()
}"
></app-chat-single-message>
<div
*ngIf="activeChatMessages().length === 0"
class="self-center rounded border border-gray-400 px-8 py-4 text-center text-gray-500"
>
<p>Noch gibt es hier nichts zu sehen</p>
<p class="mb-0">Schreibe jetzt deine erste Nachricht</p>
</div>
</div>
</div>
`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { NgClass, NgIf } from '@angular/common';
class="rounded-3xl px-6 py-3 drop-shadow"
[ngClass]="{
'rounded-br-none bg-green-100': isOwnMessage,
'rounded-tl-none bg-white': !isOwnMessage
'rounded-bl-none bg-white': !isOwnMessage
}"
>
{{ message.text }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,22 @@ import { Profile } from '../../../profile/data-access/types/profile.types';
<ng-container>
<div
*ngIf="conversation() && participant()"
class="flex cursor-pointer items-center gap-6 px-6 py-4 hover:bg-gray-100 active:bg-gray-100"
class="active:bg-gray-150 mx-2 my-0.5 flex cursor-pointer items-center gap-6 rounded border border-white px-4 py-3 hover:bg-gray-100"
tabindex="0"
data-testid="chat-list-entry"
[ngClass]="{ 'bg-gray-100': isSelected() }"
[ngClass]="{
'bg-gray-100': isSelected(),
'border-gray-300': isSelected()
}"
(click)="chatState.selectChat$.next(conversation()!.id)"
>
<div class="h-20 w-20 overflow-hidden rounded-full object-cover">
<div class="h-16 w-16 overflow-hidden rounded-full object-cover">
<img
class=""
[src]="
imageService.getDancerImageSrcOrDefault(
participant()!.profileImageHash,
80
64
)
"
[attr.alt]="'Profile Image of' + participant()!.dancerName"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ type MessageComposerForm = FormGroup<{ message: FormControl<string> }>;
@Component({
selector: 'app-chat-message-composer',
template: `
<form class="flex px-6 py-4" [formGroup]="form" (ngSubmit)="postMessage()">
<form
class="flex border-t bg-gray-50 px-6 py-4"
[formGroup]="form"
(ngSubmit)="postMessage()"
>
<mat-form-field appearance="outline" class="w-full">
<input
matInput
Expand Down
7 changes: 6 additions & 1 deletion src/app/shared/data-access/auth/auth-storage.service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { BehaviorSubject, distinct, filter } from 'rxjs';

export type AuthData = {
isLoggedIn: boolean;
Expand All @@ -19,6 +19,11 @@ export class AuthStorageService {

public readonly authData$ = this._authData$.asObservable();

public readonly hasLoggedOut$ = this.authData$.pipe(
distinct((authData) => authData.isLoggedIn),
filter((authData) => !authData.isLoggedIn)
);

constructor() {}

private static initFromLocalStorage(): AuthData {
Expand Down

0 comments on commit 9c7083a

Please sign in to comment.