SupportSidebarForm.tsx 4.9 KB

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