feat: Add incoming call modal

This commit is contained in:
2026-05-17 15:26:05 +02:00
parent 9d0a4478b2
commit 8e3ccf4157
8 changed files with 339 additions and 7 deletions

View File

@@ -0,0 +1,109 @@
import {
Component,
HostListener,
computed,
inject,
signal
} from '@angular/core';
import { CommonModule } from '@angular/common';
import { Store } from '@ngrx/store';
import { NgIcon, provideIcons } from '@ng-icons/core';
import { lucidePhone, lucidePhoneOff } from '@ng-icons/lucide';
import { UserAvatarComponent } from '../../../../shared';
import { selectCurrentUser } from '../../../../store/users/users.selectors';
import { User } from '../../../../shared-kernel';
import { DirectCallService } from '../../application/services/direct-call.service';
import { DirectCallSession, participantToUser } from '../../domain/models/direct-call.model';
@Component({
selector: 'app-incoming-call-modal',
standalone: true,
imports: [
CommonModule,
NgIcon,
UserAvatarComponent
],
viewProviders: [
provideIcons({
lucidePhone,
lucidePhoneOff
})
],
templateUrl: './incoming-call-modal.component.html'
})
export class IncomingCallModalComponent {
readonly calls = inject(DirectCallService);
readonly currentUser = inject(Store).selectSignal(selectCurrentUser);
readonly session = this.calls.incomingCall;
readonly answering = signal(false);
readonly caller = computed(() => {
const session = this.session();
if (!session) {
return null;
}
const callerId = this.callerIdFor(session);
const participant = callerId ? session.participants[callerId]?.profile : null;
return (callerId ? this.calls.userForParticipant(callerId) : null)
?? (participant ? participantToUser(participant) : null);
});
readonly callerName = computed(() => this.caller()?.displayName || 'Someone');
readonly callKindLabel = computed(() => {
const participantCount = this.session()?.participantIds.length ?? 0;
return participantCount > 2 ? `${participantCount} person call` : 'Direct call';
});
@HostListener('document:keydown.escape')
onEscape(): void {
this.decline();
}
async answer(): Promise<void> {
const session = this.session();
if (!session || this.answering()) {
return;
}
this.answering.set(true);
try {
await this.calls.answerIncomingCall(session.callId);
} finally {
this.answering.set(false);
}
}
decline(): void {
const session = this.session();
if (!session) {
return;
}
this.calls.declineIncomingCall(session.callId);
}
private callerIdFor(session: DirectCallSession): string | null {
const currentUserId = this.currentUserKey();
if (session.initiatorId && session.initiatorId !== currentUserId) {
return session.initiatorId;
}
return session.participantIds.find((participantId) => participantId !== currentUserId) ?? null;
}
private currentUserKey(): string | null {
const user = this.currentUser();
return user ? this.userKey(user) : null;
}
private userKey(user: User): string {
return user.oderId || user.id;
}
}