AIAssistantOption.tsx 4.4 KB

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