"use client"; import { useEffect, useRef, useState } from "react"; import Link from "next/link"; import { Button } from "@kandev/ui/button"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuTrigger, } from "@kandev/ui/dropdown-menu"; import { IconBrandGithub, IconHexagon, IconPlugConnected, IconTicket } from "@tabler/icons-react"; import { useJiraAvailable } from "@/components/jira/my-jira/use-jira-availability"; import { useLinearAvailable } from "@/components/linear/use-linear-availability"; import { useGitHubStatus } from "@/hooks/domains/github/use-github-status"; import type { GitHubStatus } from "@/lib/types/github"; type IntegrationsProps = { workspaceId?: string; }; type MobileIntegrationsSectionProps = IntegrationsProps & { onNavigate: () => void; }; type IntegrationId = "github" | "jira" | "linear"; type IntegrationLink = { id: IntegrationId; label: string; href: string; }; type IntegrationAvailability = { githubReady: boolean; jiraAvailable: boolean; linearAvailable: boolean; }; const INTEGRATION_LINKS: IntegrationLink[] = [ { id: "github", label: "GitHub", href: "/github" }, { id: "jira", label: "Jira", href: "/jira" }, { id: "linear", label: "Linear", href: "/linear" }, ]; const INTEGRATION_ICONS = { github: IconBrandGithub, jira: IconTicket, linear: IconHexagon, } satisfies Record; const HOVER_CLOSE_DELAY_MS = 180; export function getAvailableIntegrationLinks({ githubReady, jiraAvailable, linearAvailable, }: IntegrationAvailability): IntegrationLink[] { return INTEGRATION_LINKS.filter((link) => { if (link.id === "github") return githubReady; if (link.id === "jira") return jiraAvailable; return linearAvailable; }); } function getStatusLabel(loading: boolean | undefined): string { return loading ? "Checking" : "Setup"; } export function getGitHubIntegrationStatus(status: GitHubStatus | null, loading: boolean) { if (status?.authenticated) return { ready: true, label: "Connected" }; if (status?.token_configured) return { ready: true, label: "Configured" }; return { ready: false, label: getStatusLabel(loading) }; } function useConfiguredIntegrationLinks(workspaceId: string | undefined): IntegrationLink[] { const { status, loading } = useGitHubStatus(); const jiraAvailable = useJiraAvailable(workspaceId); const linearAvailable = useLinearAvailable(workspaceId); const githubStatus = getGitHubIntegrationStatus(status, loading); return getAvailableIntegrationLinks({ githubReady: githubStatus.ready, jiraAvailable, linearAvailable, }); } export function IntegrationsMenu({ workspaceId }: IntegrationsProps) { const links = useConfiguredIntegrationLinks(workspaceId); const [open, setOpen] = useState(false); const closeTimeoutRef = useRef | null>(null); useEffect(() => { return () => { if (closeTimeoutRef.current) clearTimeout(closeTimeoutRef.current); }; }, []); const clearCloseTimeout = () => { if (!closeTimeoutRef.current) return; clearTimeout(closeTimeoutRef.current); closeTimeoutRef.current = null; }; const openOnHover = () => { clearCloseTimeout(); setOpen((current) => (current ? current : true)); }; const closeAfterHover = () => { clearCloseTimeout(); closeTimeoutRef.current = setTimeout(() => setOpen(false), HOVER_CLOSE_DELAY_MS); }; const handleOpenChange = (nextOpen: boolean) => { clearCloseTimeout(); setOpen(nextOpen); }; if (links.length === 0) return null; return ( Integrations {links.map((link) => { const Icon = INTEGRATION_ICONS[link.id]; return ( {link.label} ); })} ); } export function MobileIntegrationsSection({ workspaceId, onNavigate, }: MobileIntegrationsSectionProps) { const links = useConfiguredIntegrationLinks(workspaceId); if (links.length === 0) return null; return (
Integrations
{links.map((link) => { const Icon = INTEGRATION_ICONS[link.id]; return ( ); })}
); }