136 lines
4.0 KiB
TypeScript
136 lines
4.0 KiB
TypeScript
"use client";
|
|
|
|
import { useState, useEffect } from 'react';
|
|
import { Phone, PhoneOff, X } from 'lucide-react';
|
|
import { Button } from '@/components/ui/button';
|
|
import { useRouter } from 'next/navigation';
|
|
|
|
export interface IncomingCall {
|
|
from: {
|
|
userId: string;
|
|
username: string;
|
|
name: string;
|
|
};
|
|
roomId: string;
|
|
roomName: string;
|
|
timestamp: Date;
|
|
}
|
|
|
|
interface IncomingCallNotificationProps {
|
|
call: IncomingCall | null;
|
|
onDismiss: () => void;
|
|
onAccept: (roomId: string) => void;
|
|
onReject: () => void;
|
|
}
|
|
|
|
export function IncomingCallNotification({
|
|
call,
|
|
onDismiss,
|
|
onAccept,
|
|
onReject,
|
|
}: IncomingCallNotificationProps) {
|
|
const router = useRouter();
|
|
const [isVisible, setIsVisible] = useState(false);
|
|
|
|
useEffect(() => {
|
|
if (call) {
|
|
console.log('[IncomingCallNotification] 📞 Call received, showing notification', {
|
|
from: call.from.name || call.from.username,
|
|
roomId: call.roomId,
|
|
});
|
|
setIsVisible(true);
|
|
|
|
// Auto-dismiss after 30 seconds if user doesn't interact
|
|
const autoDismissTimer = setTimeout(() => {
|
|
console.log('[IncomingCallNotification] ⏰ Auto-dismissing after 30 seconds');
|
|
setIsVisible(false);
|
|
onDismiss();
|
|
}, 30000); // 30 seconds
|
|
|
|
return () => {
|
|
clearTimeout(autoDismissTimer);
|
|
};
|
|
} else {
|
|
setIsVisible(false);
|
|
}
|
|
}, [call, onDismiss]);
|
|
|
|
if (!call || !isVisible) {
|
|
return null;
|
|
}
|
|
|
|
const handleAccept = () => {
|
|
onAccept(call.roomId);
|
|
// Navigate to parole page with room ID
|
|
router.push(`/parole?room=${call.roomId}`);
|
|
setIsVisible(false);
|
|
};
|
|
|
|
const handleReject = () => {
|
|
onReject();
|
|
setIsVisible(false);
|
|
};
|
|
|
|
const handleDismiss = () => {
|
|
onDismiss();
|
|
setIsVisible(false);
|
|
};
|
|
|
|
const callerName = call.from.name || call.from.username || 'Inconnu';
|
|
|
|
return (
|
|
<div className="fixed top-4 right-4 z-[9999] animate-in slide-in-from-top-5 duration-300">
|
|
<div className="bg-white rounded-lg shadow-2xl border-2 border-blue-500 p-5 min-w-[340px] max-w-[420px]">
|
|
{/* Header with Outlook-like style */}
|
|
<div className="flex items-start justify-between mb-4 pb-3 border-b border-gray-200">
|
|
<div className="flex items-center gap-3">
|
|
<div className="w-10 h-10 rounded-full bg-blue-100 flex items-center justify-center flex-shrink-0">
|
|
<Phone className="w-5 h-5 text-blue-600" />
|
|
</div>
|
|
<div>
|
|
<h3 className="font-semibold text-base text-gray-900 leading-tight">Parole</h3>
|
|
<p className="text-xs text-gray-500 mt-0.5">Appel entrant</p>
|
|
</div>
|
|
</div>
|
|
<button
|
|
onClick={handleDismiss}
|
|
className="text-gray-400 hover:text-gray-600 transition-colors p-1 -mt-1 -mr-1"
|
|
aria-label="Fermer"
|
|
>
|
|
<X className="w-4 h-4" />
|
|
</button>
|
|
</div>
|
|
|
|
{/* Call Info - Outlook style message */}
|
|
<div className="mb-5">
|
|
<p className="text-gray-800 text-sm leading-relaxed">
|
|
Vous avez un appel de <span className="font-semibold text-gray-900">{callerName}</span>
|
|
</p>
|
|
{call.roomName && call.roomName !== callerName && (
|
|
<p className="text-xs text-gray-500 mt-1.5">Dans {call.roomName}</p>
|
|
)}
|
|
</div>
|
|
|
|
{/* Actions - Outlook style buttons */}
|
|
<div className="flex gap-2.5">
|
|
<Button
|
|
onClick={handleAccept}
|
|
className="flex-1 bg-green-600 hover:bg-green-700 text-white font-medium py-2.5 text-sm shadow-sm"
|
|
>
|
|
<Phone className="w-4 h-4 mr-2" />
|
|
Accepter
|
|
</Button>
|
|
<Button
|
|
onClick={handleReject}
|
|
variant="destructive"
|
|
className="flex-1 font-medium py-2.5 text-sm shadow-sm"
|
|
>
|
|
<PhoneOff className="w-4 h-4 mr-2" />
|
|
Raccrocher
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|