MarketplaceDetail.tsx 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. import { ArrowUpRight, BookOpen, Settings } from 'lucide-react'
  2. import { Button, cn } from 'ui'
  3. import { GenericSkeletonLoader, ShimmeringLoader } from 'ui-patterns'
  4. import { Admonition } from 'ui-patterns/admonition'
  5. import { MarketplaceDetailHero } from './MarketplaceDetailHero'
  6. import { MarketplaceDetailTopBar } from './MarketplaceDetailTopBar'
  7. import { OverviewTab } from './OverviewTab'
  8. import { InstallIntegrationSheet } from '@/components/interfaces/Integrations/Integration/IntegrationOverviewTabV2/InstallIntegrationSheet/InstallIntegrationSheet'
  9. import { InstallOAuthIntegrationButton } from '@/components/interfaces/Integrations/Integration/IntegrationOverviewTabV2/InstallIntegrationSheet/InstallOAuthIntegrationButton'
  10. import { useIntegrationDetail } from '@/components/interfaces/Integrations/Landing/useIntegrationDetail'
  11. import { UnknownInterface } from '@/components/ui/UnknownInterface'
  12. export const centeredContentClass = 'mx-auto w-full max-w-6xl px-6 xl:px-10'
  13. export const MarketplaceDetail = () => {
  14. const {
  15. ref,
  16. activeRoute,
  17. isKnownRoute,
  18. layout,
  19. tabs,
  20. isReady,
  21. isWrapperBlocked,
  22. pageTitle,
  23. pageSubTitle,
  24. integration,
  25. isInstalled,
  26. isAvailableLoading,
  27. isInstalledLoading,
  28. Component,
  29. } = useIntegrationDetail()
  30. if (!isReady) return null
  31. if (isWrapperBlocked) return <UnknownInterface urlBack={`/project/${ref}/integrations`} />
  32. if (isAvailableLoading || isInstalledLoading) {
  33. return (
  34. <>
  35. <MarketplaceDetailTopBar title="" />
  36. <div className={cn(centeredContentClass, 'border-b bg-surface-75 pt-10')}>
  37. <div className="mx-auto flex w-full max-w-6xl flex-col gap-3 pb-6">
  38. <ShimmeringLoader className="h-9 w-64" />
  39. <ShimmeringLoader className="h-4 w-96" />
  40. </div>
  41. </div>
  42. <div className={cn(centeredContentClass, 'py-8')}>
  43. <GenericSkeletonLoader />
  44. </div>
  45. </>
  46. )
  47. }
  48. if (!integration) {
  49. return (
  50. <>
  51. <MarketplaceDetailTopBar title="Integration not found" />
  52. <div className={cn(centeredContentClass, 'py-8')}>
  53. <Admonition type="warning" title="This integration is not currently available">
  54. Please try again later or contact support if the problem persists.
  55. </Admonition>
  56. </div>
  57. </>
  58. )
  59. }
  60. const renderInstallAction = () => {
  61. if (integration.type === 'oauth') {
  62. return <InstallOAuthIntegrationButton integration={integration} />
  63. }
  64. if (isInstalled) {
  65. return (
  66. <Button type="outline" disabled icon={<Settings size={13} />}>
  67. Installed
  68. </Button>
  69. )
  70. }
  71. return <InstallIntegrationSheet integration={integration} />
  72. }
  73. const CustomPageComponent = activeRoute !== 'overview' && isKnownRoute ? Component : null
  74. return (
  75. <>
  76. <MarketplaceDetailTopBar
  77. title={integration.name}
  78. isInstalled={isInstalled}
  79. actions={
  80. <>
  81. {integration.docsUrl && (
  82. <Button
  83. type="text"
  84. size="tiny"
  85. icon={<BookOpen size={13} />}
  86. iconRight={<ArrowUpRight size={13} />}
  87. asChild
  88. >
  89. <a href={integration.docsUrl} target="_blank" rel="noreferrer">
  90. Docs
  91. </a>
  92. </Button>
  93. )}
  94. {renderInstallAction()}
  95. </>
  96. }
  97. />
  98. <MarketplaceDetailHero
  99. integration={integration}
  100. title={pageTitle}
  101. subtitle={pageSubTitle}
  102. tabs={tabs}
  103. />
  104. {activeRoute === 'overview' ? (
  105. <div className={centeredContentClass}>
  106. <OverviewTab integration={integration} isInstalled={isInstalled} />
  107. </div>
  108. ) : CustomPageComponent ? (
  109. layout === 'constrained' ? (
  110. <div className={centeredContentClass}>
  111. <CustomPageComponent />
  112. </div>
  113. ) : (
  114. <CustomPageComponent />
  115. )
  116. ) : null}
  117. </>
  118. )
  119. }