"use client"; import { useState, useCallback, useEffect } from "react"; import { useSearchParams, useRouter } from 'next/navigation'; import type { ChatRecipient, User, Group, CallType } from "@/lib/types"; import { useAuth } from "@/contexts/auth-context"; import { useSettings } from "@/contexts/settings-context"; import { useCalls } from "@/contexts/calls-context"; import { useContacts } from "@/contexts/contacts-context"; import { UserList } from "@/components/user-list"; import { ChatWindow } from "@/app/chat-window"; import { CreateGroupModal } from "@/components/create-group-modal"; import { ViewProfileModal } from "@/components/view-profile-modal"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from "@/components/ui/alert-dialog"; import { ImagePreviewModal } from "@/components/image-preview-modal"; import { AddGroupMembersModal } from "@/components/add-group-members-modal"; import { CallModal } from "@/components/call-modal"; import { SettingsPage } from "@/components/settings-page"; import { MobileBottomNav } from "@/components/mobile-bottom-nav"; import { Input } from "@/components/ui/input"; import { ChangeNameModal } from "@/components/change-name-modal"; import { ChangeStatusModal } from "@/components/change-status-modal"; import { ChangeBioModal } from "@/components/change-bio-modal"; import { cn } from "@/lib/utils"; import { NetworkStatusIndicator } from "@/components/network-status-indicator"; import { Capacitor } from '@capacitor/core'; import { PushNotifications } from '@capacitor/push-notifications'; import { WelcomeScreen } from "./welcome-screen"; export function ChatInterface() { const { currentUser, authStatus, signOutUser } = useAuth(); const { t } = useSettings(); const { callState, startVideoCall, answerCall, startAudioCall, endCall } = useCalls(); const { findUserByPublicId } = useContacts(); const searchParams = useSearchParams(); const router = useRouter(); const [recipient, setRecipient] = useState(null); const [isCreateGroupModalOpen, setCreateGroupModalOpen] = useState(false); const [isSettingsOpen, setSettingsOpen] = useState(false); const [settingsSection, setSettingsSection] = useState(undefined); const [viewingProfile, setViewingProfile] = useState(null); const [isSignOutModalOpen, setSignOutModalOpen] = useState(false); const [signOutConfirmText, setSignOutConfirmText] = useState(''); const [imageToPreview, setImageToPreview] = useState(null); const [groupToAddMembers, setGroupToAddMembers] = useState(null); // State for granular modals const [isChangeNameModalOpen, setChangeNameModalOpen] = useState(false); const [isChangeStatusModalOpen, setChangeStatusModalOpen] = useState(false); const [isChangeBioModalOpen, setChangeBioModalOpen] = useState(false); const handleStartCall = useCallback((peer: User, type: CallType) => { if (type === 'video') { startVideoCall(peer); } else { startAudioCall(peer); } }, [startAudioCall, startVideoCall]); const handleUserSelection = useCallback((userOrGroup: User | Group) => { if (!currentUser) return; if ('members' in userOrGroup) { // It's a Group if (userOrGroup.members[currentUser.uid]) { setRecipient({ ...userOrGroup.info, uid: userOrGroup.id, isGroup: true, displayName: userOrGroup.info.name, photoURL: userOrGroup.info.photoURL, publicId: userOrGroup.id }); } } else { // It's a User if (userOrGroup.uid !== currentUser.uid) { setRecipient({ ...userOrGroup, isGroup: false, uid: userOrGroup.uid, displayName: userOrGroup.displayName }); } } }, [currentUser]); useEffect(() => { const senderId = searchParams.get('senderId'); if (senderId && currentUser) { findUserByPublicId(senderId).then(user => { if (user) { handleUserSelection(user); } }); } }, [searchParams, currentUser, findUserByPublicId, handleUserSelection]); useEffect(() => { if (Capacitor.getPlatform() === 'web') return; // Clear any existing listeners to avoid duplicates when the component re-renders PushNotifications.removeAllListeners().then(() => { PushNotifications.addListener('pushNotificationActionPerformed', (action) => { const { actionId, notification } = action; const data = notification.data || {}; console.log(`[Push Action] Received action: ${actionId}`, data); if (data && data.type === 'incoming-call') { // Important: Check if this action corresponds to the current incoming call if (callState.status === 'incoming' && callState.channelName === data.channelName) { if (actionId === 'answer') { console.log('[Push Action] Answering call...'); answerCall(); } else if (actionId === 'decline') { console.log('[Push Action] Declining call...'); endCall(); } } else { console.warn(`[Push Action] Received action for call ${data.channelName}, but current call state is ${callState.status} for channel ${callState.channelName}. Action ignored.`); } } }); }); // Cleanup on component unmount return () => { PushNotifications.removeAllListeners(); } }, [callState.status, callState.channelName, answerCall, endCall]); // Dependencies ensure the listener always has the latest state handlers const openSettings = useCallback((section?: string) => { setSettingsSection(section); setSettingsOpen(true); setRecipient(null); // Close any open chat window }, []); const openChangeNameModal = useCallback(() => setChangeNameModalOpen(true), []); const openChangeStatusModal = useCallback(() => setChangeStatusModalOpen(true), []); const openChangeBioModal = useCallback(() => setChangeBioModalOpen(true), []); if (authStatus !== 'authenticated' || !currentUser) { return null; } const handleSignOut = async () => { await signOutUser(); setSignOutModalOpen(false); setSignOutConfirmText(''); }; const isMobile = typeof window !== 'undefined' && window.innerWidth < 768; const showMobileNav = isMobile && !recipient && !isSettingsOpen; const isSignOutConfirmValid = signOutConfirmText.toLowerCase() === t('leaveWord') || signOutConfirmText.toLowerCase() === 'leave'; const numericUid = parseInt(currentUser.uid.replace(/[^0-9]/g, '').substring(0, 8), 10) || Math.floor(Math.random() * 100000); return ( <>
{/* Pane 1: User List (always visible on desktop, conditionally on mobile) */}
{ setRecipient(r); setSettingsOpen(false); }} onOpenCreateGroup={() => setCreateGroupModalOpen(true)} onOpenSettings={openSettings} onSignOut={() => setSignOutModalOpen(true)} onViewProfile={setViewingProfile} />
{/* Pane 2: Main Content (Chat, Settings, or Welcome) */}
{isSettingsOpen ? ( setSettingsOpen(false)} initialSection={settingsSection} /> ) : recipient ? ( setRecipient(null)} onViewProfile={setViewingProfile} onPreviewImage={setImageToPreview} onAddMembers={(group) => setGroupToAddMembers(group)} onStartCall={handleStartCall} onOpenSettings={openSettings} openChangeNameModal={openChangeNameModal} openChangeStatusModal={openChangeStatusModal} openChangeBioModal={openChangeBioModal} /> ) : ( // This only shows on desktop when no chat/settings are open )}
{/* Mobile nav is only shown on the UserList screen */} {showMobileNav && }
setCreateGroupModalOpen(false)} /> setViewingProfile(null)} onStartChat={handleUserSelection} /> {groupToAddMembers && ( setGroupToAddMembers(null)} group={groupToAddMembers} /> )} setImageToPreview(null)} /> setChangeNameModalOpen(false)} /> setChangeStatusModalOpen(false)} /> setChangeBioModalOpen(false)} /> {t('signOutConfirmationTitle')} {t('signOutConfirmationDescription', { word: t('leaveWord') })} setSignOutConfirmText(e.target.value)} placeholder={t('leaveWord')} autoFocus /> setSignOutConfirmText('')}>{t('cancel')} {t('signOut')} ); }