import { useCallback, useState } from "react"; import { AppSettings } from "@calcom/app-store/_components/AppSettings"; import { InstallAppButton } from "@calcom/app-store/components"; import { getLocationFromApp, type EventLocationType } from "@calcom/app-store/locations"; import type { CredentialOwner } from "@calcom/app-store/types"; import AppListCard from "@calcom/features/apps/components/AppListCard"; import type { UpdateUsersDefaultConferencingAppParams } from "@calcom/features/apps/components/AppSetDefaultLinkDialog"; import { AppSetDefaultLinkDialog } from "@calcom/features/apps/components/AppSetDefaultLinkDialog"; import type { BulkUpdatParams, EventTypes, } from "@calcom/features/eventtypes/components/BulkEditDefaultForEventsModal"; import { BulkEditDefaultForEventsModal } from "@calcom/features/eventtypes/components/BulkEditDefaultForEventsModal"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import type { AppCategories } from "@calcom/prisma/enums"; import { type RouterOutputs } from "@calcom/trpc"; import type { App } from "@calcom/types/App"; import { Alert, Button, Dropdown, DropdownItem, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, List, showToast, } from "@calcom/ui"; export type HandleDisconnect = (credentialId: number, app: App["slug"], teamId?: number) => void; interface AppListProps { variant?: AppCategories; data: RouterOutputs["viewer"]["integrations"]; handleDisconnect: HandleDisconnect; listClassName?: string; defaultConferencingApp: RouterOutputs["viewer"]["getUsersDefaultConferencingApp"]; handleUpdateUserDefaultConferencingApp: (params: UpdateUsersDefaultConferencingAppParams) => void; handleBulkUpdateDefaultLocation: (params: BulkUpdatParams) => void; isBulkUpdateDefaultLocationPending: boolean; eventTypes?: EventTypes; isEventTypesFetching?: boolean; handleConnectDisconnectIntegrationMenuToggle: () => void; handleBulkEditDialogToggle: () => void; } export const AppList = ({ data, handleDisconnect, variant, listClassName, defaultConferencingApp, handleUpdateUserDefaultConferencingApp, handleBulkUpdateDefaultLocation, isBulkUpdateDefaultLocationPending, eventTypes, isEventTypesFetching, handleConnectDisconnectIntegrationMenuToggle, handleBulkEditDialogToggle, }: AppListProps) => { const [bulkUpdateModal, setBulkUpdateModal] = useState(false); const [locationType, setLocationType] = useState<(EventLocationType & { slug: string }) | undefined>( undefined ); const onSuccessCallback = useCallback(() => { setBulkUpdateModal(true); showToast("Default app updated successfully", "success"); }, []); const ChildAppCard = ({ item, }: { item: RouterOutputs["viewer"]["integrations"]["items"][number] & { credentialOwner?: CredentialOwner; }; }) => { const appSlug = item?.slug; const appIsDefault = appSlug === defaultConferencingApp?.appSlug || (appSlug === "daily-video" && !defaultConferencingApp?.appSlug); return ( 0 : false} credentialOwner={item?.credentialOwner} actions={ !item.credentialOwner?.readOnly ? (
) : null }>
); }; const appsWithTeamCredentials = data.items.filter((app) => app.teams.length); const cardsForAppsWithTeams = appsWithTeamCredentials.map((app) => { const appCards = []; if (app.userCredentialIds.length) { appCards.push(); } for (const team of app.teams) { if (team) { appCards.push( ); } } return appCards; }); const { t } = useLocale(); return ( <> {cardsForAppsWithTeams.map((apps) => apps.map((cards) => cards))} {data.items .filter((item) => item.invalidCredentialIds) .map((item, i) => { if (!item.teams.length) return ; })} {locationType && ( setLocationType(undefined)} onSuccess={onSuccessCallback} handleUpdateUserDefaultConferencingApp={handleUpdateUserDefaultConferencingApp} /> )} {bulkUpdateModal && ( )} ); }; function ConnectOrDisconnectIntegrationMenuItem(props: { credentialId: number; type: App["type"]; isGlobal?: boolean; installed?: boolean; invalidCredentialIds?: number[]; teamId?: number; app: App["slug"]; handleDisconnect: HandleDisconnect; handleConnectDisconnectIntegrationMenuToggle: () => void; }) { const { type, credentialId, isGlobal, installed, handleDisconnect, teamId, app } = props; const { t } = useLocale(); if (credentialId || type === "stripe_payment" || isGlobal) { return ( handleDisconnect(credentialId, app, teamId)} disabled={isGlobal} StartIcon="trash"> {t("remove_app")} ); } if (!installed) { return (
); } return ( ( )} onChanged={props.handleConnectDisconnectIntegrationMenuToggle} /> ); }