Fix app categories (#6016)
* Fix app metas * Optimize categories on app store * Remove commented code * Remove console log * Update apps/web/pages/apps/index.tsx Co-authored-by: Omar López <zomars@me.com> * Add categories to missing app metadata * Fix type error * Type fix * Type fixes * More type fixes * Clean up * Fix build error * No leaky please * Remove comment Co-authored-by: Omar López <zomars@me.com> Co-authored-by: Peer Richelsen <peeroke@gmail.com> Co-authored-by: Bailey Pumfleet <bailey@pumfleet.co.uk>
This commit is contained in:
parent
2d9064e92f
commit
540bf3a1cb
|
@ -47,13 +47,7 @@ export default function Apps({ apps }: InferGetStaticPropsType<typeof getStaticP
|
|||
}
|
||||
|
||||
export const getStaticPaths = async () => {
|
||||
const appStore = await getAppRegistry();
|
||||
const paths = appStore.reduce((categories, app) => {
|
||||
if (!categories.includes(app.category)) {
|
||||
categories.push(app.category);
|
||||
}
|
||||
return categories;
|
||||
}, [] as string[]);
|
||||
const paths = Object.keys(AppCategories);
|
||||
|
||||
return {
|
||||
paths: paths.map((category) => ({ params: { category } })),
|
||||
|
|
|
@ -44,7 +44,9 @@ export default function Apps({ categories }: InferGetStaticPropsType<typeof getS
|
|||
export const getStaticProps = async () => {
|
||||
const appStore = await getAppRegistry();
|
||||
const categories = appStore.reduce((c, app) => {
|
||||
c[app.category] = c[app.category] ? c[app.category] + 1 : 1;
|
||||
for (const category of app.categories) {
|
||||
c[category] = c[category] ? c[category] + 1 : 1;
|
||||
}
|
||||
return c;
|
||||
}, {} as Record<string, number>);
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { GetServerSideProps, InferGetServerSidePropsType } from "next";
|
||||
import { GetServerSidePropsContext } from "next";
|
||||
import { ChangeEventHandler, useState } from "react";
|
||||
|
||||
import { getAppRegistry, getAppRegistryWithCredentials } from "@calcom/app-store/_appRegistry";
|
||||
|
@ -6,6 +6,7 @@ import { classNames } from "@calcom/lib";
|
|||
import { getSession } from "@calcom/lib/auth";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import type { AppCategories } from "@calcom/prisma/client";
|
||||
import { inferSSRProps } from "@calcom/types/inferSSRProps";
|
||||
import { AllApps, AppsLayout, AppStoreCategories, Icon, TextField, TrendingAppsSlider } from "@calcom/ui";
|
||||
|
||||
import { ssgInit } from "@server/lib/ssg";
|
||||
|
@ -30,10 +31,7 @@ function AppsSearch({
|
|||
);
|
||||
}
|
||||
|
||||
export default function Apps({
|
||||
categories,
|
||||
appStore,
|
||||
}: InferGetServerSidePropsType<typeof getServerSideProps>) {
|
||||
export default function Apps({ categories, appStore }: inferSSRProps<typeof getServerSideProps>) {
|
||||
const { t } = useLocale();
|
||||
const [searchText, setSearchText] = useState<string | undefined>(undefined);
|
||||
|
||||
|
@ -52,12 +50,16 @@ export default function Apps({
|
|||
<TrendingAppsSlider items={appStore} />
|
||||
</>
|
||||
)}
|
||||
<AllApps apps={appStore} searchText={searchText} />
|
||||
<AllApps
|
||||
apps={appStore}
|
||||
searchText={searchText}
|
||||
categories={categories.map((category) => category.name)}
|
||||
/>
|
||||
</AppsLayout>
|
||||
);
|
||||
}
|
||||
|
||||
export const getServerSideProps: GetServerSideProps = async (context) => {
|
||||
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
|
||||
const ssg = await ssgInit(context);
|
||||
|
||||
const session = await getSession(context);
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import type { Credential } from "@prisma/client";
|
||||
|
||||
import prisma from "@calcom/prisma";
|
||||
import { App } from "@calcom/types/App";
|
||||
import prisma, { safeAppSelect, safeCredentialSelect } from "@calcom/prisma";
|
||||
import { AppFrontendPayload as App } from "@calcom/types/App";
|
||||
import { CredentialFrontendPayload as Credential } from "@calcom/types/Credential";
|
||||
|
||||
export async function getAppWithMetadata(app: { dirName: string }) {
|
||||
let appMetadata: App | null = null;
|
||||
|
@ -30,7 +29,7 @@ export async function getAppRegistry() {
|
|||
where: { enabled: true },
|
||||
select: { dirName: true, slug: true, categories: true, enabled: true },
|
||||
});
|
||||
const apps = [] as Omit<App, "key">[];
|
||||
const apps = [] as App[];
|
||||
for await (const dbapp of dbApps) {
|
||||
const app = await getAppWithMetadata(dbapp);
|
||||
if (!app) continue;
|
||||
|
@ -56,9 +55,15 @@ export async function getAppRegistry() {
|
|||
export async function getAppRegistryWithCredentials(userId: number) {
|
||||
const dbApps = await prisma.app.findMany({
|
||||
where: { enabled: true },
|
||||
include: { credentials: { where: { userId } } },
|
||||
select: {
|
||||
...safeAppSelect,
|
||||
credentials: {
|
||||
where: { userId },
|
||||
select: safeCredentialSelect,
|
||||
},
|
||||
},
|
||||
});
|
||||
const apps = [] as (Omit<App, "key"> & {
|
||||
const apps = [] as (App & {
|
||||
credentials: Credential[];
|
||||
})[];
|
||||
for await (const dbapp of dbApps) {
|
||||
|
@ -77,8 +82,7 @@ export async function getAppRegistryWithCredentials(userId: number) {
|
|||
...remainingAppProps,
|
||||
categories: dbapp.categories,
|
||||
credentials: dbapp.credentials,
|
||||
installed:
|
||||
true /* All apps from DB are considered installed by default. @TODO: Add and filter our by `enabled` property */,
|
||||
installed: true,
|
||||
});
|
||||
}
|
||||
return apps;
|
||||
|
|
|
@ -10,6 +10,7 @@ export const metadata = {
|
|||
title: "Apple Calendar",
|
||||
imageSrc: "/api/app-store/applecalendar/icon.svg",
|
||||
variant: "calendar",
|
||||
categories: ["calendar"],
|
||||
category: "calendar",
|
||||
logo: "/api/app-store/applecalendar/icon.svg",
|
||||
publisher: "Cal.com",
|
||||
|
|
|
@ -3,7 +3,6 @@ import type { AppMeta } from "@calcom/types/App";
|
|||
import config from "./config.json";
|
||||
|
||||
export const metadata = {
|
||||
category: "other",
|
||||
dirName: "around",
|
||||
appData: {
|
||||
location: {
|
||||
|
|
|
@ -11,6 +11,7 @@ export const metadata = {
|
|||
imageSrc: "/api/app-store/caldavcalendar/icon.svg",
|
||||
variant: "calendar",
|
||||
category: "calendar",
|
||||
categories: ["calendar"],
|
||||
logo: "/api/app-store/caldavcalendar/icon.svg",
|
||||
publisher: "Cal.com",
|
||||
rating: 5,
|
||||
|
|
|
@ -11,6 +11,7 @@ export const metadata = {
|
|||
imageSrc: "/api/app-store/caldavcalendar/icon.svg",
|
||||
variant: "calendar",
|
||||
category: "calendar",
|
||||
categories: ["calendar"],
|
||||
logo: "/api/app-store/caldavcalendar/icon.svg",
|
||||
publisher: "Cal.com",
|
||||
rating: 5,
|
||||
|
|
|
@ -3,7 +3,6 @@ import type { AppMeta } from "@calcom/types/App";
|
|||
import config from "./config.json";
|
||||
|
||||
export const metadata = {
|
||||
category: "other",
|
||||
dirName: "caldavcalendar",
|
||||
...config,
|
||||
} as AppMeta;
|
||||
|
|
|
@ -10,6 +10,7 @@ export const metadata = {
|
|||
imageSrc: "/api/app-store/dailyvideo/icon.svg",
|
||||
variant: "conferencing",
|
||||
url: "https://daily.co",
|
||||
categories: ["calendar"],
|
||||
trending: true,
|
||||
logo: "/api/app-store/dailyvideo/icon.svg",
|
||||
publisher: "Cal.com",
|
||||
|
|
|
@ -11,6 +11,7 @@ export const metadata = {
|
|||
imageSrc: "/api/app-store/exchange2013calendar/icon.svg",
|
||||
variant: "calendar",
|
||||
category: "calendar",
|
||||
categories: ["calendar"],
|
||||
label: "Exchange Calendar",
|
||||
logo: "/api/app-store/exchange2013calendar/icon.svg",
|
||||
publisher: "Cal.com",
|
||||
|
|
|
@ -11,6 +11,7 @@ export const metadata = {
|
|||
imageSrc: "/api/app-store/exchange2016calendar/icon.svg",
|
||||
variant: "calendar",
|
||||
category: "calendar",
|
||||
categories: ["calendar"],
|
||||
label: "Exchange Calendar",
|
||||
logo: "/api/app-store/exchange2016calendar/icon.svg",
|
||||
publisher: "Cal.com",
|
||||
|
|
|
@ -3,7 +3,6 @@ import type { AppMeta } from "@calcom/types/App";
|
|||
import config from "./config.json";
|
||||
|
||||
export const metadata = {
|
||||
category: "other",
|
||||
dirName: "ga4",
|
||||
...config,
|
||||
} as AppMeta;
|
||||
|
|
|
@ -6,7 +6,7 @@ export const metadata = {
|
|||
name: "Giphy",
|
||||
description: _package.description,
|
||||
installed: true,
|
||||
category: "other",
|
||||
categories: ["other"],
|
||||
// If using static next public folder, can then be referenced from the base URL (/).
|
||||
imageSrc: "/api/app-store/giphy/icon.svg",
|
||||
logo: "/api/app-store/giphy/icon.svg",
|
||||
|
|
|
@ -12,6 +12,7 @@ export const metadata = {
|
|||
imageSrc: "/api/app-store/googlecalendar/icon.svg",
|
||||
variant: "calendar",
|
||||
category: "calendar",
|
||||
categories: ["calendar"],
|
||||
logo: "/api/app-store/googlecalendar/icon.svg",
|
||||
publisher: "Cal.com",
|
||||
rating: 5,
|
||||
|
|
|
@ -9,6 +9,7 @@ export const metadata = {
|
|||
installed: !!(process.env.GOOGLE_API_CREDENTIALS && validJson(process.env.GOOGLE_API_CREDENTIALS)),
|
||||
slug: "google-meet",
|
||||
category: "video",
|
||||
categories: ["video"],
|
||||
type: "google_video",
|
||||
title: "Google Meet",
|
||||
imageSrc: "/api/app-store/googlevideo/logo.webp",
|
||||
|
|
|
@ -15,7 +15,7 @@ export const metadata = {
|
|||
verified: true,
|
||||
rating: 4.3, // TODO: placeholder for now, pull this from TrustPilot or G2
|
||||
reviews: 69, // TODO: placeholder for now, pull this from TrustPilot or G2
|
||||
category: "other",
|
||||
categories: ["other"],
|
||||
label: "HubSpot CRM",
|
||||
slug: "hubspot",
|
||||
title: "HubSpot CRM",
|
||||
|
|
|
@ -10,6 +10,7 @@ export const metadata = {
|
|||
type: "huddle01_video",
|
||||
imageSrc: "/api/app-store/huddle01video/icon.svg",
|
||||
variant: "conferencing",
|
||||
categories: ["video", "web3"],
|
||||
logo: "/api/app-store/huddle01video/icon.svg",
|
||||
publisher: "huddle01.com",
|
||||
url: "https://huddle01.com",
|
||||
|
|
|
@ -9,13 +9,13 @@ export const metadata = {
|
|||
type: "jitsi_video",
|
||||
imageSrc: "/api/app-store/jitsivideo/icon.svg",
|
||||
variant: "conferencing",
|
||||
categories: ["video"],
|
||||
logo: "/api/app-store/jitsivideo/icon.svg",
|
||||
publisher: "Cal.com",
|
||||
url: "https://jitsi.org/",
|
||||
verified: true,
|
||||
rating: 0, // TODO: placeholder for now, pull this from TrustPilot or G2
|
||||
reviews: 0, // TODO: placeholder for now, pull this from TrustPilot or G2
|
||||
category: "video",
|
||||
slug: "jitsi",
|
||||
title: "Jitsi Meet",
|
||||
trending: true,
|
||||
|
|
|
@ -10,7 +10,7 @@ export const metadata = {
|
|||
title: "Lark Calendar",
|
||||
imageSrc: "/api/app-store/larkcalendar/icon.svg",
|
||||
variant: "calendar",
|
||||
category: "calendar",
|
||||
categories: ["calendar"],
|
||||
logo: "/api/app-store/larkcalendar/icon.svg",
|
||||
publisher: "Lark",
|
||||
rating: 5,
|
||||
|
|
|
@ -10,6 +10,7 @@ export const metadata = {
|
|||
imageSrc: "/api/app-store/office365calendar/icon.svg",
|
||||
variant: "calendar",
|
||||
category: "calendar",
|
||||
categories: ["calendar"],
|
||||
logo: "/api/app-store/office365calendar/icon.svg",
|
||||
publisher: "Cal.com",
|
||||
rating: 5,
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
"rating": 4.3,
|
||||
"reviews": 69,
|
||||
"category": "video",
|
||||
"categories": ["video"],
|
||||
"slug": "msteams",
|
||||
"title": "MS Teams (Requires work/school account)",
|
||||
"trending": true,
|
||||
|
|
|
@ -3,7 +3,6 @@ import type { AppMeta } from "@calcom/types/App";
|
|||
import config from "./config.json";
|
||||
|
||||
export const metadata = {
|
||||
category: "other",
|
||||
// FIXME: Currently for an app to be shown as installed, it must have this variable set. Either hardcoded or if it depends on some env variable, that should be checked here
|
||||
installed: true,
|
||||
rating: 0,
|
||||
|
|
|
@ -3,7 +3,6 @@ import type { AppMeta } from "@calcom/types/App";
|
|||
import config from "./config.json";
|
||||
|
||||
export const metadata = {
|
||||
category: "other",
|
||||
dirName: "pipedream",
|
||||
...config,
|
||||
} as AppMeta;
|
||||
|
|
|
@ -3,7 +3,6 @@ import type { AppMeta } from "@calcom/types/App";
|
|||
import config from "./config.json";
|
||||
|
||||
export const metadata = {
|
||||
category: "other",
|
||||
dirName: "rainbow",
|
||||
...config,
|
||||
} as AppMeta;
|
||||
|
|
|
@ -3,7 +3,6 @@ import type { AppMeta } from "@calcom/types/App";
|
|||
import config from "./config.json";
|
||||
|
||||
export const metadata = {
|
||||
category: "other",
|
||||
// FIXME: Currently for an app to be shown as installed, it must have this variable set. Either hardcoded or if it depends on some env variable, that should be checked here
|
||||
installed: true,
|
||||
rating: 0,
|
||||
|
|
|
@ -3,7 +3,6 @@ import type { AppMeta } from "@calcom/types/App";
|
|||
import config from "./config.json";
|
||||
|
||||
export const metadata = {
|
||||
category: "other",
|
||||
dirName: "salesforce",
|
||||
...config,
|
||||
} as AppMeta;
|
||||
|
|
|
@ -3,7 +3,6 @@ import type { AppMeta } from "@calcom/types/App";
|
|||
import config from "./config.json";
|
||||
|
||||
export const metadata = {
|
||||
category: "other",
|
||||
dirName: "sendgrid",
|
||||
...config,
|
||||
} as AppMeta;
|
||||
|
|
|
@ -3,7 +3,6 @@ import type { AppMeta } from "@calcom/types/App";
|
|||
import config from "./config.json";
|
||||
|
||||
export const metadata = {
|
||||
category: "other",
|
||||
dirName: "signal",
|
||||
...config,
|
||||
} as AppMeta;
|
||||
|
|
|
@ -3,7 +3,6 @@ import type { AppMeta } from "@calcom/types/App";
|
|||
import config from "./config.json";
|
||||
|
||||
export const metadata = {
|
||||
category: "other",
|
||||
dirName: "sirius_video",
|
||||
...config,
|
||||
} as AppMeta;
|
||||
|
|
|
@ -12,6 +12,7 @@ export const metadata = {
|
|||
),
|
||||
slug: "stripe",
|
||||
category: "payment",
|
||||
categories: ["payment"],
|
||||
logo: "/api/app-store/stripepayment/icon.svg",
|
||||
rating: 4.6,
|
||||
trending: true,
|
||||
|
|
|
@ -9,6 +9,7 @@ export const metadata = {
|
|||
title: "Tandem Video",
|
||||
imageSrc: "/api/app-store/tandemvideo/icon.svg",
|
||||
variant: "conferencing",
|
||||
categories: ["video"],
|
||||
slug: "tandem",
|
||||
category: "video",
|
||||
logo: "/api/app-store/tandemvideo/icon.svg",
|
||||
|
|
|
@ -3,7 +3,6 @@ import type { AppMeta } from "@calcom/types/App";
|
|||
import config from "./config.json";
|
||||
|
||||
export const metadata = {
|
||||
category: "other",
|
||||
dirName: "telegram",
|
||||
...config,
|
||||
} as AppMeta;
|
||||
|
|
|
@ -76,7 +76,10 @@ export function getLocationGroupedOptions(integrations: ReturnType<typeof getApp
|
|||
const apps: Record<string, { label: string; value: string; disabled?: boolean; icon?: string }[]> = {};
|
||||
integrations.forEach((app) => {
|
||||
if (app.locationOption) {
|
||||
const category = app.category;
|
||||
// All apps that are labeled as a locationOption are video apps. Extract the secondary category if available
|
||||
let category =
|
||||
app.categories.length >= 2 ? app.categories.find((category) => category !== "video") : app.category;
|
||||
if (!category) category = "video";
|
||||
const option = { ...app.locationOption, icon: app.imageSrc };
|
||||
if (apps[category]) {
|
||||
apps[category] = [...apps[category], option];
|
||||
|
|
|
@ -7,6 +7,7 @@ export const metadata = {
|
|||
description: _package.description,
|
||||
installed: true,
|
||||
category: "other",
|
||||
categories: ["other"],
|
||||
// If using static next public folder, can then be referenced from the base URL (/).
|
||||
imageSrc: "/api/app-store/vital/icon.svg",
|
||||
logo: "/api/app-store/vital/icon.svg",
|
||||
|
|
|
@ -3,7 +3,6 @@ import type { AppMeta } from "@calcom/types/App";
|
|||
import config from "./config.json";
|
||||
|
||||
export const metadata = {
|
||||
category: "other",
|
||||
dirName: "whatsapp",
|
||||
...config,
|
||||
} as AppMeta;
|
||||
|
|
|
@ -3,7 +3,6 @@ import type { AppMeta } from "@calcom/types/App";
|
|||
import config from "./config.json";
|
||||
|
||||
export const metadata = {
|
||||
category: "other",
|
||||
// FIXME: Currently for an app to be shown as installed, it must have this variable set. Either hardcoded or if it depends on some env variable, that should be checked here
|
||||
installed: true,
|
||||
rating: 0,
|
||||
|
|
|
@ -7,6 +7,7 @@ export const metadata = {
|
|||
description: _package.description,
|
||||
installed: true,
|
||||
category: "other",
|
||||
categories: ["other"],
|
||||
// If using static next public folder, can then be referenced from the base URL (/).
|
||||
imageSrc: "/api/app-store/wipemycalother/icon-dark.svg",
|
||||
logo: "/api/app-store/wipemycalother/icon-dark.svg",
|
||||
|
|
|
@ -7,6 +7,7 @@ export const metadata = {
|
|||
description: _package.description,
|
||||
installed: true,
|
||||
category: "automation",
|
||||
categories: ["automation"],
|
||||
imageSrc: "/api/app-store/zapier/icon.svg",
|
||||
logo: "/api/app-store/zapier/icon.svg",
|
||||
publisher: "Cal.com",
|
||||
|
|
|
@ -7,6 +7,7 @@ export const metadata = {
|
|||
name: "Zoom Video",
|
||||
description: _package.description,
|
||||
type: "zoom_video",
|
||||
categories: ["video"],
|
||||
imageSrc: "/api/app-store/zoomvideo/icon.svg",
|
||||
variant: "conferencing",
|
||||
logo: "/api/app-store/zoomvideo/icon.svg",
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
import { Prisma } from "@prisma/client";
|
||||
|
||||
export const safeAppSelect = Prisma.validator<Prisma.AppSelect>()({
|
||||
slug: true,
|
||||
dirName: true,
|
||||
/** Omitting to avoid frontend leaks */
|
||||
// keys: true,
|
||||
categories: true,
|
||||
createdAt: true,
|
||||
updatedAt: true,
|
||||
enabled: true,
|
||||
});
|
|
@ -0,0 +1,11 @@
|
|||
import { Prisma } from "@prisma/client";
|
||||
|
||||
export const safeCredentialSelect = Prisma.validator<Prisma.CredentialSelect>()({
|
||||
id: true,
|
||||
type: true,
|
||||
/** Omitting to avoid frontend leaks */
|
||||
// key: true,
|
||||
userId: true,
|
||||
appId: true,
|
||||
invalid: true,
|
||||
});
|
|
@ -1,3 +1,5 @@
|
|||
export { safeAppSelect } from "./app";
|
||||
export * from "./booking";
|
||||
export { safeCredentialSelect } from "./credential";
|
||||
export * from "./event-types";
|
||||
export * from "./user";
|
||||
|
|
|
@ -89,10 +89,10 @@ export interface App {
|
|||
/*
|
||||
* @deprecated Use categories
|
||||
*/
|
||||
category: string;
|
||||
category?: string;
|
||||
|
||||
/** The category to which this app belongs, currently we have `calendar`, `payment` or `video` */
|
||||
categories?: string[];
|
||||
categories: string[];
|
||||
/**
|
||||
* `User` is the broadest category. `EventType` is when you want to add features to EventTypes.
|
||||
* See https://app.gitbook.com/o/6snd8PyPYMhg0wUw6CeQ/s/VXRprBTuMlihk37NQgUU/~/changes/6xkqZ4qvJ3Xh9k8UaWaZ/engineering/product-specs/app-store#user-apps for more details
|
||||
|
@ -121,9 +121,6 @@ export interface App {
|
|||
isGlobal?: boolean;
|
||||
/** A contact email, mainly to ask for support */
|
||||
email: string;
|
||||
|
||||
/** Needed API Keys (usually for global apps) */
|
||||
key?: Prisma.JsonValue;
|
||||
/** Needed API Keys (usually for global apps) */
|
||||
key?: Prisma.JsonValue;
|
||||
/** If not free, what kind of fees does the app have */
|
||||
|
@ -138,4 +135,9 @@ export interface App {
|
|||
dirName?: string;
|
||||
}
|
||||
|
||||
export type AppFrontendPayload = Omit<App, "key"> & {
|
||||
/** We should type error if keys are leaked to the frontend */
|
||||
key?: never;
|
||||
};
|
||||
|
||||
export type AppMeta = Optional<App, "rating" | "trending" | "reviews" | "verified">;
|
||||
|
|
|
@ -16,4 +16,9 @@ export type CredentialPayload = Prisma.CredentialGetPayload<{
|
|||
};
|
||||
}>;
|
||||
|
||||
export type CredentialFrontendPayload = Omit<CredentialPayload, "key"> & {
|
||||
/** We should type error if keys are leaked to the frontend */
|
||||
key?: never;
|
||||
};
|
||||
|
||||
export type CredentialWithAppName = CredentialPayload & { appName: string };
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { useAutoAnimate } from "@formkit/auto-animate/react";
|
||||
import type { Credential } from "@prisma/client";
|
||||
import { useRouter } from "next/router";
|
||||
import { UIEvent, useEffect, useRef, useState } from "react";
|
||||
|
||||
import { classNames } from "@calcom/lib";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import type { App } from "@calcom/types/App";
|
||||
import type { AppFrontendPayload as App } from "@calcom/types/App";
|
||||
import type { CredentialFrontendPayload as Credential } from "@calcom/types/Credential";
|
||||
import { Icon } from "@calcom/ui";
|
||||
|
||||
import EmptyScreen from "../EmptyScreen";
|
||||
|
@ -37,7 +37,11 @@ export function useShouldShowArrows() {
|
|||
return { ref, calculateScroll, leftVisible: showArrowScroll.left, rightVisible: showArrowScroll.right };
|
||||
}
|
||||
|
||||
type AllAppsPropsType = { apps: (App & { credentials: Credential[] | undefined })[]; searchText?: string };
|
||||
type AllAppsPropsType = {
|
||||
apps: (App & { credentials?: Credential[] })[];
|
||||
searchText?: string;
|
||||
categories: string[];
|
||||
};
|
||||
|
||||
interface CategoryTabProps {
|
||||
selectedCategory: string | null;
|
||||
|
@ -125,18 +129,12 @@ function CategoryTab({ selectedCategory, categories, searchText }: CategoryTabPr
|
|||
);
|
||||
}
|
||||
|
||||
export default function AllApps({ apps, searchText }: AllAppsPropsType) {
|
||||
export default function AllApps({ apps, searchText, categories }: AllAppsPropsType) {
|
||||
const router = useRouter();
|
||||
const { t } = useLocale();
|
||||
const [selectedCategory, setSelectedCategory] = useState<string | null>(null);
|
||||
const [appsContainerRef, enableAnimation] = useAutoAnimate<HTMLDivElement>();
|
||||
|
||||
const categories = apps
|
||||
.map((app) => app.category)
|
||||
.filter((cat, pos, self) => {
|
||||
return self.indexOf(cat) === pos;
|
||||
});
|
||||
|
||||
if (searchText) {
|
||||
enableAnimation && enableAnimation(false);
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import type { Credential } from "@prisma/client";
|
||||
import { useRouter } from "next/router";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import useAddAppMutation from "@calcom/app-store/_utils/useAddAppMutation";
|
||||
import { InstallAppButton } from "@calcom/app-store/components";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { App } from "@calcom/types/App";
|
||||
import { AppFrontendPayload as App } from "@calcom/types/App";
|
||||
import type { CredentialFrontendPayload as Credential } from "@calcom/types/Credential";
|
||||
|
||||
import { Button, Icon } from "../../..";
|
||||
import { showToast } from "../notifications";
|
||||
|
@ -123,8 +123,6 @@ export default function AppCard({ app, credentials, searchText }: AppCardProps)
|
|||
},
|
||||
};
|
||||
}
|
||||
props.color;
|
||||
// ^?
|
||||
return (
|
||||
<Button
|
||||
StartIcon={Icon.FiPlus}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import type { App } from "@calcom/types/App";
|
||||
import { AppFrontendPayload as App } from "@calcom/types/App";
|
||||
|
||||
import AppCard from "./AppCard";
|
||||
import Slider from "./Slider";
|
||||
|
|
Loading…
Reference in New Issue
Block a user