|
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