|
1 | | -import { Loader2, Maximize2, MessageSquare, Minimize2, Send, X } from 'lucide-react'; |
| 1 | +import { Loader2, MessageSquare, Send, X } from 'lucide-react'; |
2 | 2 | import React, { ChangeEvent, KeyboardEvent, useEffect, useRef, useState } from 'react'; |
3 | 3 |
|
4 | 4 | import { Alert, AlertDescription } from '@/components/ui/alert'; |
@@ -28,7 +28,6 @@ export const ChatLayout: React.FC<ChatLayoutProps> = ({ |
28 | 28 | title, |
29 | 29 | }) => { |
30 | 30 | const [input, setInput] = useState<string>(''); |
31 | | - const [isExpanded, setIsExpanded] = useState<boolean>(false); |
32 | 31 | const inputRef = useRef<HTMLInputElement>(null); |
33 | 32 | const messagesEndRef = useRef<HTMLDivElement>(null); |
34 | 33 |
|
@@ -62,85 +61,62 @@ export const ChatLayout: React.FC<ChatLayoutProps> = ({ |
62 | 61 | }; |
63 | 62 |
|
64 | 63 | return ( |
65 | | - <div |
66 | | - className={`fixed right-0 top-14 h-[calc(100%-3.5rem)] bg-white shadow-xl transition-all duration-300 ease-in-out ${ |
67 | | - isOpen ? 'translate-x-0' : 'translate-x-full' |
68 | | - } ${isExpanded ? 'w-3/4' : 'w-1/5'}`} |
69 | | - > |
70 | | - <div className='flex h-full flex-col'> |
71 | | - <div className='flex items-center justify-between border-b bg-white px-4 py-3'> |
72 | | - <div className='flex items-center gap-2'> |
73 | | - <MessageSquare className='size-5 text-blue-500' /> |
74 | | - <h2 className='text-base font-semibold'>{title}</h2> |
75 | | - </div> |
76 | | - <div className='flex items-center gap-2'> |
77 | | - <Button |
78 | | - variant='ghost' |
79 | | - size='icon' |
80 | | - onClick={() => setIsExpanded(!isExpanded)} |
81 | | - className='rounded-full hover:bg-gray-100' |
82 | | - > |
83 | | - {isExpanded ? <Minimize2 className='size-5' /> : <Maximize2 className='size-5' />} |
84 | | - </Button> |
85 | | - <Button |
86 | | - variant='ghost' |
87 | | - size='icon' |
88 | | - onClick={onClose} |
89 | | - className='rounded-full hover:bg-gray-100' |
90 | | - > |
91 | | - <X className='size-5' /> |
92 | | - </Button> |
93 | | - </div> |
| 64 | + <div className='flex size-full flex-col'> |
| 65 | + <div className='bg-secondary/50 flex items-center justify-between border-b px-4 py-3'> |
| 66 | + <div className='flex items-center gap-2'> |
| 67 | + <h2 className='font-semibold'>{title}</h2> |
94 | 68 | </div> |
| 69 | + <div className='flex items-center gap-2'> |
| 70 | + <Button |
| 71 | + variant='ghost' |
| 72 | + size='icon' |
| 73 | + onClick={onClose} |
| 74 | + className='rounded-full hover:bg-gray-100' |
| 75 | + > |
| 76 | + <X className='size-5' /> |
| 77 | + </Button> |
| 78 | + </div> |
| 79 | + </div> |
95 | 80 |
|
96 | | - <ScrollArea className='flex-1 overflow-y-auto p-4'> |
97 | | - {messages.length === 0 && ( |
98 | | - <div className='flex h-full flex-col items-center justify-center text-gray-500'> |
99 | | - <MessageSquare className='mb-4 size-12 opacity-50' /> |
100 | | - <p className='text-center'>No messages yet. Start a conversation!</p> |
101 | | - </div> |
102 | | - )} |
103 | | - {messages.map((msg, index) => ( |
104 | | - <ChatMessage key={index} message={msg} /> |
105 | | - ))} |
106 | | - {isLoading && ( |
107 | | - <div className='mb-4 flex justify-start'> |
108 | | - <div className='rounded-lg bg-gray-50 px-4 py-2'> |
109 | | - <Loader2 className='size-5 animate-spin text-gray-500' /> |
110 | | - </div> |
| 81 | + <ScrollArea className='h-full flex-1 overflow-y-auto p-4'> |
| 82 | + {messages.length === 0 && ( |
| 83 | + <div className='flex h-full flex-col items-center justify-center text-gray-500'> |
| 84 | + <MessageSquare className='mb-4 size-12 opacity-50' /> |
| 85 | + <p className='text-center'>No messages yet. Start a conversation!</p> |
| 86 | + </div> |
| 87 | + )} |
| 88 | + {messages.map((msg, index) => ( |
| 89 | + <ChatMessage key={index} message={msg} /> |
| 90 | + ))} |
| 91 | + {isLoading && ( |
| 92 | + <div className='mb-4 flex justify-start'> |
| 93 | + <div className='rounded-lg bg-gray-50 px-4 py-2'> |
| 94 | + <Loader2 className='size-5 animate-spin text-gray-500' /> |
111 | 95 | </div> |
112 | | - )} |
113 | | - {error && ( |
114 | | - <Alert variant='destructive' className='mb-4'> |
115 | | - <AlertDescription>{error}</AlertDescription> |
116 | | - </Alert> |
117 | | - )} |
118 | | - <div ref={messagesEndRef} /> |
119 | | - </ScrollArea> |
120 | | - |
121 | | - <div className='border-t bg-white p-4'> |
122 | | - <div className='flex gap-2'> |
123 | | - <Input |
124 | | - ref={inputRef} |
125 | | - value={input} |
126 | | - onChange={(e: ChangeEvent<HTMLInputElement>) => setInput(e.target.value)} |
127 | | - placeholder='Type your message...' |
128 | | - onKeyPress={handleKeyPress} |
129 | | - disabled={isLoading} |
130 | | - className='flex-1' |
131 | | - /> |
132 | | - <Button |
133 | | - onClick={handleSend} |
134 | | - disabled={isLoading || !input.trim()} |
135 | | - className='bg-blue-500 hover:bg-blue-600' |
136 | | - > |
137 | | - {isLoading ? ( |
138 | | - <Loader2 className='size-4 animate-spin' /> |
139 | | - ) : ( |
140 | | - <Send className='size-4' /> |
141 | | - )} |
142 | | - </Button> |
143 | 96 | </div> |
| 97 | + )} |
| 98 | + {error && ( |
| 99 | + <Alert variant='destructive' className='mb-4'> |
| 100 | + <AlertDescription>{error}</AlertDescription> |
| 101 | + </Alert> |
| 102 | + )} |
| 103 | + <div ref={messagesEndRef} /> |
| 104 | + </ScrollArea> |
| 105 | + |
| 106 | + <div className='bg-secondary/50 border p-4'> |
| 107 | + <div className='flex gap-2'> |
| 108 | + <Input |
| 109 | + ref={inputRef} |
| 110 | + value={input} |
| 111 | + onChange={(e: ChangeEvent<HTMLInputElement>) => setInput(e.target.value)} |
| 112 | + placeholder='Type your message...' |
| 113 | + onKeyPress={handleKeyPress} |
| 114 | + disabled={isLoading} |
| 115 | + className='bg-primary-foreground flex-1' |
| 116 | + /> |
| 117 | + <Button variant='outline' onClick={handleSend} disabled={isLoading || !input.trim()}> |
| 118 | + {isLoading ? <Loader2 className='size-4 animate-spin' /> : <Send className='size-4' />} |
| 119 | + </Button> |
144 | 120 | </div> |
145 | 121 | </div> |
146 | 122 | </div> |
|
0 commit comments