FeedbackDropdown.tsx 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. import { IS_PLATFORM } from 'common'
  2. import { Lightbulb, TriangleAlert } from 'lucide-react'
  3. import { useRouter } from 'next/router'
  4. import { useState } from 'react'
  5. import { Button, Popover, PopoverContent, PopoverSeparator, PopoverTrigger } from 'ui'
  6. import { FeedbackWidget } from './FeedbackWidget'
  7. import { SIDEBAR_KEYS } from '@/components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider'
  8. import { ASSISTANT_SUGGESTIONS } from '@/components/ui/HelpPanel/HelpPanel.constants'
  9. import { getSupportLinkQueryParams } from '@/components/ui/HelpPanel/HelpPanel.utils'
  10. import { HelpSection } from '@/components/ui/HelpPanel/HelpSection'
  11. import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization'
  12. import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
  13. import { useTrack } from '@/lib/telemetry/track'
  14. import { useAiAssistantStateSnapshot } from '@/state/ai-assistant-state'
  15. import { useSidebarManagerSnapshot } from '@/state/sidebar-manager-state'
  16. export const FeedbackDropdown = ({ className }: { className?: string }) => {
  17. const router = useRouter()
  18. const { data: project } = useSelectedProjectQuery()
  19. const { data: org } = useSelectedOrganizationQuery()
  20. const snap = useAiAssistantStateSnapshot()
  21. const { openSidebar } = useSidebarManagerSnapshot()
  22. const [isOpen, setIsOpen] = useState(false)
  23. const [stage, setStage] = useState<'select' | 'issue-options' | 'widget'>('select')
  24. const track = useTrack()
  25. const projectRef = project?.parent_project_ref ?? (router.query.ref as string | undefined)
  26. const supportLinkQueryParams = getSupportLinkQueryParams(
  27. project,
  28. org,
  29. router.query.ref as string | undefined
  30. )
  31. return (
  32. <Popover
  33. modal={false}
  34. open={isOpen}
  35. onOpenChange={(e) => {
  36. if (e) track('header_feedback_dropdown_opened')
  37. setIsOpen(e)
  38. if (!e) setStage('select')
  39. }}
  40. >
  41. <PopoverTrigger asChild>
  42. <Button
  43. asChild
  44. onClick={() => {
  45. setIsOpen((isOpen) => !isOpen)
  46. setStage('select')
  47. }}
  48. type="text"
  49. className="rounded-full h-[32px] text-foreground-light hover:text-foreground"
  50. >
  51. <span className={className}>Feedback</span>
  52. </Button>
  53. </PopoverTrigger>
  54. <PopoverContent
  55. side="bottom"
  56. align="end"
  57. className="p-0 flex flex-col w-96"
  58. id="feedback-widget"
  59. >
  60. {stage === 'select' && (
  61. <div className="flex flex-col gap-4 p-4">
  62. <div className="font-medium text-sm">What would you like to share?</div>
  63. <div className="grid grid-cols-2 gap-3">
  64. <Button type="default" className="h-32" onClick={() => setStage('issue-options')}>
  65. <div className="grid gap-1.5 text-center">
  66. <TriangleAlert size="28" className="mx-auto text-destructive-600" />
  67. <div className="flex flex-col items-center">
  68. <span className="text-base">Issue</span>
  69. <span className="text-xs text-foreground-lighter">with my project</span>
  70. </div>
  71. </div>
  72. </Button>
  73. <Button type="default" className="h-32" onClick={() => setStage('widget')}>
  74. <div className="grid gap-1.5 text-center">
  75. <Lightbulb size="28" className="mx-auto text-warning" />
  76. <div className="flex flex-col items-center">
  77. <span className="text-base">Idea</span>
  78. <span className="text-xs text-foreground-lighter">to improve Briven</span>
  79. </div>
  80. </div>
  81. </Button>
  82. </div>
  83. </div>
  84. )}
  85. {stage === 'issue-options' && (
  86. <>
  87. <div className="flex flex-col gap-4 p-4">
  88. <HelpSection
  89. excludeIds={[]}
  90. isPlatform={IS_PLATFORM}
  91. projectRef={projectRef}
  92. supportLinkQueryParams={supportLinkQueryParams}
  93. onAssistantClick={() => {
  94. openSidebar(SIDEBAR_KEYS.AI_ASSISTANT)
  95. snap.newChat(ASSISTANT_SUGGESTIONS)
  96. setIsOpen(false)
  97. }}
  98. onSupportClick={() => setIsOpen(false)}
  99. />
  100. </div>
  101. <PopoverSeparator />
  102. <div className="px-4 pt-4 pb-4">
  103. <Button type="default" size="tiny" onClick={() => setStage('widget')}>
  104. Leave feedback instead
  105. </Button>
  106. </div>
  107. </>
  108. )}
  109. {stage === 'widget' && (
  110. <FeedbackWidget
  111. onClose={() => setIsOpen(false)}
  112. onSwitchToIssueOptions={() => setStage('issue-options')}
  113. />
  114. )}
  115. </PopoverContent>
  116. </Popover>
  117. )
  118. }