diff --git a/apps/web/components/apps/AllApps.tsx b/apps/web/components/apps/AllApps.tsx index fd203ee695..26e4ad8bf3 100644 --- a/apps/web/components/apps/AllApps.tsx +++ b/apps/web/components/apps/AllApps.tsx @@ -1,12 +1,10 @@ -import { appRegistry } from "pages/apps/_appRegistry"; - +import { App } from "@lib/apps/interfaces/App"; import { useLocale } from "@lib/hooks/useLocale"; import AppCard from "./AppCard"; -export default function AllApps() { +export default function AllApps({ apps }: { apps: App[] }) { const { t } = useLocale(); - const apps = appRegistry(); return (
diff --git a/apps/web/components/apps/Slider.tsx b/apps/web/components/apps/Slider.tsx index 8ab1cb8a9c..7eefa54ed9 100644 --- a/apps/web/components/apps/Slider.tsx +++ b/apps/web/components/apps/Slider.tsx @@ -2,16 +2,15 @@ import Glide from "@glidejs/glide"; import "@glidejs/glide/dist/css/glide.core.min.css"; import "@glidejs/glide/dist/css/glide.theme.min.css"; import { ArrowLeftIcon, ArrowRightIcon } from "@heroicons/react/solid"; -import { appRegistry } from "pages/apps/_appRegistry"; import { useEffect, useState } from "react"; +import type { App } from "@lib/apps/interfaces/App"; import { useLocale } from "@lib/hooks/useLocale"; import useMediaQuery from "@lib/hooks/useMediaQuery"; import AppCard from "./AppCard"; -export default function Slider() { - const apps = appRegistry(); +const Slider = ({ items }: { items: T[] }) => { const { t } = useLocale(); const isMobile = useMediaQuery("(max-width: 767px)"); const [size, setSize] = useState(3); @@ -49,7 +48,7 @@ export default function Slider() {
); -} +}; + +export default Slider; diff --git a/apps/web/lib/apps/interfaces/App.ts b/apps/web/lib/apps/interfaces/App.ts index 065cb2777b..5bbe60999b 100644 --- a/apps/web/lib/apps/interfaces/App.ts +++ b/apps/web/lib/apps/interfaces/App.ts @@ -18,4 +18,14 @@ export type App = { description: string; imageSrc: string; variant: "calendar" | "payment" | "conferencing"; + label: string; + slug: string; + category: string; + logo: string; + publisher: string; + url: string; + verified: boolean; + trending: boolean; + rating: number; + reviews: number; }; diff --git a/apps/web/pages/apps/categories/[category].tsx b/apps/web/pages/apps/categories/[category].tsx index 58e7ce2340..fa56c124f2 100644 --- a/apps/web/pages/apps/categories/[category].tsx +++ b/apps/web/pages/apps/categories/[category].tsx @@ -1,18 +1,18 @@ import { ChevronLeftIcon } from "@heroicons/react/solid"; +import { InferGetStaticPropsType } from "next"; import { useRouter } from "next/router"; +import { getAppRegistry } from "@calcom/app-store/_appRegistry"; + import { useLocale } from "@lib/hooks/useLocale"; import Shell from "@components/Shell"; import AppCard from "@components/apps/AppCard"; import Button from "@components/ui/Button"; -import { appRegistry } from "../_appRegistry"; - -export default function Apps() { +export default function Apps({ appStore }: InferGetStaticPropsType) { const { t } = useLocale(); const router = useRouter(); - const apps = appRegistry(); return (

All {router.query.category} apps

- {apps.map((app) => { + {appStore.map((app) => { return ( app.category === router.query.category && ( ); } + +export const getStaticPaths = async () => { + const appStore = getAppRegistry(); + const paths = appStore.reduce((categories, app) => { + if (!categories.includes(app.category)) { + categories.push(app.category); + } + return categories; + }, [] as string[]); + + return { + paths: paths.map((category) => ({ params: { category } })), + fallback: false, + }; +}; + +export const getStaticProps = async () => { + return { + props: { + appStore: getAppRegistry(), + }, + }; +}; diff --git a/apps/web/pages/apps/index.tsx b/apps/web/pages/apps/index.tsx index 1a37703b54..9571309750 100644 --- a/apps/web/pages/apps/index.tsx +++ b/apps/web/pages/apps/index.tsx @@ -1,3 +1,5 @@ +import { getAppRegistry } from "@calcom/app-store/_appRegistry"; + import { useLocale } from "@lib/hooks/useLocale"; import AppsShell from "@components/AppsShell"; @@ -6,31 +8,35 @@ import AllApps from "@components/apps/AllApps"; import AppStoreCategories from "@components/apps/Categories"; import Slider from "@components/apps/Slider"; -export default function Apps() { +export default function Apps({ appStore, categories }) { const { t } = useLocale(); - const popularCategories = [ - { - name: "Payments", - count: 1, - }, - { - name: "Video", - count: 3, - }, - { - name: "Calendar", - count: 4, - }, - ]; - return ( - - - + + + ); } + +export const getStaticProps = async () => { + const appStore = getAppRegistry(); + const categories = appStore.reduce((c, app) => { + if (c[app.category]) { + c[app.category] = c[app.category]++; + } else { + c[app.category] = 1; + } + return c; + }, {}); + + return { + props: { + categories: Object.entries(categories).map(([name, count]) => ({ name, count })), + appStore, + }, + }; +}; diff --git a/apps/web/pages/apps/_appRegistry.ts b/packages/app-store/_appRegistry.ts similarity index 71% rename from apps/web/pages/apps/_appRegistry.ts rename to packages/app-store/_appRegistry.ts index 868e117450..90ca55523d 100644 --- a/apps/web/pages/apps/_appRegistry.ts +++ b/packages/app-store/_appRegistry.ts @@ -1,38 +1,9 @@ -import fs from "fs"; -import path from "path"; - -// It won't be called on client-side. -export async function getStaticProps() { - const appStoreDir = path.join(process.cwd(), "packages/appStore"); - const filenames = fs.readdirSync(appStoreDir); - - const apps = filenames.map((filename) => { - const filePath = path.join(appStoreDir, filename); - const fileContents = fs.readFileSync(filePath, "utf8"); - - // Generally you would parse/transform the contents - // For example you can transform markdown to HTML here - - return { - filename, - content: fileContents, - }; - }); - // By returning { props: posts }, the Blog component - // will receive `posts` as a prop at build time - return { - props: { - posts: apps, - }, - }; -} - -export function appRegistry() { +export function getAppRegistry() { return [ { name: "Zoom", slug: "zoom", // needs to be the same as the folder name - category: "Video Conferencing", + category: "video", description: "Zoom is the most popular video conferencing platform, joinable on the web or via desktop/mobile apps.", logo: "/apps/zoom.svg", @@ -45,7 +16,7 @@ export function appRegistry() { { name: "Cal Video", slug: "cal-video", - category: "Video Conferencing", + category: "video", description: "Cal Video is the in-house web-based video conferencing platform powered by Daily.co, which is minimalistic and lightweight, but has most of the features you need.", logo: "/apps/daily.svg", @@ -59,7 +30,7 @@ export function appRegistry() { { name: "Google Meet", slug: "google-meet", - category: "Video Conferencing", + category: "video", description: "Google Meet is Google's web-based video conferencing platform, designed to compete with major conferencing platforms.", logo: "https://cdn.iconscout.com/icon/free/png-256/google-meet-2923654-2416657.png", @@ -69,8 +40,8 @@ export function appRegistry() { }, { name: "Stripe", - slug: "stripe", - category: "Payments", + slug: "stripe_payment", + category: "payment", description: "Stripe is the world's leading payment provider. Start charging for your bookings today.", logo: "/apps/stripe.svg", rating: 4.6, @@ -80,7 +51,7 @@ export function appRegistry() { { name: "Google Calendar", slug: "google-calendar", - category: "Calendar", + category: "calendar", description: "Google Calendar is the most popular calendar platform for personal and business calendars.", logo: "/apps/google-calendar.svg", @@ -90,7 +61,7 @@ export function appRegistry() { { name: "Microsoft 365/Outlook Calendar", slug: "microsoft-365", - category: "Calendar", + category: "calendar", description: "Microsoft 365 calendars for business users, and Outlook is a popular calendar platform for personal users.", logo: "/apps/outlook.svg", @@ -100,7 +71,7 @@ export function appRegistry() { { name: "CalDAV", slug: "caldav", - category: "Calendar", + category: "calendar", description: "CalDAV is an open calendar standard which connects to virtually every calendar.", logo: "/apps/caldav.svg", rating: 3.6, @@ -109,7 +80,7 @@ export function appRegistry() { { name: "iCloud Calendar", slug: "icloud-calendar", - category: "Calendar", + category: "calendar", description: "iCloud Calendar is Apple's calendar platform for users of iCloud, and is used in the Apple Calendar app on iOS and macOS.", logo: "/apps/apple-calendar.svg",