HelpOptionsList.tsx 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. import { Activity, BookOpen, ChevronRight, Mail, Wrench } from 'lucide-react'
  2. import { useRouter } from 'next/router'
  3. import type { ReactNode } from 'react'
  4. import SVG from 'react-inlinesvg'
  5. import { AiIconAnimation } from 'ui'
  6. import type { HelpOptionId } from './HelpPanel.constants'
  7. import { HELP_OPTION_IDS } from './HelpPanel.constants'
  8. import type { SupportFormUrlKeys } from '@/components/interfaces/Support/SupportForm.utils'
  9. import { createSupportFormUrl } from '@/components/interfaces/Support/SupportForm.utils'
  10. import { ResourceItem } from '@/components/ui/Resource/ResourceItem'
  11. import { ResourceList } from '@/components/ui/Resource/ResourceList'
  12. import { takeBreadcrumbSnapshot } from '@/lib/breadcrumbs'
  13. import { DOCS_URL } from '@/lib/constants'
  14. const DISCORD_URL = 'https://discord.supabase.com'
  15. const STATUS_URL = 'https://status.supabase.com'
  16. type HelpOptionsListProps = {
  17. excludeIds?: HelpOptionId[]
  18. isPlatform: boolean
  19. projectRef: string | undefined
  20. supportLinkQueryParams: Partial<SupportFormUrlKeys> | undefined
  21. onAssistantClick?: () => void
  22. onSupportClick?: () => boolean | void
  23. }
  24. type HelpOption = {
  25. media: ReactNode
  26. title: string
  27. description: string
  28. href?: string
  29. onClick?: () => void
  30. }
  31. export const HelpOptionsList = ({
  32. excludeIds = [],
  33. isPlatform,
  34. projectRef,
  35. supportLinkQueryParams,
  36. onAssistantClick,
  37. onSupportClick,
  38. }: HelpOptionsListProps) => {
  39. const router = useRouter()
  40. const basePath = router.basePath ?? ''
  41. const ids = HELP_OPTION_IDS.filter((id) => !excludeIds.includes(id))
  42. const include = (id: HelpOptionId): boolean => {
  43. if (id === 'assistant') return !!projectRef
  44. if (id === 'status' || id === 'support') return isPlatform
  45. return true
  46. }
  47. const filteredIds = ids.filter(include)
  48. const handleSupportClick = () => {
  49. const shouldNavigate = onSupportClick?.()
  50. if (shouldNavigate === false) {
  51. return
  52. }
  53. takeBreadcrumbSnapshot()
  54. router.push(createSupportFormUrl(supportLinkQueryParams ?? {}))
  55. }
  56. const renderOption = (title: string, description: string) => (
  57. <div className="flex flex-col gap-0.5">
  58. <p className="text-sm text-foreground">{title}</p>
  59. <p className="text-xs text-foreground-lighter">{description}</p>
  60. </div>
  61. )
  62. const options: Record<HelpOptionId, HelpOption> = {
  63. assistant: {
  64. media: <AiIconAnimation allowHoverEffect size={14} />,
  65. title: 'Briven Assistant',
  66. description: 'Get guided help with your project directly in Studio.',
  67. onClick: onAssistantClick,
  68. },
  69. docs: {
  70. media: <BookOpen strokeWidth={1.5} size={14} />,
  71. title: 'Docs',
  72. description: 'Browse guides, references, and product documentation.',
  73. href: `${DOCS_URL}/`,
  74. },
  75. troubleshooting: {
  76. media: <Wrench strokeWidth={1.5} size={14} />,
  77. title: 'Troubleshooting',
  78. description: 'Find fixes for common platform issues and errors.',
  79. href: `${DOCS_URL}/guides/troubleshooting?products=platform`,
  80. },
  81. discord: {
  82. media: <SVG src={`${basePath}/img/discord-icon.svg`} className="h-4 w-4" />,
  83. title: 'Ask on Discord',
  84. description: 'Get help from the community on code-related questions.',
  85. href: DISCORD_URL,
  86. },
  87. status: {
  88. media: <Activity strokeWidth={1.5} size={14} />,
  89. title: 'Briven status',
  90. description: 'Check incidents, maintenance, and uptime updates.',
  91. href: STATUS_URL,
  92. },
  93. support: {
  94. media: <Mail strokeWidth={1.5} size={14} />,
  95. title: 'Contact support',
  96. description: 'Reach support for account and platform issues.',
  97. onClick: handleSupportClick,
  98. },
  99. }
  100. return (
  101. <ResourceList className="rounded-none border-0 bg-transparent shadow-none">
  102. {filteredIds.map((id) => {
  103. const option = options[id]
  104. if (option.href) {
  105. return (
  106. <ResourceItem
  107. key={id}
  108. className="!border-b"
  109. media={option.media}
  110. meta={<ChevronRight strokeWidth={1.5} size={16} />}
  111. href={option.href}
  112. target="_blank"
  113. rel="noreferrer noopener"
  114. >
  115. {renderOption(option.title, option.description)}
  116. </ResourceItem>
  117. )
  118. }
  119. return (
  120. <ResourceItem
  121. key={id}
  122. className="!border-b"
  123. media={option.media}
  124. onClick={option.onClick}
  125. >
  126. {renderOption(option.title, option.description)}
  127. </ResourceItem>
  128. )
  129. })}
  130. </ResourceList>
  131. )
  132. }