115 lines
4.8 KiB
JavaScript
115 lines
4.8 KiB
JavaScript
|
|
import React from 'react';
|
|
import { Mail, Phone, Calendar, FileText, User } from 'lucide-react';
|
|
import { cn, formatDateFR } from '@/lib/utils';
|
|
import StatusBadge from './StatusBadget';
|
|
import { useNavigate } from 'react-router-dom';
|
|
import { useAppDispatch } from '@/store/hooks';
|
|
import { selectCommandeAsync } from '@/store/features/commande/thunk';
|
|
import { selectDevis } from '@/store/features/devis/slice';
|
|
import { motion } from 'framer-motion';
|
|
import {
|
|
CheckCircle2, AlertCircle,
|
|
ArrowRight, Truck, PenTool, FileCheck, XCircle, Plus
|
|
} from 'lucide-react';
|
|
|
|
const iconMap = {
|
|
email: Mail,
|
|
call: Phone,
|
|
meeting: Calendar,
|
|
quote: FileText,
|
|
task: User,
|
|
};
|
|
|
|
const getEventIcon = (type) => {
|
|
switch (type) {
|
|
case 'creation': return Plus;
|
|
case 'email': return Mail;
|
|
case 'viewed': return CheckCircle2;
|
|
case 'signature': return PenTool;
|
|
case 'transform': return ArrowRight;
|
|
case 'delivery': return Truck;
|
|
case 'payment': return FileCheck;
|
|
case 'cancellation': return XCircle;
|
|
case 'update': return FileText;
|
|
default: return Calendar;
|
|
}
|
|
};
|
|
|
|
const getEventColor = (type) => {
|
|
switch (type) {
|
|
case 'creation': return 'bg-blue-100 text-blue-600 dark:bg-blue-900/30 dark:text-blue-400';
|
|
case 'email': return 'bg-purple-100 text-purple-600 dark:bg-purple-900/30 dark:text-purple-400';
|
|
case 'signature': return 'bg-green-100 text-green-600 dark:bg-green-900/30 dark:text-green-400';
|
|
case 'delivery': return 'bg-orange-100 text-orange-600 dark:bg-orange-900/30 dark:text-orange-400';
|
|
case 'cancellation': return 'bg-red-100 text-red-600 dark:bg-red-900/30 dark:text-red-400';
|
|
default: return 'bg-gray-100 text-gray-600 dark:bg-gray-800 dark:text-gray-400';
|
|
}
|
|
};
|
|
|
|
|
|
const Timeline = ({ events }) => {
|
|
const navigate = useNavigate();
|
|
const dispatch = useAppDispatch()
|
|
|
|
return (
|
|
<div className="max-w-2xl mx-auto py-4">
|
|
<div className="relative space-y-8 before:absolute before:inset-0 before:ml-5 before:h-full before:w-0.5 before:-translate-x-px before:bg-gradient-to-b before:from-transparent before:via-gray-200 before:to-transparent dark:before:via-gray-800">
|
|
{events.map((event, index) => {
|
|
const Icon = getEventIcon(event.type);
|
|
const colorClass = getEventColor(event.type);
|
|
|
|
return (
|
|
<motion.div
|
|
key={index}
|
|
initial={{ opacity: 0, x: -10 }}
|
|
animate={{ opacity: 1, x: 0 }}
|
|
transition={{ delay: index * 0.1 }}
|
|
className="relative flex items-start gap-6 group"
|
|
onClick={() => navigate(event.link)}
|
|
>
|
|
<div className={cn(
|
|
"relative z-10 flex h-10 w-10 items-center justify-center rounded-full border-4 border-white dark:border-gray-950 shadow-sm transition-transform group-hover:scale-110",
|
|
colorClass
|
|
)}>
|
|
<Icon className="h-4 w-4" />
|
|
</div>
|
|
|
|
<div className="flex-1 pt-1.5">
|
|
<div className="flex flex-col sm:flex-row sm:justify-between sm:items-center gap-1 mb-1">
|
|
<h4 className="text-base font-bold text-gray-900 dark:text-white">
|
|
{event.title}
|
|
</h4>
|
|
<span className="text-xs font-mono text-gray-400 dark:text-gray-500 whitespace-nowrap">
|
|
{new Date(event.date).toLocaleDateString()}
|
|
{event.time && ` • ${event.time}`}
|
|
</span>
|
|
</div>
|
|
|
|
<div className="bg-gray-50 dark:bg-gray-900/50 rounded-xl p-3 border border-gray-100 dark:border-gray-800 relative">
|
|
{/* Tiny triangle for speech bubble effect */}
|
|
<div className="absolute top-3 -left-1.5 w-3 h-3 bg-gray-50 dark:bg-gray-900/50 border-l border-b border-gray-100 dark:border-gray-800 transform rotate-45"></div>
|
|
|
|
<p className="text-sm text-gray-600 dark:text-gray-300 relative z-10">
|
|
{event.description || 'Aucun détail supplémentaire.'}
|
|
</p>
|
|
|
|
<div className="mt-2 flex items-center gap-2 pt-2 border-t border-gray-100 dark:border-gray-800">
|
|
<div className="w-5 h-5 rounded-full bg-gray-200 dark:bg-gray-700 flex items-center justify-center text-[9px] font-bold text-gray-600 dark:text-gray-300">
|
|
J
|
|
</div>
|
|
<span className="text-xs font-medium text-gray-500 dark:text-gray-400">
|
|
Jean Dupont
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</motion.div>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default Timeline;
|