11"use client" ;
22
3- import { ArrowRightIcon } from "lucide-react" ;
3+ import { ArrowRightIcon , UserIcon } from "lucide-react" ;
44import Link from "next/link" ;
55import { useCallback , useState } from "react" ;
66import type { Team } from "@/api/team" ;
7- import { Reasoning } from "@/components/chat/Reasoning " ;
7+ import { MarkdownRenderer } from "@/components/blocks/markdown-renderer " ;
88import { Button } from "@/components/ui/button" ;
9+ import { DynamicHeight } from "@/components/ui/DynamicHeight" ;
10+ import {
11+ Dialog ,
12+ DialogContent ,
13+ DialogHeader ,
14+ DialogTitle ,
15+ DialogTrigger ,
16+ } from "@/components/ui/dialog" ;
17+ import { TextShimmer } from "@/components/ui/text-shimmer" ;
918import { AutoResizeTextarea } from "@/components/ui/textarea" ;
10- import { cn } from "../../../../../../../../@/lib/utils" ;
1119import { ThirdwebMiniLogo } from "../../../../../../components/ThirdwebMiniLogo" ;
1220import { SupportTicketForm } from "./SupportTicketForm" ;
1321
@@ -131,104 +139,122 @@ export function CreateSupportCase(props: { team: Team; authToken: string }) {
131139 ) ;
132140
133141 const aiIcon = (
134- < div className = "rounded-full size-8 border bg-card shrink-0 flex items-center justify-center" >
135- < ThirdwebMiniLogo className = "size-4 text-foreground" isMonoChrome />
142+ < div className = "rounded-full size-9 border shrink-0 flex items-center justify-center bg-inverted" >
143+ < ThirdwebMiniLogo
144+ className = "size-4 text-inverted-foreground"
145+ isMonoChrome
146+ />
147+ </ div >
148+ ) ;
149+
150+ const userIcon = (
151+ < div className = "rounded-full size-9 border bg-muted/50 shrink-0 flex items-center justify-center" >
152+ < UserIcon className = "size-4 text-muted-foreground" />
136153 </ div >
137154 ) ;
138155
139156 return (
140- < div className = "flex flex-col grow bg-card border rounded-xl overflow-hidden" >
157+ < div className = "flex flex-col border bg-card rounded-xl mt-4" >
158+ < div className = "px-4 lg:px-12 py-6 lg:py-10 border-b border-dashed" >
159+ < h2 className = "text-xl lg:text-2xl font-semibold tracking-tight mb-0.5" >
160+ Chat with support
161+ </ h2 >
162+
163+ < p className = "text-muted-foreground text-sm md:text-base text-balance" >
164+ Describe your issue and we'll help you resolve it
165+ </ p >
166+ </ div >
141167 { /* Chat Messages */ }
142- < div className = "flex-1 overflow-y-auto space-y-10 pb-10 p-4" >
143- { chatMessages . map ( ( message , index ) => (
144- < div
145- key = { message . id }
146- className = { cn (
147- "flex" ,
148- message . isUser ? "justify-end" : "justify-start" ,
149- ) }
150- >
151- < div
152- className = { cn (
153- "max-w-[80%]" ,
154- message . isUser &&
155- "overflow-auto rounded-xl border bg-card px-4 py-2" ,
156- ) }
157- >
168+ < DynamicHeight >
169+ < div className = "flex-1 overflow-y-auto space-y-8 px-4 lg:px-12 pt-8 pb-20" >
170+ { chatMessages . map ( ( message , index ) => (
171+ < div key = { message . id } >
158172 { message . isUser ? (
159- < p className = "whitespace-pre-line text-sm md:text-base leading-loose md:leading-loose" >
160- { message . content }
161- </ p >
173+ < div className = "flex items-start gap-3.5" >
174+ { userIcon }
175+ < div className = "px-3.5 py-2 rounded-xl border bg-muted/50 relative" >
176+ < StyledMarkdownRenderer
177+ text = { message . content }
178+ type = "user"
179+ isMessagePending = { false }
180+ />
181+ </ div >
182+ </ div >
162183 ) : message . content === "__reasoning__" ? (
163- < div className = "flex items-start gap-3" >
184+ < div className = "flex items-center gap-3.5 " >
164185 { aiIcon }
165- < Reasoning isPending = { true } texts = { [ ] } />
186+ < TextShimmer
187+ text = "Reasoning..."
188+ className = "text-sm md:text-base"
189+ />
166190 </ div >
167191 ) : (
168- < div className = "flex items-start gap-3" >
192+ < div className = "flex items-start gap-3.5 " >
169193 { aiIcon }
170194 < div >
171- < p className = "whitespace-pre-line leading-loose md:leading-loose text-sm md:text-base" >
172- { message . content }
173- </ p >
195+ < StyledMarkdownRenderer
196+ text = { message . content }
197+ type = "assistant"
198+ isMessagePending = { false }
199+ />
174200
175201 { /* Show Create Support Case button in the AI response - only if form not shown and after user interaction */ }
176202 { index === chatMessages . length - 1 &&
177- ! showCreateForm &&
178203 ! message . isSuccessMessage &&
179204 chatMessages . length > 2 && (
180- < div className = "mt-3" >
181- < Button
182- onClick = { ( ) => setShowCreateForm ( true ) }
183- size = "sm"
184- className = "gap-2"
185- >
186- Create Support Case
187- < ArrowRightIcon className = "w-4 h-4" />
188- </ Button >
189- </ div >
190- ) }
191-
192- { /* Show Support Case Form in the same message bubble when button is clicked */ }
193- { ! message . isUser &&
194- index === chatMessages . length - 1 &&
195- showCreateForm &&
196- message . content !== "__reasoning__" && (
197- < div className = "border p-4 rounded-lg bg-card mt-4" >
198- < h3 className = "text-lg font-semibold text-foreground mb-0.5" >
199- Create Support Case
200- </ h3 >
201- < p className = "text-sm text-muted-foreground mb-3" >
202- Let's create a detailed support case for our
203- technical team.
204- </ p >
205+ < div className = "mt-5" >
206+ < Dialog >
207+ < DialogTrigger asChild >
208+ < Button
209+ size = "sm"
210+ variant = "outline"
211+ className = "gap-2 rounded-full bg-background"
212+ >
213+ Create Support Case
214+ < ArrowRightIcon className = "w-4 h-4" />
215+ </ Button >
216+ </ DialogTrigger >
217+ < DialogContent className = "p-0 bg-card" >
218+ < DynamicHeight >
219+ < DialogHeader className = "p-4 lg:p-6 border-b border-dashed space-y-1" >
220+ < DialogTitle className = "text-xl font-semibold text-foreground tracking-tight" >
221+ Create Support Case
222+ </ DialogTitle >
223+ < p className = "text-muted-foreground text-sm" >
224+ Let's create a detailed support case for our
225+ technical team.
226+ </ p >
227+ </ DialogHeader >
205228
206- < SupportTicketForm
207- team = { team }
208- productLabel = { productLabel }
209- setProductLabel = { setProductLabel }
210- conversationId = { conversationId }
211- onSuccess = { ( ) => {
212- setShowCreateForm ( false ) ;
213- setProductLabel ( "" ) ;
214- setChatMessages ( ( prev ) => [
215- ...prev ,
216- {
217- id : Date . now ( ) ,
218- content : `Support case created successfully!\n\nYour case has been submitted to our technical team. You'll receive updates via email at ${ team . billingEmail } .\n\nYou can track your case in the support portal above.` ,
219- isUser : false ,
220- timestamp : new Date ( ) . toISOString ( ) ,
221- isSuccessMessage : true ,
222- } ,
223- ] ) ;
224- } }
225- />
229+ < SupportTicketForm
230+ team = { team }
231+ productLabel = { productLabel }
232+ setProductLabel = { setProductLabel }
233+ conversationId = { conversationId }
234+ onSuccess = { ( ) => {
235+ setShowCreateForm ( false ) ;
236+ setProductLabel ( "" ) ;
237+ setChatMessages ( ( prev ) => [
238+ ...prev ,
239+ {
240+ id : Date . now ( ) ,
241+ content : `Support case created successfully!\n\nYour case has been submitted to our technical team. You'll receive updates via email at ${ team . billingEmail } .\n\nYou can track your case in the support portal above.` ,
242+ isUser : false ,
243+ timestamp : new Date ( ) . toISOString ( ) ,
244+ isSuccessMessage : true ,
245+ } ,
246+ ] ) ;
247+ } }
248+ />
249+ </ DynamicHeight >
250+ </ DialogContent >
251+ </ Dialog >
226252 </ div >
227253 ) }
228254
229255 { /* Show Back to Support button for success message */ }
230256 { ! message . isUser && message . isSuccessMessage && (
231- < div className = "mt-3 " >
257+ < div className = "mt-5 " >
232258 < Button asChild size = "sm" className = "gap-2" >
233259 < Link href = { `/team/${ team . slug } /~/support` } >
234260 View all cases
@@ -241,20 +267,20 @@ export function CreateSupportCase(props: { team: Team; authToken: string }) {
241267 </ div >
242268 ) }
243269 </ div >
244- </ div >
245- ) ) }
246- </ div >
270+ ) ) }
271+ </ div >
272+ </ DynamicHeight >
247273
248274 { /* Chat Input */ }
249275 { ! showCreateForm && (
250- < div className = "border-t " >
276+ < div className = "px-4 lg:px-12 pb-12 " >
251277 < div className = "relative" >
252278 < AutoResizeTextarea
253279 placeholder = "I am having an issue with..."
254280 value = { chatInput }
255281 onChange = { ( e ) => setChatInput ( e . target . value ) }
256282 onKeyDown = { handleChatKeyPress }
257- className = "min-h-[120px] border-none "
283+ className = "min-h-[120px] rounded-xl "
258284 />
259285 < Button
260286 onClick = { handleChatSend }
@@ -271,3 +297,26 @@ export function CreateSupportCase(props: { team: Team; authToken: string }) {
271297 </ div >
272298 ) ;
273299}
300+
301+ function StyledMarkdownRenderer ( props : {
302+ text : string ;
303+ isMessagePending : boolean ;
304+ type : "assistant" | "user" ;
305+ } ) {
306+ return (
307+ < MarkdownRenderer
308+ className = "text-sm md:text-base text-foreground [&>*:first-child]:mt-0 [&>*:first-child]:border-none [&>*:first-child]:pb-0 [&>*:last-child]:mb-0 leading-relaxed"
309+ code = { {
310+ className : "bg-transparent" ,
311+ ignoreFormattingErrors : true ,
312+ } }
313+ inlineCode = { { className : "border-none" } }
314+ li = { { className : "text-foreground leading-relaxed" } }
315+ markdownText = { props . text }
316+ p = { {
317+ className : "text-foreground leading-relaxed" ,
318+ } }
319+ skipHtml
320+ />
321+ ) ;
322+ }
0 commit comments