ConnectSection.tsx 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. import { IS_PLATFORM } from 'common'
  2. import { ChevronRight } from 'lucide-react'
  3. import { useRouter } from 'next/router'
  4. import { parseAsBoolean, parseAsString, useQueryState } from 'nuqs'
  5. import { useEffect, useRef } from 'react'
  6. import { Card, CardContent, cn } from 'ui'
  7. import { useAvailableConnectModes } from '../ConnectSheet/useAvailableConnectModes'
  8. import { CONNECT_ACTIONS } from './ConnectSection.config'
  9. import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
  10. import { BASE_PATH, PROJECT_STATUS } from '@/lib/constants'
  11. import { useTrack } from '@/lib/telemetry/track'
  12. import { useAppStateSnapshot } from '@/state/app-state'
  13. export const ConnectSection = () => {
  14. const router = useRouter()
  15. const { data: selectedProject } = useSelectedProjectQuery()
  16. const { setConnectSheetSource } = useAppStateSnapshot()
  17. const track = useTrack()
  18. const [, setShowConnect] = useQueryState('showConnect', parseAsBoolean.withDefault(false))
  19. const [, setConnectTab] = useQueryState('connectTab', parseAsString)
  20. const isActiveHealthy = selectedProject?.status === PROJECT_STATUS.ACTIVE_HEALTHY
  21. const availableModeIds = useAvailableConnectModes()
  22. const availableActions = CONNECT_ACTIONS.filter((action) =>
  23. action.mode ? availableModeIds.includes(action.mode) : true
  24. )
  25. const hasTrackedExposure = useRef(false)
  26. useEffect(() => {
  27. if (!IS_PLATFORM) return
  28. if (hasTrackedExposure.current) return
  29. hasTrackedExposure.current = true
  30. track('home_connect_section_exposed')
  31. }, [track])
  32. const handleActionClick = (action: (typeof CONNECT_ACTIONS)[number]) => {
  33. track('home_connect_action_clicked', { mode: action.id })
  34. if (action.mode) {
  35. setConnectTab(action.mode)
  36. setConnectSheetSource('connect_section')
  37. setShowConnect(true)
  38. return
  39. }
  40. if (action.href && selectedProject?.ref) {
  41. router.push(action.href.replace('[ref]', selectedProject.ref))
  42. }
  43. }
  44. return (
  45. <section className="w-full">
  46. <div className="mb-6">
  47. <h3 className="heading-section">Get connected</h3>
  48. </div>
  49. <Card className="bg-background/25 border-dashed relative overflow-hidden">
  50. <div className="absolute -inset-16 z-0 opacity-50">
  51. <img
  52. src={`${BASE_PATH}/img/reports/bg-grafana-dark.svg`}
  53. alt=""
  54. className="w-full h-full object-cover object-right hidden dark:block"
  55. />
  56. <img
  57. src={`${BASE_PATH}/img/reports/bg-grafana-light.svg`}
  58. alt=""
  59. className="w-full h-full object-cover object-right dark:hidden"
  60. />
  61. <div className="absolute inset-0 bg-linear-to-r from-background-alternative to-transparent" />
  62. </div>
  63. <CardContent className="relative z-10 p-0">
  64. <div className="grid grid-cols-1 xl:grid-cols-5 divide-y xl:divide-y-0 xl:divide-x border-muted">
  65. {availableActions.map((action) => (
  66. <button
  67. key={action.id}
  68. type="button"
  69. disabled={
  70. (action.requiresActiveProject ?? true) ? !isActiveHealthy : !selectedProject?.ref
  71. }
  72. onClick={() => handleActionClick(action)}
  73. className={cn(
  74. 'group flex items-center gap-3 p-4 text-left transition-colors min-h-[72px] w-full',
  75. 'hover:bg-surface-100 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-brand',
  76. 'xl:min-h-32 xl:flex-col xl:justify-center xl:p-6 xl:text-center',
  77. ((action.requiresActiveProject ?? true)
  78. ? !isActiveHealthy
  79. : !selectedProject?.ref) && 'cursor-not-allowed opacity-50'
  80. )}
  81. >
  82. <span className="shrink-0 text-foreground-light group-hover:text-foreground">
  83. {action.icon}
  84. </span>
  85. <div className="flex min-w-0 flex-1 flex-col gap-1 xl:flex-initial">
  86. <p className="text-sm">{action.heading}</p>
  87. <p className="text-sm text-foreground-lighter">{action.subheading}</p>
  88. </div>
  89. <ChevronRight
  90. size={16}
  91. className="shrink-0 text-foreground-lighter group-hover:text-foreground xl:hidden"
  92. />
  93. </button>
  94. ))}
  95. </div>
  96. </CardContent>
  97. </Card>
  98. </section>
  99. )
  100. }