From 47a5a436aa2d575ce4c2e5cbb4fb645e8d9192a3 Mon Sep 17 00:00:00 2001 From: laxmanhalaki Date: Thu, 23 Oct 2025 19:40:12 +0530 Subject: [PATCH] enhanced ext editor in worknote page --- .../layout/PageLayout/PageLayout.tsx | 61 +++- .../workNote/WorkNoteChat/WorkNoteChat.tsx | 270 +++++++++++++++--- src/styles/globals.css | 24 ++ 3 files changed, 303 insertions(+), 52 deletions(-) diff --git a/src/components/layout/PageLayout/PageLayout.tsx b/src/components/layout/PageLayout/PageLayout.tsx index 033ff2d..25bced4 100644 --- a/src/components/layout/PageLayout/PageLayout.tsx +++ b/src/components/layout/PageLayout/PageLayout.tsx @@ -1,4 +1,4 @@ -import { useState } from 'react'; +import { useState, useEffect } from 'react'; import { Bell, Settings, User, Plus, Search, Home, FileText, CheckCircle, LogOut, PanelLeft, PanelLeftClose } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; @@ -14,7 +14,7 @@ interface PageLayoutProps { } export function PageLayout({ children, currentPage = 'dashboard', onNavigate, onNewRequest }: PageLayoutProps) { - const [sidebarOpen, setSidebarOpen] = useState(true); + const [sidebarOpen, setSidebarOpen] = useState(false); const menuItems = [ { id: 'dashboard', label: 'Dashboard', icon: Home }, @@ -27,11 +27,52 @@ export function PageLayout({ children, currentPage = 'dashboard', onNavigate, on setSidebarOpen(!sidebarOpen); }; + // Handle responsive behavior: sidebar open on desktop, closed on mobile + useEffect(() => { + const handleResize = () => { + // 768px is the md breakpoint in Tailwind + if (window.innerWidth >= 768) { + setSidebarOpen(true); // Always open on desktop + } else { + setSidebarOpen(false); // Closed by default on mobile + } + }; + + // Set initial state + handleResize(); + + // Add event listener + window.addEventListener('resize', handleResize); + + // Cleanup + return () => window.removeEventListener('resize', handleResize); + }, []); + return (
- {/* Sidebar */} -
-
+ {/* Mobile Overlay */} + {sidebarOpen && ( +
setSidebarOpen(false)} + /> + )} + + {/* Sidebar - Hidden on mobile by default, toggleable on desktop */} + {/* Main Content Area */}
diff --git a/src/components/workNote/WorkNoteChat/WorkNoteChat.tsx b/src/components/workNote/WorkNoteChat/WorkNoteChat.tsx index 62fbd6d..cdc4a07 100644 --- a/src/components/workNote/WorkNoteChat/WorkNoteChat.tsx +++ b/src/components/workNote/WorkNoteChat/WorkNoteChat.tsx @@ -305,7 +305,9 @@ export function WorkNoteChat({ requestId, onBack }: WorkNoteChatProps) { const [showEmojiPicker, setShowEmojiPicker] = useState(false); const [messages, setMessages] = useState(INITIAL_MESSAGES); const [showSidebar, setShowSidebar] = useState(false); + const [selectedFiles, setSelectedFiles] = useState([]); const messagesEndRef = useRef(null); + const fileInputRef = useRef(null); // Get request info const requestInfo = useMemo(() => { @@ -334,26 +336,116 @@ export function WorkNoteChat({ requestId, onBack }: WorkNoteChatProps) { }, [messages]); const handleSendMessage = () => { - if (message.trim()) { + if (message.trim() || selectedFiles.length > 0) { + const attachments = selectedFiles.map(file => ({ + name: file.name, + url: URL.createObjectURL(file), + type: file.type.split('/')[1] || 'file' + })); + const newMessage: Message = { id: Date.now().toString(), user: { name: 'You', avatar: 'YO', role: 'Current User' }, content: message, - timestamp: new Date().toLocaleString(), + timestamp: new Date().toLocaleString('en-US', { + month: 'short', + day: 'numeric', + year: 'numeric', + hour: 'numeric', + minute: 'numeric', + hour12: true + }), mentions: extractMentions(message), - isHighPriority: message.includes('!important') || message.includes('urgent') + isHighPriority: message.includes('!important') || message.includes('urgent'), + attachments: attachments.length > 0 ? attachments : undefined }; setMessages(prev => [...prev, newMessage]); setMessage(''); + setSelectedFiles([]); } }; + const handleFileSelect = (e: React.ChangeEvent) => { + if (e.target.files) { + const filesArray = Array.from(e.target.files); + setSelectedFiles(prev => [...prev, ...filesArray]); + } + }; + + const handleRemoveFile = (index: number) => { + setSelectedFiles(prev => prev.filter((_, i) => i !== index)); + // Reset file input to allow reselecting the same file + if (fileInputRef.current) { + fileInputRef.current.value = ''; + } + }; + + const handleEmojiSelect = (emoji: string) => { + setMessage(prev => prev + emoji); + setShowEmojiPicker(false); + }; + + const handleAttachmentClick = () => { + fileInputRef.current?.click(); + }; + + // Emoji picker data - Expanded collection + const emojiList = [ + // Smileys & Emotions + '๐Ÿ˜Š', '๐Ÿ˜‚', '๐Ÿคฃ', '๐Ÿ˜', '๐Ÿ˜ƒ', '๐Ÿ˜„', '๐Ÿ˜…', '๐Ÿ˜†', '๐Ÿ˜‰', '๐Ÿ˜Œ', + '๐Ÿ˜', '๐Ÿฅฐ', '๐Ÿ˜˜', '๐Ÿ˜—', '๐Ÿ˜™', '๐Ÿ˜š', '๐Ÿ™‚', '๐Ÿค—', '๐Ÿคฉ', '๐Ÿค”', + '๐Ÿคจ', '๐Ÿ˜', '๐Ÿ˜‘', '๐Ÿ˜ถ', '๐Ÿ™„', '๐Ÿ˜', '๐Ÿ˜’', '๐Ÿ™ƒ', '๐Ÿ˜ฌ', '๐Ÿค', + '๐Ÿ˜ด', '๐Ÿ˜ช', '๐Ÿ˜ต', '๐Ÿคฏ', '๐Ÿคช', '๐Ÿ˜œ', '๐Ÿ˜', '๐Ÿ˜›', '๐Ÿคค', '๐Ÿ˜‹', + '๐Ÿ˜Ž', '๐Ÿค“', '๐Ÿง', '๐Ÿ˜•', '๐Ÿ˜Ÿ', '๐Ÿ™', 'โ˜น๏ธ', '๐Ÿ˜ฎ', '๐Ÿ˜ฏ', '๐Ÿ˜ฒ', + '๐Ÿ˜ณ', '๐Ÿฅบ', '๐Ÿ˜ฆ', '๐Ÿ˜ง', '๐Ÿ˜จ', '๐Ÿ˜ฐ', '๐Ÿ˜ฅ', '๐Ÿ˜ข', '๐Ÿ˜ญ', '๐Ÿ˜ฑ', + '๐Ÿ˜–', '๐Ÿ˜ฃ', '๐Ÿ˜ž', '๐Ÿ˜“', '๐Ÿ˜ฉ', '๐Ÿ˜ซ', '๐Ÿฅฑ', '๐Ÿ˜ค', '๐Ÿ˜ก', '๐Ÿ˜ ', + '๐Ÿคฌ', '๐Ÿ˜ˆ', '๐Ÿ‘ฟ', '๐Ÿ’€', 'โ˜ ๏ธ', '๐Ÿ’ฉ', '๐Ÿคก', '๐Ÿ‘น', '๐Ÿ‘บ', '๐Ÿ‘ป', + + // Gestures & Body + '๐Ÿ‘‹', '๐Ÿคš', '๐Ÿ–๏ธ', 'โœ‹', '๐Ÿ––', '๐Ÿ‘Œ', '๐ŸคŒ', '๐Ÿค', 'โœŒ๏ธ', '๐Ÿคž', + '๐ŸคŸ', '๐Ÿค˜', '๐Ÿค™', '๐Ÿ‘ˆ', '๐Ÿ‘‰', '๐Ÿ‘†', '๐Ÿ–•', '๐Ÿ‘‡', 'โ˜๏ธ', '๐Ÿ‘', + '๐Ÿ‘Ž', 'โœŠ', '๐Ÿ‘Š', '๐Ÿค›', '๐Ÿคœ', '๐Ÿ‘', '๐Ÿ™Œ', '๐Ÿ‘', '๐Ÿคฒ', '๐Ÿค', + '๐Ÿ™', '๐Ÿ’ช', '๐Ÿฆพ', '๐Ÿฆฟ', '๐Ÿฆต', '๐Ÿฆถ', '๐Ÿ‘‚', '๐Ÿฆป', '๐Ÿ‘ƒ', '๐Ÿง ', + + // Hearts & Love + 'โค๏ธ', '๐Ÿงก', '๐Ÿ’›', '๐Ÿ’š', '๐Ÿ’™', '๐Ÿ’œ', '๐Ÿ–ค', '๐Ÿค', '๐ŸคŽ', '๐Ÿ’”', + 'โฃ๏ธ', '๐Ÿ’•', '๐Ÿ’ž', '๐Ÿ’“', '๐Ÿ’—', '๐Ÿ’–', '๐Ÿ’˜', '๐Ÿ’', '๐Ÿ’Ÿ', 'โค๏ธโ€๐Ÿ”ฅ', + + // Work & Office + '๐Ÿ’ผ', '๐Ÿ“Š', '๐Ÿ“ˆ', '๐Ÿ“‰', '๐Ÿ’ป', 'โŒจ๏ธ', '๐Ÿ–ฅ๏ธ', '๐Ÿ–จ๏ธ', '๐Ÿ–ฑ๏ธ', '๐Ÿ’พ', + '๐Ÿ’ฟ', '๐Ÿ“ฑ', 'โ˜Ž๏ธ', '๐Ÿ“ž', '๐Ÿ“Ÿ', '๐Ÿ“ ', '๐Ÿ“ง', 'โœ‰๏ธ', '๐Ÿ“จ', '๐Ÿ“ฉ', + '๐Ÿ“ฎ', '๐Ÿ“ช', '๐Ÿ“ซ', '๐Ÿ“ฌ', '๐Ÿ“ญ', '๐Ÿ“„', '๐Ÿ“ƒ', '๐Ÿ“‘', '๐Ÿ“', 'โœ๏ธ', + 'โœ’๏ธ', '๐Ÿ–Š๏ธ', '๐Ÿ–‹๏ธ', '๐Ÿ“', '๐Ÿ“', '๐Ÿ“Œ', '๐Ÿ“', '๐Ÿ—‚๏ธ', '๐Ÿ“', '๐Ÿ“‚', + + // Success & Achievement + 'โœ…', 'โœ”๏ธ', 'โ˜‘๏ธ', '๐ŸŽฏ', '๐ŸŽ–๏ธ', '๐Ÿ†', '๐Ÿฅ‡', '๐Ÿฅˆ', '๐Ÿฅ‰', 'โญ', + '๐ŸŒŸ', 'โœจ', '๐Ÿ’ซ', '๐Ÿ”ฅ', '๐Ÿ’ฅ', 'โšก', '๐Ÿ’ฏ', '๐ŸŽ‰', '๐ŸŽŠ', '๐ŸŽˆ', + + // Alerts & Symbols + 'โš ๏ธ', '๐Ÿšซ', 'โŒ', 'โ›”', '๐Ÿšท', '๐Ÿšฏ', '๐Ÿšฑ', '๐Ÿšณ', '๐Ÿ”ž', '๐Ÿ“ต', + 'โ—', 'โ“', 'โ•', 'โ”', 'โ€ผ๏ธ', 'โ‰๏ธ', '๐Ÿ’ข', '๐Ÿ’ฌ', '๐Ÿ’ญ', '๐Ÿ—ฏ๏ธ', + + // Time & Calendar + 'โฐ', 'โฑ๏ธ', 'โฒ๏ธ', 'โณ', 'โŒ›', '๐Ÿ“…', '๐Ÿ“†', '๐Ÿ—“๏ธ', '๐Ÿ“‡', '๐Ÿ•', + '๐Ÿ•‘', '๐Ÿ•’', '๐Ÿ•“', '๐Ÿ•”', '๐Ÿ••', '๐Ÿ•–', '๐Ÿ•—', '๐Ÿ•˜', '๐Ÿ•™', '๐Ÿ•š', + + // Actions & Arrows + '๐Ÿš€', '๐ŸŽฏ', '๐ŸŽฒ', '๐ŸŽฐ', '๐Ÿงฉ', '๐Ÿ”', '๐Ÿ”Ž', '๐Ÿ”‘', '๐Ÿ—๏ธ', '๐Ÿ”’', + '๐Ÿ”“', '๐Ÿ”', '๐Ÿ”', '๐Ÿ””', '๐Ÿ”•', '๐Ÿ“ฃ', '๐Ÿ“ข', '๐Ÿ’ก', '๐Ÿ”ฆ', '๐Ÿฎ', + 'โž•', 'โž–', 'โœ–๏ธ', 'โž—', 'โ™พ๏ธ', 'โ€ผ๏ธ', 'โ‰๏ธ', 'โ“', 'โ”', 'โ•', + '๐Ÿ”„', '๐Ÿ”ƒ', '๐Ÿ”‚', 'โ–ถ๏ธ', 'โธ๏ธ', 'โฏ๏ธ', 'โน๏ธ', 'โบ๏ธ', 'โญ๏ธ', 'โฎ๏ธ', + 'โฉ', 'โช', 'โซ', 'โฌ', 'โ—€๏ธ', '๐Ÿ”ผ', '๐Ÿ”ฝ', 'โžก๏ธ', 'โฌ…๏ธ', 'โฌ†๏ธ', + 'โฌ‡๏ธ', 'โ†—๏ธ', 'โ†˜๏ธ', 'โ†™๏ธ', 'โ†–๏ธ', 'โ†•๏ธ', 'โ†”๏ธ', 'โ†ช๏ธ', 'โ†ฉ๏ธ', 'โคด๏ธ' + ]; + const extractMentions = (text: string): string[] => { const mentionRegex = /@([\w\s]+)(?=\s|$|[.,!?])/g; - const mentions = []; + const mentions: string[] = []; let match; while ((match = mentionRegex.exec(text)) !== null) { - mentions.push(match[1].trim()); + if (match[1]) { + mentions.push(match[1].trim()); + } } return mentions; }; @@ -392,8 +484,8 @@ export function WorkNoteChat({ requestId, onBack }: WorkNoteChatProps) { return (
- {/* Header */} -
+ {/* Header - Fixed at top */} +