"use client"; import { ActionIcon, Button, Divider, Group, List, Stack, Text, ThemeIcon, Title, Tooltip } from "@mantine/core"; import { useLocalStorage } from "@mantine/hooks"; import { IconAppWindow, IconCheck, IconLayoutDashboard, IconPlugConnected, IconX } from "@tabler/icons-react"; import { clientApi } from "@homarr/api/client"; import { useSession } from "@homarr/auth/client"; import { constructBoardPermissions } from "@homarr/auth/shared"; import { useOptionalBoard } from "@homarr/boards/context"; import type { IntegrationKind } from "@homarr/definitions"; import { getIntegrationName, getWidgetKindsForIntegration } from "@homarr/definitions"; import { createModal, modalSizeForm, useModalAction } from "@homarr/modals"; import { useI18n } from "@homarr/translation/client"; import type { CreatedIntegrationResult } from "~/app/[locale]/manage/integrations/new/_integration-new-form"; import { ItemSelectModal } from "~/components/board/items/item-select-modal"; import { getBoardRecipeDismissalKey, getBoardRecipeRecommendations, } from "~/components/board/items/board-recipe-recommendations"; import { useSetupAnalytics } from "~/components/create/setup-analytics"; interface IntegrationCompletionModalProps { result: CreatedIntegrationResult; boardId?: string; } export const IntegrationCompletionModal = createModal(({ actions, innerProps }) => { const t = useI18n(); const board = useOptionalBoard(); const { data: session } = useSession(); const { data: integrations = [] } = clientApi.integration.all.useQuery(); const { openModal: openItemSelectModal } = useModalAction(ItemSelectModal); const trackSetup = useSetupAnalytics(); const compatibleWidgets = getWidgetKindsForIntegration(innerProps.result.integration.kind); const boardMatchesContext = board !== null && board.id === innerProps.boardId; const canModifyBoard = boardMatchesContext && constructBoardPermissions(board, session).hasChangeAccess; const dismissalKey = getBoardRecipeDismissalKey( innerProps.boardId ?? "no-board-context", innerProps.result.integration.kind, ); const [recommendationsDismissed, setRecommendationsDismissed] = useLocalStorage({ key: dismissalKey, defaultValue: false, }); const configuredIntegrationKinds = [ ...new Set([ ...integrations.map((integration) => integration.kind), innerProps.result.integration.kind, ]), ]; const recommendations = boardMatchesContext ? getBoardRecipeRecommendations({ configuredIntegrationKinds, existingItemKinds: board.items.map((item) => item.kind), preferredIntegrationKind: innerProps.result.integration.kind, }) : []; const showRecommendations = canModifyBoard && !recommendationsDismissed && recommendations.length > 0; const addWidget = () => { if (!innerProps.boardId) return; actions.closeModal(); openItemSelectModal({ boardId: innerProps.boardId, initialIntegrationKind: innerProps.result.integration.kind, }); }; const addRecommendedWidget = (widgetKind: (typeof recommendations)[number]["widgetKind"]) => { if (!innerProps.boardId) return; trackSetup("completion-recipe-selected", { entryPoint: "board", intent: "add-compatible-widget", outcome: "continued", hasBoardContext: true, }); actions.closeModal(); openItemSelectModal({ boardId: innerProps.boardId, initialWidgetKind: widgetKind }); }; return ( {t("integration.completion.title", { name: innerProps.result.integration.name })} {t("integration.completion.description")} } > {t("integration.completion.connectionReady")} {innerProps.result.appId && ( {t("integration.completion.appReady")} )} {t("integration.completion.compatibleWidgets", { count: String(compatibleWidgets.length) })} {showRecommendations && (
{t("integration.completion.recipes.title")} {t("integration.completion.recipes.description")}
setRecommendationsDismissed(true)} >
{recommendations.map((recommendation) => ( {t(`widget.${recommendation.widgetKind}.name`)} {t( recommendation.isNewlyAvailable ? "integration.completion.recipes.newConnectionReason" : "integration.completion.recipes.existingConnectionReason", { integration: recommendation.isNewlyAvailable ? innerProps.result.integration.name : getIntegrationName(recommendation.integrationKind), }, )} ))}
)} {innerProps.boardId && compatibleWidgets.length > 0 && ( )}
); }).withOptions({ defaultTitle: (t) => t("integration.completion.modalTitle"), size: modalSizeForm, });