import { ArrowRight, Pause, Play } from 'lucide-react' import Link from 'next/link' import { useEffect, useRef, useState } from 'react' import { Badge, Button, cn } from 'ui' import { IntegrationLogo } from '../Integration/IntegrationLogo' import { formatCategoryLabel, getMarketplaceSource, MarketplaceSourceBadge, } from './Marketplace.constants' import type { IntegrationDefinition } from '@/components/interfaces/Integrations/Landing/Integrations.constants' import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject' const ROTATION_INTERVAL_MS = 7000 interface MarketplaceFeaturedHeroProps { integrations: IntegrationDefinition[] installedIds: string[] categoryOptions: Array<{ slug: string; name: string }> } export const MarketplaceFeaturedHero = ({ integrations, installedIds, categoryOptions, }: MarketplaceFeaturedHeroProps) => { const { data: project } = useSelectedProjectQuery() const [activeIndex, setActiveIndex] = useState(0) const [isPaused, setIsPaused] = useState(false) const hoveringRef = useRef(false) const cardRef = useRef(null) useEffect(() => { if (integrations.length <= 1) return if (isPaused) return const interval = setInterval(() => { if (hoveringRef.current) return setActiveIndex((idx) => (idx + 1) % integrations.length) }, ROTATION_INTERVAL_MS) return () => clearInterval(interval) }, [integrations.length, isPaused]) useEffect(() => { const node = cardRef.current if (!node) return const enter = () => { hoveringRef.current = true } const leave = () => { hoveringRef.current = false } node.addEventListener('pointerenter', enter) node.addEventListener('pointerleave', leave) return () => { node.removeEventListener('pointerenter', enter) node.removeEventListener('pointerleave', leave) } }, []) if (integrations.length === 0) return null const active = integrations[Math.min(activeIndex, integrations.length - 1)] const activeCategorySlug = active.categories?.[0] const activeCategoryName = activeCategorySlug ? formatCategoryLabel(activeCategorySlug, categoryOptions) : null const isActiveInstalled = installedIds.includes(active.id) const source = getMarketplaceSource(active) const handleTabClick = (idx: number) => { setActiveIndex(idx) } return (

Featured integrations

{active.name}
{active.status && {active.status}}
{isActiveInstalled && ( Installed )}

{active.description}

{integrations.map((integration, idx) => { const isActive = idx === activeIndex const slug = integration.categories?.[0] const categoryLabel = slug ? formatCategoryLabel(slug, categoryOptions) : null return ( ) })}
) } interface FeaturedCoverProps { integration: IntegrationDefinition categoryLabel: string | null } // Decorative cover panel on the left of the hero. Uses a subtle dotted // gradient and renders the integration's own icon at a large scale so each // partner stays visually distinct without bespoke artwork per listing. const FeaturedCover = ({ integration, categoryLabel }: FeaturedCoverProps) => (
{integration.icon({ className: 'h-16 w-16' })}
{categoryLabel && ( {categoryLabel} )}
)