SupportSidebarForm.tsx154 lines · main
1// @ts-nocheck
2import * as Sentry from '@sentry/nextjs'
3import { Loader2 } from 'lucide-react'
4import Link from 'next/link'
5import { useCallback, useReducer } from 'react'
6import { toast } from 'sonner'
7import { Button, cn, Tooltip, TooltipContent, TooltipTrigger } from 'ui'
8
9import { IncidentAdmonition } from './IncidentAdmonition'
10import { Success } from './Success'
11import type { ExtendedSupportCategories } from './Support.constants'
12import { createInitialSupportFormState, supportFormReducer } from './SupportForm.state'
13import type { SupportFormUrlKeys } from './SupportForm.utils'
14import { SupportFormV3 } from './SupportFormV3'
15import { useSupportForm } from './useSupportForm'
16import { useIncidentStatusQuery } from '@/data/platform/incident-status-query'
17import { useSendEventMutation } from '@/data/telemetry/send-event-mutation'
18import { useStateTransition } from '@/hooks/misc/useStateTransition'
19
20function useSupportFormTelemetry() {
21 const { mutate: sendEvent } = useSendEventMutation()
22
23 return useCallback(
24 ({
25 projectRef,
26 orgSlug,
27 category,
28 }: {
29 projectRef: string | undefined
30 orgSlug: string | undefined
31 category: ExtendedSupportCategories
32 }) =>
33 sendEvent({
34 action: 'support_ticket_submitted',
35 properties: {
36 ticketCategory: category,
37 },
38 groups: {
39 project: projectRef,
40 organization: orgSlug,
41 },
42 }),
43 [sendEvent]
44 )
45}
46
47interface SupportFormProps {
48 initialParams?: Partial<SupportFormUrlKeys>
49 onFinish?: () => void
50}
51
52export function SupportForm({ initialParams, onFinish }: SupportFormProps) {
53 const [state, dispatch] = useReducer(supportFormReducer, undefined, createInitialSupportFormState)
54 const { form, initialError, projectRef } = useSupportForm(dispatch, initialParams)
55
56 const {
57 data: allStatusPageEvents,
58 isPending: isIncidentsPending,
59 isError: isIncidentsError,
60 } = useIncidentStatusQuery()
61 const { incidents = [] } = allStatusPageEvents ?? {}
62 const hasActiveIncidents =
63 !isIncidentsPending && !isIncidentsError && incidents && incidents.length > 0
64
65 const sendTelemetry = useSupportFormTelemetry()
66 useStateTransition(state, 'submitting', 'success', (_, curr) => {
67 toast.success('Support request sent. Thank you!')
68 sendTelemetry({
69 projectRef: curr.sentProjectRef,
70 orgSlug: curr.sentOrgSlug,
71 category: curr.sentCategory,
72 })
73 })
74
75 useStateTransition(state, 'submitting', 'error', (_, curr) => {
76 toast.error(`Failed to submit support ticket: ${curr.message}`)
77 Sentry.captureMessage(`Failed to submit Support Form: ${curr.message}`)
78 dispatch({ type: 'RETURN_TO_EDITING' })
79 })
80
81 const isSuccess = state.type === 'success'
82
83 return (
84 <div className="relative h-full overflow-y-auto overflow-x-hidden">
85 <IncidentAdmonition
86 isActive={hasActiveIncidents}
87 className="rounded-none border-x-0 shadow-none"
88 />
89 <div className="min-h-full px-5 pt-5">
90 <div className="flex flex-col gap-y-8">
91 {isSuccess ? (
92 <div className="pt-2">
93 <Success
94 selectedProject={projectRef ?? undefined}
95 sentCategory={state.sentCategory}
96 onFinish={onFinish}
97 finishLabel={onFinish ? 'Done' : undefined}
98 />
99 </div>
100 ) : (
101 <SupportFormV3
102 form={form}
103 initialError={initialError}
104 state={state}
105 dispatch={dispatch}
106 selectedProjectRef={projectRef}
107 />
108 )}
109 </div>
110 </div>
111 </div>
112 )
113}
114
115export function SupportFormStatusButton() {
116 const { data: allStatusPageEvents, isPending: isLoading, isError } = useIncidentStatusQuery()
117 const { incidents = [], maintenanceEvents = [] } = allStatusPageEvents ?? {}
118 const isMaintenance = maintenanceEvents.length > 0
119 const isIncident = incidents.length > 0
120
121 return (
122 <Tooltip>
123 <TooltipTrigger asChild>
124 <Button
125 asChild
126 type="default"
127 size="tiny"
128 icon={
129 isLoading ? (
130 <Loader2 className="animate-spin" />
131 ) : (
132 <div className={cn('h-2 w-2 rounded-full', isIncident ? 'bg-warning' : 'bg-brand')} />
133 )
134 }
135 >
136 <Link href="https://status.supabase.com/" target="_blank" rel="noreferrer">
137 {isLoading
138 ? 'Checking status'
139 : isError
140 ? 'Failed to check status'
141 : isIncident
142 ? 'Active incident ongoing'
143 : isMaintenance
144 ? 'Scheduled maintenance'
145 : 'All systems operational'}
146 </Link>
147 </Button>
148 </TooltipTrigger>
149 <TooltipContent side="bottom" align="center">
150 Check the Briven status page
151 </TooltipContent>
152 </Tooltip>
153 )
154}