import React, { useState, useRef, useEffect, useMemo } from 'react'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from './ui/card'; import { Button } from './ui/button'; import { Input } from './ui/input'; import { Avatar, AvatarFallback } from './ui/avatar'; import { Badge } from './ui/badge'; import { Tabs, TabsContent, TabsList, TabsTrigger } from './ui/tabs'; import { ScrollArea } from './ui/scroll-area'; import { Separator } from './ui/separator'; import { Textarea } from './ui/textarea'; import { ArrowLeft, Send, Smile, Paperclip, Users, FileText, Download, Eye, MoreHorizontal, MessageSquare, Clock, CheckCircle, AlertCircle, Search, Hash, AtSign, Phone, Video, Settings, Pin, Share, Archive, Plus, Filter, Calendar, Zap, Activity, Bell, Star, Flag, X } from 'lucide-react'; interface Message { id: string; user: { name: string; avatar: string; role: string; }; content: string; timestamp: string; mentions?: string[]; isSystem?: boolean; attachments?: { name: string; url: string; type: string; }[]; reactions?: { emoji: string; users: string[]; }[]; isHighPriority?: boolean; } interface Participant { name: string; avatar: string; role: string; status: 'online' | 'away' | 'offline'; email: string; lastSeen?: string; permissions: string[]; } interface WorkNoteViewProps { requestId: string; onBack?: () => void; } // Get request data from the same source as RequestDetail const REQUEST_DATABASE = { 'RE-REQ-001': { id: 'RE-REQ-001', title: 'Marketing Campaign Budget Approval', department: 'Marketing', priority: 'high', status: 'pending' }, 'RE-REQ-002': { id: 'RE-REQ-002', title: 'IT Equipment Purchase', department: 'IT', priority: 'medium', status: 'in-review' } }; // Static data to prevent re-renders const MOCK_PARTICIPANTS: Participant[] = [ { name: 'Sarah Chen', avatar: 'SC', role: 'Initiator', status: 'online', email: 'sarah.chen@royalenfield.com', permissions: ['read', 'write', 'mention'] }, { name: 'Mike Johnson', avatar: 'MJ', role: 'Team Lead', status: 'online', email: 'mike.johnson@royalenfield.com', permissions: ['read', 'write', 'mention', 'approve'] }, { name: 'Lisa Wong', avatar: 'LW', role: 'Finance Manager', status: 'away', email: 'lisa.wong@royalenfield.com', lastSeen: '5 minutes ago', permissions: ['read', 'write', 'mention', 'approve'] }, { name: 'Anna Smith', avatar: 'AS', role: 'Spectator', status: 'online', email: 'anna.smith@royalenfield.com', permissions: ['read', 'write', 'mention'] }, { name: 'John Doe', avatar: 'JD', role: 'Spectator', status: 'offline', email: 'john.doe@royalenfield.com', lastSeen: '2 hours ago', permissions: ['read'] }, { name: 'Emily Davis', avatar: 'ED', role: 'Creative Director', status: 'online', email: 'emily.davis@royalenfield.com', permissions: ['read', 'write', 'mention'] } ]; const MOCK_DOCUMENTS = [ { name: 'Q4_Marketing_Strategy.pdf', size: '2.4 MB', uploadedBy: 'Sarah Chen', uploadedAt: '2024-10-05 14:32', type: 'PDF', url: '#' }, { name: 'Budget_Breakdown.xlsx', size: '1.1 MB', uploadedBy: 'Sarah Chen', uploadedAt: '2024-10-05 14:35', type: 'Excel', url: '#' }, { name: 'Previous_Campaign_ROI.pdf', size: '856 KB', uploadedBy: 'Anna Smith', uploadedAt: '2024-10-06 09:15', type: 'PDF', url: '#' }, { name: 'Competitor_Analysis.pptx', size: '3.2 MB', uploadedBy: 'Emily Davis', uploadedAt: '2024-10-06 15:22', type: 'PowerPoint', url: '#' } ]; const INITIAL_MESSAGES: Message[] = [ { id: '1', user: { name: 'Sarah Chen', avatar: 'SC', role: 'Initiator' }, content: 'Hi everyone! I\'ve submitted the marketing campaign budget request for Q4. Please review the attached documents and let me know if you need any additional information.', timestamp: '2024-10-05 14:30', isSystem: false, reactions: [ { emoji: 'šŸ‘', users: ['Mike Johnson', 'Anna Smith'] }, { emoji: 'šŸ“‹', users: ['Lisa Wong'] } ] }, { id: '2', user: { name: 'System', avatar: 'SY', role: 'System' }, content: 'Request RE-REQ-001 has been created and assigned to Mike Johnson for initial review.', timestamp: '2024-10-05 14:31', isSystem: true }, { id: '3', user: { name: 'Anna Smith', avatar: 'AS', role: 'Spectator' }, content: 'I\'ve added the previous campaign ROI data to help with the decision. The numbers show a 285% ROI from our last similar campaign. @Mike Johnson @Lisa Wong please check it out when you have a moment.', timestamp: '2024-10-06 09:15', mentions: ['Mike Johnson', 'Lisa Wong'], attachments: [ { name: 'Previous_Campaign_ROI.pdf', url: '#', type: 'pdf' } ] }, { id: '4', user: { name: 'Mike Johnson', avatar: 'MJ', role: 'Team Lead' }, content: 'Thanks @Anna Smith! The historical data is very helpful. After reviewing the strategy document and budget breakdown, I believe this campaign is well-planned and has strong potential. I\'m approving this and forwarding to Finance for final review.', timestamp: '2024-10-06 10:30', mentions: ['Anna Smith'], reactions: [ { emoji: 'āœ…', users: ['Sarah Chen', 'Anna Smith'] } ] }, { id: '5', user: { name: 'System', avatar: 'SY', role: 'System' }, content: 'Request approved by Mike Johnson and forwarded to Lisa Wong for finance review.', timestamp: '2024-10-06 10:31', isSystem: true }, { id: '6', user: { name: 'Emily Davis', avatar: 'ED', role: 'Creative Director' }, content: 'Great work on the strategy @Sarah Chen! I\'ve also added our competitor analysis to provide more context. The creative assets timeline looks achievable.', timestamp: '2024-10-06 15:22', mentions: ['Sarah Chen'], attachments: [ { name: 'Competitor_Analysis.pptx', url: '#', type: 'pptx' } ] }, { id: '7', user: { name: 'Lisa Wong', avatar: 'LW', role: 'Finance Manager' }, content: 'I\'m currently reviewing the budget allocation and comparing it with Q3 spending. @Sarah Chen can you clarify the expected timeline for the LinkedIn ads campaign? Also, do we have approval from legal for the content strategy?', timestamp: '2024-10-07 14:20', mentions: ['Sarah Chen'], isHighPriority: true }, { id: '8', user: { name: 'Sarah Chen', avatar: 'SC', role: 'Initiator' }, content: 'Hi @Lisa Wong! For the LinkedIn campaign:\n\n• Launch: November 1st\n• Duration: 8 weeks\n• Budget distribution: 40% first 4 weeks, 60% last 4 weeks\n\nRegarding legal approval - I\'ll coordinate with the legal team this week. The content strategy follows our established brand guidelines.', timestamp: '2024-10-07 15:45', mentions: ['Lisa Wong'] } ]; // Utility functions const getStatusColor = (status: string) => { switch (status) { case 'online': return 'bg-green-500'; case 'away': return 'bg-yellow-500'; case 'offline': return 'bg-gray-400'; default: return 'bg-gray-400'; } }; const getStatusText = (status: string) => { switch (status) { case 'online': return 'Online'; case 'away': return 'Away'; case 'offline': return 'Offline'; default: return 'Unknown'; } }; const formatMessage = (content: string) => { // Enhanced mention highlighting with better regex return content .replace(/@([\w\s]+)(?=\s|$|[.,!?])/g, '@$1') .replace(/\n/g, '
'); }; const getFileIcon = (type: string) => { switch (type.toLowerCase()) { case 'pdf': return 'šŸ“„'; case 'excel': case 'xlsx': return 'šŸ“Š'; case 'powerpoint': case 'pptx': return 'šŸ“Š'; case 'word': case 'docx': return 'šŸ“'; case 'image': case 'png': case 'jpg': case 'jpeg': return 'šŸ–¼ļø'; default: return 'šŸ“Ž'; } }; export function WorkNoteView({ requestId, onBack }: WorkNoteViewProps) { const [message, setMessage] = useState(''); const [isTyping, setIsTyping] = useState(false); const [activeTab, setActiveTab] = useState('chat'); const [searchTerm, setSearchTerm] = useState(''); const [showEmojiPicker, setShowEmojiPicker] = useState(false); const [messages, setMessages] = useState(INITIAL_MESSAGES); const [showSidebar, setShowSidebar] = useState(false); const messagesEndRef = useRef(null); // Get request info const requestInfo = useMemo(() => { const data = REQUEST_DATABASE[requestId as keyof typeof REQUEST_DATABASE]; return data || { id: requestId, title: 'Unknown Request', department: 'Unknown', priority: 'medium', status: 'pending' }; }, [requestId]); const onlineParticipants = MOCK_PARTICIPANTS.filter(p => p.status === 'online'); const filteredMessages = messages.filter(msg => msg.content.toLowerCase().includes(searchTerm.toLowerCase()) || msg.user.name.toLowerCase().includes(searchTerm.toLowerCase()) ); const scrollToBottom = () => { messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }); }; useEffect(() => { scrollToBottom(); }, [messages]); const handleSendMessage = () => { if (message.trim()) { const newMessage: Message = { id: Date.now().toString(), user: { name: 'You', avatar: 'YO', role: 'Current User' }, content: message, timestamp: new Date().toLocaleString(), mentions: extractMentions(message), isHighPriority: message.includes('!important') || message.includes('urgent') }; setMessages(prev => [...prev, newMessage]); setMessage(''); } }; const extractMentions = (text: string): string[] => { const mentionRegex = /@([\w\s]+)(?=\s|$|[.,!?])/g; const mentions = []; let match; while ((match = mentionRegex.exec(text)) !== null) { mentions.push(match[1].trim()); } return mentions; }; const handleKeyPress = (e: React.KeyboardEvent) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); handleSendMessage(); } }; const addReaction = (messageId: string, emoji: string) => { setMessages(prev => prev.map(msg => { if (msg.id === messageId) { const reactions = msg.reactions || []; const existingReaction = reactions.find(r => r.emoji === emoji); if (existingReaction) { if (existingReaction.users.includes('You')) { existingReaction.users = existingReaction.users.filter(u => u !== 'You'); if (existingReaction.users.length === 0) { return { ...msg, reactions: reactions.filter(r => r.emoji !== emoji) }; } } else { existingReaction.users.push('You'); } } else { reactions.push({ emoji, users: ['You'] }); } return { ...msg, reactions }; } return msg; })); }; return (
{/* Header */}

Work Notes

{requestInfo.title}

{requestId}
{onlineParticipants.slice(0, 3).map((participant, index) => ( {participant.avatar} ))} {onlineParticipants.length > 3 && (
+{onlineParticipants.length - 3}
)}
{/* Main Chat Area */}
{/* Tab Navigation */}
Messages Chat Files Activity Act
{/* Chat Tab */} {/* Search Bar */}
setSearchTerm(e.target.value)} className="pl-10 bg-gray-50 border-gray-200 h-9 sm:h-10" />
{/* Messages Area */}
{filteredMessages.map((msg) => (
{!msg.isSystem && ( {msg.user.avatar} )}
{msg.isSystem ? (
{msg.content} {msg.timestamp}
) : (
{/* Message Header */}
{msg.user.name} {msg.user.role} {msg.timestamp} {msg.isHighPriority && ( Priority )}
{/* Message Content */}
{/* Attachments */} {msg.attachments && msg.attachments.length > 0 && (
{msg.attachments.map((attachment, index) => (
{getFileIcon(attachment.type)} {attachment.name}
))}
)} {/* Reactions */} {msg.reactions && msg.reactions.length > 0 && (
{msg.reactions.map((reaction, index) => ( ))}
)}
)}
))} {isTyping && (
Someone is typing...
)}
{/* Message Input */}