AIAssistantOption.tsx115 lines · main
1// @ts-nocheck
2import { AnimatePresence, motion } from 'framer-motion'
3import { MessageSquare } from 'lucide-react'
4import Link from 'next/link'
5import { useCallback, useEffect, useState } from 'react'
6import { AiIconAnimation, Button } from 'ui'
7
8import { NO_ORG_MARKER, NO_PROJECT_MARKER } from './SupportForm.utils'
9import { useSendEventMutation } from '@/data/telemetry/send-event-mutation'
10
11interface AIAssistantOptionProps {
12 projectRef?: string | null
13 organizationSlug?: string | null
14 onClick?: () => void
15}
16
17export const AIAssistantOption = ({
18 projectRef,
19 organizationSlug,
20 onClick,
21}: AIAssistantOptionProps) => {
22 const { mutate: sendEvent } = useSendEventMutation()
23 const [isVisible, setIsVisible] = useState(false)
24
25 useEffect(() => {
26 const timer = setTimeout(() => setIsVisible(true), 800)
27 return () => clearTimeout(timer)
28 }, [])
29
30 const onAiAssistantClicked = useCallback(() => {
31 sendEvent({
32 action: 'ai_assistant_in_support_form_clicked',
33 groups: {
34 project: projectRef === null || projectRef === NO_PROJECT_MARKER ? undefined : projectRef,
35 organization:
36 organizationSlug === null || organizationSlug === NO_ORG_MARKER
37 ? undefined
38 : organizationSlug,
39 },
40 })
41
42 onClick?.()
43 }, [onClick, projectRef, organizationSlug, sendEvent])
44
45 // If no specific project selected, use the wildcard route
46 const aiLink = `/project/${projectRef !== NO_PROJECT_MARKER ? projectRef : '_'}?sidebar=ai-assistant&slug=${organizationSlug}`
47
48 if (!organizationSlug || organizationSlug === NO_ORG_MARKER) return null
49
50 return (
51 <AnimatePresence>
52 {isVisible && (
53 <motion.aside
54 initial={{ height: 0, opacity: 0 }}
55 animate={{ height: 'auto', opacity: 1 }}
56 exit={{ height: 0, opacity: 0 }}
57 className="w-full overflow-hidden border rounded-md relative bg-200"
58 >
59 <div className="flex items-center p-6">
60 <div className="flex flex-col gap-3 z-2 shrink-0 w-full">
61 <div>
62 <h5 className="text-sm font-medium text-foreground">Try Briven Assistant</h5>
63 <p className="text-sm text-foreground-lighter">
64 Ask our AI assistant to help you with your support issue.
65 </p>
66 </div>
67 <div>
68 {onClick ? (
69 <Button
70 size="tiny"
71 type="default"
72 icon={<AiIconAnimation size={14} />}
73 onClick={onAiAssistantClicked}
74 >
75 Ask the Assistant
76 </Button>
77 ) : (
78 <Link href={aiLink} onClick={onAiAssistantClicked}>
79 <Button size="tiny" type="default" icon={<AiIconAnimation size={14} />}>
80 Ask the Assistant
81 </Button>
82 </Link>
83 )}
84 </div>
85 </div>
86 {/* Decorative background */}
87 <div className="absolute z-1 scale-75 -right-40 md:-right-24 -top-6 md:top-0">
88 <div className="relative grow flex flex-col gap-3 w-[400px]">
89 <div className="flex items-start gap-3 pl-12">
90 <div className="w-8 h-8 rounded-full bg-background-surface-300 flex items-center justify-center">
91 <MessageSquare size={16} className="text-foreground-lighter" />
92 </div>
93 <div className="flex-1 bg-background-surface-200 rounded-lg p-4 max-w-[280px]">
94 <p className="text-sm text-foreground-lighter">
95 Hi! I'm your AI assistant. How can I help you today?
96 </p>
97 </div>
98 </div>
99 <div className="flex items-start justify-end gap-3 pr-10">
100 <div className="bg-background-surface-200 rounded-lg p-4 max-w-[280px]">
101 <p className="text-sm text-foreground-lighter">
102 I can help you with database queries, API endpoints, or any other technical
103 questions you might have.
104 </p>
105 </div>
106 </div>
107 </div>
108 <div className="absolute -inset-2 bg-linear-to-l from-transparent via-background-200 via-90% to-background-200 to-100% z-1" />
109 </div>
110 </div>
111 </motion.aside>
112 )}
113 </AnimatePresence>
114 )
115}