fix(mobile): resolve all TypeScript errors from integration

- Fix voiceStore method names (toggleMic, leaveVoice, setCurrentVoiceChannel)
- Fix MemberWithUser nested user property access
- Pass required channelId props to MessageList, TypingIndicator, MessageInput
- Fix ConfirmDialog props (isOpen, description, variant, onClose)
- Add mobileStyle prop to Modal component (fullscreen + sheet modes)
- Fix fromId/isAdmin camelCase property names
- Guard possibly undefined touch events and array accesses
- Fix notification channelId resolution
This commit is contained in:
Jannis Braun
2026-03-17 15:54:39 +01:00
parent 7619b091da
commit ed70099963
11 changed files with 89 additions and 25 deletions
+61 -1
View File
@@ -1,4 +1,5 @@
import React, { useEffect, useCallback } from 'react';
import { useUIStore } from '../../stores/uiStore';
interface ModalProps {
isOpen: boolean;
@@ -6,9 +7,13 @@ interface ModalProps {
title?: string;
children: React.ReactNode;
maxWidth?: string;
/** Mobile display style: 'fullscreen' fills the screen, 'sheet' anchors to bottom, 'default' stays centered */
mobileStyle?: 'fullscreen' | 'sheet' | 'default';
}
export function Modal({ isOpen, onClose, title, children, maxWidth = 'max-w-md' }: ModalProps) {
export function Modal({ isOpen, onClose, title, children, maxWidth = 'max-w-md', mobileStyle = 'default' }: ModalProps) {
const isMobile = useUIStore((s) => s.isMobile);
const handleKeyDown = useCallback((e: KeyboardEvent) => {
if (e.key === 'Escape') {
onClose();
@@ -24,6 +29,61 @@ export function Modal({ isOpen, onClose, title, children, maxWidth = 'max-w-md'
if (!isOpen) return null;
// Mobile fullscreen style
if (isMobile && mobileStyle === 'fullscreen') {
return (
<div className="fixed inset-0 z-[200] flex flex-col bg-surface-base animate-fade-in">
{title && (
<div className="flex items-center justify-between px-4 pt-4 flex-shrink-0" style={{ paddingTop: 'calc(16px + env(safe-area-inset-top))' }}>
<h2 className="text-xl font-bold text-txt-primary">{title}</h2>
<button
onClick={onClose}
className="text-txt-tertiary hover:text-txt-primary transition-colors p-1"
>
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
<path d="M18.4 4L12 10.4L5.6 4L4 5.6L10.4 12L4 18.4L5.6 20L12 13.6L18.4 20L20 18.4L13.6 12L20 5.6L18.4 4Z" />
</svg>
</button>
</div>
)}
<div className="p-4 overflow-y-auto scrollbar-thin flex-1 min-h-0" style={{ paddingBottom: 'calc(16px + env(safe-area-inset-bottom))' }}>
{children}
</div>
</div>
);
}
// Mobile bottom sheet style
if (isMobile && mobileStyle === 'sheet') {
return (
<div className="fixed inset-0 z-[200] flex items-end justify-center animate-fade-in">
<div
className="absolute inset-0 bg-black/50"
onClick={onClose}
/>
<div className="relative w-full max-h-[85vh] flex flex-col glass-modal rounded-t-2xl animate-slide-up" style={{ paddingBottom: 'env(safe-area-inset-bottom)' }}>
{title && (
<div className="flex items-center justify-between px-4 pt-4 flex-shrink-0">
<h2 className="text-xl font-bold text-txt-primary">{title}</h2>
<button
onClick={onClose}
className="text-txt-tertiary hover:text-txt-primary transition-colors p-1"
>
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
<path d="M18.4 4L12 10.4L5.6 4L4 5.6L10.4 12L4 18.4L5.6 20L12 13.6L18.4 20L20 18.4L13.6 12L20 5.6L18.4 4Z" />
</svg>
</button>
</div>
)}
<div className="p-4 overflow-y-auto scrollbar-thin flex-1 min-h-0">
{children}
</div>
</div>
</div>
);
}
// Default centered dialog (desktop and mobile default)
return (
<div className="fixed inset-0 z-[200] flex items-center justify-center animate-fade-in">
<div