This commit is contained in:
zomars 2022-02-22 08:52:49 -07:00
parent a7523a7d5d
commit 3522af1a16
6 changed files with 81 additions and 72 deletions

View File

@ -1,12 +1,10 @@
import { appRegistry } from "pages/apps/_appRegistry"; import { App } from "@lib/apps/interfaces/App";
import { useLocale } from "@lib/hooks/useLocale"; import { useLocale } from "@lib/hooks/useLocale";
import AppCard from "./AppCard"; import AppCard from "./AppCard";
export default function AllApps() { export default function AllApps({ apps }: { apps: App[] }) {
const { t } = useLocale(); const { t } = useLocale();
const apps = appRegistry();
return ( return (
<div className="mb-16"> <div className="mb-16">

View File

@ -2,16 +2,15 @@ import Glide from "@glidejs/glide";
import "@glidejs/glide/dist/css/glide.core.min.css"; import "@glidejs/glide/dist/css/glide.core.min.css";
import "@glidejs/glide/dist/css/glide.theme.min.css"; import "@glidejs/glide/dist/css/glide.theme.min.css";
import { ArrowLeftIcon, ArrowRightIcon } from "@heroicons/react/solid"; import { ArrowLeftIcon, ArrowRightIcon } from "@heroicons/react/solid";
import { appRegistry } from "pages/apps/_appRegistry";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import type { App } from "@lib/apps/interfaces/App";
import { useLocale } from "@lib/hooks/useLocale"; import { useLocale } from "@lib/hooks/useLocale";
import useMediaQuery from "@lib/hooks/useMediaQuery"; import useMediaQuery from "@lib/hooks/useMediaQuery";
import AppCard from "./AppCard"; import AppCard from "./AppCard";
export default function Slider() { const Slider = <T extends App>({ items }: { items: T[] }) => {
const apps = appRegistry();
const { t } = useLocale(); const { t } = useLocale();
const isMobile = useMediaQuery("(max-width: 767px)"); const isMobile = useMediaQuery("(max-width: 767px)");
const [size, setSize] = useState(3); const [size, setSize] = useState(3);
@ -49,7 +48,7 @@ export default function Slider() {
</div> </div>
<div className="glide__track" data-glide-el="track"> <div className="glide__track" data-glide-el="track">
<ul className="glide__slides"> <ul className="glide__slides">
{apps.map((app) => { {items.map((app) => {
return ( return (
app.trending && ( app.trending && (
<li key={app.name} className="glide__slide"> <li key={app.name} className="glide__slide">
@ -71,4 +70,6 @@ export default function Slider() {
</div> </div>
</div> </div>
); );
} };
export default Slider;

View File

@ -18,4 +18,14 @@ export type App = {
description: string; description: string;
imageSrc: string; imageSrc: string;
variant: "calendar" | "payment" | "conferencing"; variant: "calendar" | "payment" | "conferencing";
label: string;
slug: string;
category: string;
logo: string;
publisher: string;
url: string;
verified: boolean;
trending: boolean;
rating: number;
reviews: number;
}; };

View File

@ -1,18 +1,18 @@
import { ChevronLeftIcon } from "@heroicons/react/solid"; import { ChevronLeftIcon } from "@heroicons/react/solid";
import { InferGetStaticPropsType } from "next";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { getAppRegistry } from "@calcom/app-store/_appRegistry";
import { useLocale } from "@lib/hooks/useLocale"; import { useLocale } from "@lib/hooks/useLocale";
import Shell from "@components/Shell"; import Shell from "@components/Shell";
import AppCard from "@components/apps/AppCard"; import AppCard from "@components/apps/AppCard";
import Button from "@components/ui/Button"; import Button from "@components/ui/Button";
import { appRegistry } from "../_appRegistry"; export default function Apps({ appStore }: InferGetStaticPropsType<typeof getStaticProps>) {
export default function Apps() {
const { t } = useLocale(); const { t } = useLocale();
const router = useRouter(); const router = useRouter();
const apps = appRegistry();
return ( return (
<Shell <Shell
@ -27,7 +27,7 @@ export default function Apps() {
<div className="mb-16"> <div className="mb-16">
<h2 className="mb-2 text-lg font-semibold text-gray-900">All {router.query.category} apps</h2> <h2 className="mb-2 text-lg font-semibold text-gray-900">All {router.query.category} apps</h2>
<div className="grid grid-cols-3 gap-3"> <div className="grid grid-cols-3 gap-3">
{apps.map((app) => { {appStore.map((app) => {
return ( return (
app.category === router.query.category && ( app.category === router.query.category && (
<AppCard <AppCard
@ -46,3 +46,26 @@ export default function Apps() {
</Shell> </Shell>
); );
} }
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(),
},
};
};

View File

@ -1,3 +1,5 @@
import { getAppRegistry } from "@calcom/app-store/_appRegistry";
import { useLocale } from "@lib/hooks/useLocale"; import { useLocale } from "@lib/hooks/useLocale";
import AppsShell from "@components/AppsShell"; import AppsShell from "@components/AppsShell";
@ -6,31 +8,35 @@ import AllApps from "@components/apps/AllApps";
import AppStoreCategories from "@components/apps/Categories"; import AppStoreCategories from "@components/apps/Categories";
import Slider from "@components/apps/Slider"; import Slider from "@components/apps/Slider";
export default function Apps() { export default function Apps({ appStore, categories }) {
const { t } = useLocale(); const { t } = useLocale();
const popularCategories = [
{
name: "Payments",
count: 1,
},
{
name: "Video",
count: 3,
},
{
name: "Calendar",
count: 4,
},
];
return ( return (
<Shell heading={t("app_store")} subtitle={t("app_store_description")} large> <Shell heading={t("app_store")} subtitle={t("app_store_description")} large>
<AppsShell> <AppsShell>
<AppStoreCategories categories={popularCategories} /> <AppStoreCategories categories={categories} />
<Slider /> <Slider items={appStore} />
<AllApps /> <AllApps apps={appStore} />
</AppsShell> </AppsShell>
</Shell> </Shell>
); );
} }
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,
},
};
};

View File

@ -1,38 +1,9 @@
import fs from "fs"; export function getAppRegistry() {
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() {
return [ return [
{ {
name: "Zoom", name: "Zoom",
slug: "zoom", // needs to be the same as the folder name slug: "zoom", // needs to be the same as the folder name
category: "Video Conferencing", category: "video",
description: description:
"Zoom is the most popular video conferencing platform, joinable on the web or via desktop/mobile apps.", "Zoom is the most popular video conferencing platform, joinable on the web or via desktop/mobile apps.",
logo: "/apps/zoom.svg", logo: "/apps/zoom.svg",
@ -45,7 +16,7 @@ export function appRegistry() {
{ {
name: "Cal Video", name: "Cal Video",
slug: "cal-video", slug: "cal-video",
category: "Video Conferencing", category: "video",
description: 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.", "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", logo: "/apps/daily.svg",
@ -59,7 +30,7 @@ export function appRegistry() {
{ {
name: "Google Meet", name: "Google Meet",
slug: "google-meet", slug: "google-meet",
category: "Video Conferencing", category: "video",
description: description:
"Google Meet is Google's web-based video conferencing platform, designed to compete with major conferencing platforms.", "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", logo: "https://cdn.iconscout.com/icon/free/png-256/google-meet-2923654-2416657.png",
@ -69,8 +40,8 @@ export function appRegistry() {
}, },
{ {
name: "Stripe", name: "Stripe",
slug: "stripe", slug: "stripe_payment",
category: "Payments", category: "payment",
description: "Stripe is the world's leading payment provider. Start charging for your bookings today.", description: "Stripe is the world's leading payment provider. Start charging for your bookings today.",
logo: "/apps/stripe.svg", logo: "/apps/stripe.svg",
rating: 4.6, rating: 4.6,
@ -80,7 +51,7 @@ export function appRegistry() {
{ {
name: "Google Calendar", name: "Google Calendar",
slug: "google-calendar", slug: "google-calendar",
category: "Calendar", category: "calendar",
description: description:
"Google Calendar is the most popular calendar platform for personal and business calendars.", "Google Calendar is the most popular calendar platform for personal and business calendars.",
logo: "/apps/google-calendar.svg", logo: "/apps/google-calendar.svg",
@ -90,7 +61,7 @@ export function appRegistry() {
{ {
name: "Microsoft 365/Outlook Calendar", name: "Microsoft 365/Outlook Calendar",
slug: "microsoft-365", slug: "microsoft-365",
category: "Calendar", category: "calendar",
description: description:
"Microsoft 365 calendars for business users, and Outlook is a popular calendar platform for personal users.", "Microsoft 365 calendars for business users, and Outlook is a popular calendar platform for personal users.",
logo: "/apps/outlook.svg", logo: "/apps/outlook.svg",
@ -100,7 +71,7 @@ export function appRegistry() {
{ {
name: "CalDAV", name: "CalDAV",
slug: "caldav", slug: "caldav",
category: "Calendar", category: "calendar",
description: "CalDAV is an open calendar standard which connects to virtually every calendar.", description: "CalDAV is an open calendar standard which connects to virtually every calendar.",
logo: "/apps/caldav.svg", logo: "/apps/caldav.svg",
rating: 3.6, rating: 3.6,
@ -109,7 +80,7 @@ export function appRegistry() {
{ {
name: "iCloud Calendar", name: "iCloud Calendar",
slug: "icloud-calendar", slug: "icloud-calendar",
category: "Calendar", category: "calendar",
description: description:
"iCloud Calendar is Apple's calendar platform for users of iCloud, and is used in the Apple Calendar app on iOS and macOS.", "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", logo: "/apps/apple-calendar.svg",