NeahStable/components/outlook-notification.tsx
2026-01-16 01:59:57 +01:00

162 lines
5.0 KiB
TypeScript

"use client";
import { useState, useEffect, ReactNode } from 'react';
import { X, LucideIcon } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { useRouter } from 'next/navigation';
export interface OutlookNotificationAction {
label: string;
onClick: () => void;
variant?: 'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link';
className?: string;
icon?: LucideIcon;
}
export interface OutlookNotificationData {
id: string;
source: 'email' | 'rocketchat' | 'call' | 'leantime' | 'calendar';
title: string;
subtitle?: string;
message: string;
icon: LucideIcon;
iconColor?: string;
iconBgColor?: string;
borderColor?: string;
link?: string;
timestamp?: Date;
actions?: OutlookNotificationAction[];
autoDismiss?: number; // milliseconds, default 30s
}
interface OutlookNotificationProps {
notification: OutlookNotificationData | null;
onDismiss: () => void;
}
export function OutlookNotification({
notification,
onDismiss,
}: OutlookNotificationProps) {
const router = useRouter();
const [isVisible, setIsVisible] = useState(false);
useEffect(() => {
if (notification) {
console.log('[OutlookNotification] 📬 Showing notification', {
source: notification.source,
title: notification.title,
});
setIsVisible(true);
// Auto-dismiss after specified time (default 30 seconds)
const autoDismissTime = notification.autoDismiss || 30000;
const autoDismissTimer = setTimeout(() => {
console.log('[OutlookNotification] ⏰ Auto-dismissing after', autoDismissTime, 'ms');
setIsVisible(false);
onDismiss();
}, autoDismissTime);
return () => {
clearTimeout(autoDismissTimer);
};
} else {
setIsVisible(false);
}
}, [notification, onDismiss]);
if (!notification || !isVisible) {
return null;
}
const handleDismiss = () => {
onDismiss();
setIsVisible(false);
};
const handleLinkClick = () => {
if (notification.link) {
router.push(notification.link);
setIsVisible(false);
onDismiss();
}
};
const Icon = notification.icon;
const borderColor = notification.borderColor || 'border-blue-500';
const iconBgColor = notification.iconBgColor || 'bg-blue-100';
const iconColor = notification.iconColor || 'text-blue-600';
return (
<div className={`bg-white rounded-lg shadow-2xl border-2 ${borderColor} 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 ${iconBgColor} flex items-center justify-center flex-shrink-0`}>
<Icon className={`w-5 h-5 ${iconColor}`} />
</div>
<div>
<h3 className="font-semibold text-base text-gray-900 leading-tight">{notification.title}</h3>
{notification.subtitle && (
<p className="text-xs text-gray-500 mt-0.5">{notification.subtitle}</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>
{/* Message - Outlook style */}
<div className="mb-5">
<p className="text-gray-800 text-sm leading-relaxed">
{notification.message}
</p>
{notification.timestamp && (
<p className="text-xs text-gray-500 mt-1.5">
{new Date(notification.timestamp).toLocaleTimeString('fr-FR', {
hour: '2-digit',
minute: '2-digit'
})}
</p>
)}
</div>
{/* Actions - Outlook style buttons */}
{notification.actions && notification.actions.length > 0 && (
<div className="flex gap-2.5">
{notification.actions.map((action, index) => {
const ActionIcon = action.icon;
return (
<Button
key={index}
onClick={action.onClick}
variant={action.variant || 'default'}
className={`flex-1 font-medium py-2.5 text-sm shadow-sm ${action.className || ''}`}
>
{ActionIcon && <ActionIcon className="w-4 h-4 mr-2" />}
{action.label}
</Button>
);
})}
</div>
)}
{/* If no actions but has link, make the whole card clickable */}
{!notification.actions && notification.link && (
<Button
onClick={handleLinkClick}
className="w-full font-medium py-2.5 text-sm shadow-sm"
>
Ouvrir
</Button>
)}
</div>
</div>
);
}