diff --git a/packages/atoms/app-card/components/Card/index.tsx b/packages/atoms/app-card/components/Card/index.tsx new file mode 100644 index 0000000000..feb7aa01e9 --- /dev/null +++ b/packages/atoms/app-card/components/Card/index.tsx @@ -0,0 +1,90 @@ +import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; +import { cn } from "@/lib/utils"; +import { useState, useEffect } from "react"; + +import { doesAppSupportTeamInstall } from "@calcom/app-store/utils"; +import type { UserAdminTeams } from "@calcom/ee/teams/lib/getUserAdminTeams"; +import type { AppFrontendPayload as App } from "@calcom/types/App"; +import type { CredentialFrontendPayload as Credential } from "@calcom/types/Credential"; + +type CardProps = { + app: App; + credentials?: Credential[]; + searchText?: string; + userAdminTeams?: UserAdminTeams; +}; + +export function Card({ app, credentials, searchText, userAdminTeams }: CardProps) { + const enabledOnTeams = doesAppSupportTeamInstall(app.categories, app.concurrentMeetings); + const appAdded = (credentials && credentials.length) || 0; + + const appInstalled = enabledOnTeams && userAdminTeams ? userAdminTeams.length < appAdded : appAdded > 0; + + const [searchTextIndex, setSearchTextIndex] = useState(undefined); + + useEffect(() => { + setSearchTextIndex(searchText ? app.name.toLowerCase().indexOf(searchText.toLowerCase()) : undefined); + }, [app.name, searchText]); + + return ( +
+
+ {`${app.name} +
+
+

+ {searchTextIndex != undefined && searchText ? ( + <> + {app.name.substring(0, searchTextIndex)} + + {app.name.substring(searchTextIndex, searchTextIndex + searchText.length)} + + {app.name.substring(searchTextIndex + searchText.length)} + + ) : ( + app.name + )} +

+
+

+ {app.description} +

+
+ + {} +
+
+ {appInstalled ? ( + + Installed + + ) : null} + {app.isTemplate && ( + Template + )} + {(app.isDefault || (!app.isDefault && app.isGlobal)) && ( + + Default + + )} +
+
+ ); +}