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