From 213caa722eea884f31d34bad4c61dd2952e48f15 Mon Sep 17 00:00:00 2001 From: Jaideep Guntupalli <63718527+JaideepGuntupalli@users.noreply.github.com> Date: Thu, 13 Jul 2023 19:17:46 +0530 Subject: [PATCH] feat: Added order by most popular in Onboarding screen (#9891) Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com> Co-authored-by: Peer Richelsen --- .../steps-views/ConnectCalendars.tsx | 6 ++++- .../steps-views/ConnectedVideoStep.tsx | 1 + packages/app-store/_appRegistry.ts | 25 +---------------- packages/lib/apps/getMostPopularApps.ts | 27 +++++++++++++++++++ .../loggedInViewer/integrations.handler.ts | 22 ++++++++++++++- .../loggedInViewer/integrations.schema.ts | 1 + 6 files changed, 56 insertions(+), 26 deletions(-) create mode 100644 packages/lib/apps/getMostPopularApps.ts diff --git a/apps/web/components/getting-started/steps-views/ConnectCalendars.tsx b/apps/web/components/getting-started/steps-views/ConnectCalendars.tsx index 60118a4319..6c606178b5 100644 --- a/apps/web/components/getting-started/steps-views/ConnectCalendars.tsx +++ b/apps/web/components/getting-started/steps-views/ConnectCalendars.tsx @@ -17,7 +17,11 @@ const ConnectedCalendars = (props: IConnectCalendarsProps) => { const { nextStep } = props; const queryConnectedCalendars = trpc.viewer.connectedCalendars.useQuery({ onboarding: true }); const { t } = useLocale(); - const queryIntegrations = trpc.viewer.integrations.useQuery({ variant: "calendar", onlyInstalled: false }); + const queryIntegrations = trpc.viewer.integrations.useQuery({ + variant: "calendar", + onlyInstalled: false, + sortByMostPopular: true, + }); const firstCalendar = queryConnectedCalendars.data?.connectedCalendars.find( (item) => item.calendars && item.calendars?.length > 0 diff --git a/apps/web/components/getting-started/steps-views/ConnectedVideoStep.tsx b/apps/web/components/getting-started/steps-views/ConnectedVideoStep.tsx index 46108e9553..1179460825 100644 --- a/apps/web/components/getting-started/steps-views/ConnectedVideoStep.tsx +++ b/apps/web/components/getting-started/steps-views/ConnectedVideoStep.tsx @@ -16,6 +16,7 @@ const ConnectedVideoStep = (props: ConnectedAppStepProps) => { const { data: queryConnectedVideoApps, isLoading } = trpc.viewer.integrations.useQuery({ variant: "conferencing", onlyInstalled: false, + sortByMostPopular: true, }); const { t } = useLocale(); diff --git a/packages/app-store/_appRegistry.ts b/packages/app-store/_appRegistry.ts index 4a0eb47212..3cc83ef7b7 100644 --- a/packages/app-store/_appRegistry.ts +++ b/packages/app-store/_appRegistry.ts @@ -1,8 +1,7 @@ -import { z } from "zod"; - import { appStoreMetadata } from "@calcom/app-store/appStoreMetaData"; import { getAppFromSlug } from "@calcom/app-store/utils"; import type { UserAdminTeams } from "@calcom/features/ee/teams/lib/getUserAdminTeams"; +import getMostPopularApps from "@calcom/lib/apps/getMostPopularApps"; import prisma, { safeAppSelect, safeCredentialSelect } from "@calcom/prisma"; import { userMetadata } from "@calcom/prisma/zod-utils"; import type { AppFrontendPayload as App } from "@calcom/types/App"; @@ -130,25 +129,3 @@ export async function getAppRegistryWithCredentials(userId: number, userAdminTea return apps; } - -async function getMostPopularApps() { - const mostPopularApps = z.array(z.object({ appId: z.string(), installCount: z.number() })).parse( - await prisma.$queryRaw` - SELECT - c."appId", - COUNT(*)::integer AS "installCount" - FROM - "Credential" c - WHERE - c."appId" IS NOT NULL - GROUP BY - c."appId" - ORDER BY - "installCount" DESC - ` - ); - return mostPopularApps.reduce((acc, { appId, installCount }) => { - acc[appId] = installCount; - return acc; - }, {} as Record); -} diff --git a/packages/lib/apps/getMostPopularApps.ts b/packages/lib/apps/getMostPopularApps.ts new file mode 100644 index 0000000000..fa1fb7ac71 --- /dev/null +++ b/packages/lib/apps/getMostPopularApps.ts @@ -0,0 +1,27 @@ +import { z } from "zod"; + +import prisma from "@calcom/prisma"; + +const getMostPopularApps = async () => { + const mostPopularApps = z.array(z.object({ appId: z.string(), installCount: z.number() })).parse( + await prisma.$queryRaw` + SELECT + c."appId", + COUNT(*)::integer AS "installCount" + FROM + "Credential" c + WHERE + c."appId" IS NOT NULL + GROUP BY + c."appId" + ORDER BY + "installCount" DESC + ` + ); + return mostPopularApps.reduce((acc, { appId, installCount }) => { + acc[appId] = installCount; + return acc; + }, {} as Record); +}; + +export default getMostPopularApps; diff --git a/packages/trpc/server/routers/loggedInViewer/integrations.handler.ts b/packages/trpc/server/routers/loggedInViewer/integrations.handler.ts index dbceb3a2b2..57488cce25 100644 --- a/packages/trpc/server/routers/loggedInViewer/integrations.handler.ts +++ b/packages/trpc/server/routers/loggedInViewer/integrations.handler.ts @@ -1,4 +1,5 @@ import getEnabledApps from "@calcom/lib/apps/getEnabledApps"; +import getMostPopularApps from "@calcom/lib/apps/getMostPopularApps"; import prisma from "@calcom/prisma"; import { MembershipRole } from "@calcom/prisma/enums"; import type { TrpcSessionUser } from "@calcom/trpc/server/trpc"; @@ -33,7 +34,15 @@ type TeamQuery = Prisma.TeamGetPayload<{ export const integrationsHandler = async ({ ctx, input }: IntegrationsOptions) => { const { user } = ctx; - const { variant, exclude, onlyInstalled, includeTeamInstalledApps, extendsFeature, teamId } = input; + const { + variant, + exclude, + onlyInstalled, + includeTeamInstalledApps, + extendsFeature, + teamId, + sortByMostPopular, + } = input; let { credentials } = user; let userTeams: TeamQuery[] = []; @@ -167,6 +176,17 @@ export const integrationsHandler = async ({ ctx, input }: IntegrationsOptions) = })); } + if (sortByMostPopular) { + const mostPopularApps = await getMostPopularApps(); + + // sort the apps array by the most popular apps + apps.sort((a, b) => { + const aCount = mostPopularApps[a.slug] || 0; + const bCount = mostPopularApps[b.slug] || 0; + return bCount - aCount; + }); + } + return { items: apps, }; diff --git a/packages/trpc/server/routers/loggedInViewer/integrations.schema.ts b/packages/trpc/server/routers/loggedInViewer/integrations.schema.ts index 71aa807081..855f565091 100644 --- a/packages/trpc/server/routers/loggedInViewer/integrations.schema.ts +++ b/packages/trpc/server/routers/loggedInViewer/integrations.schema.ts @@ -7,6 +7,7 @@ export const ZIntegrationsInputSchema = z.object({ includeTeamInstalledApps: z.boolean().optional(), extendsFeature: z.literal("EventType").optional(), teamId: z.union([z.number(), z.null()]).optional(), + sortByMostPopular: z.boolean().optional(), }); export type TIntegrationsInputSchema = z.infer;