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 AppCard from "./AppCard";
export default function AllApps() {
export default function AllApps({ apps }: { apps: App[] }) {
const { t } = useLocale();
const apps = appRegistry();
return (
<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.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 = <T extends App>({ 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() {
</div>
<div className="glide__track" data-glide-el="track">
<ul className="glide__slides">
{apps.map((app) => {
{items.map((app) => {
return (
app.trending && (
<li key={app.name} className="glide__slide">
@ -71,4 +70,6 @@ export default function Slider() {
</div>
</div>
);
}
};
export default Slider;

View File

@ -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;
};

View File

@ -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<typeof getStaticProps>) {
const { t } = useLocale();
const router = useRouter();
const apps = appRegistry();
return (
<Shell
@ -27,7 +27,7 @@ export default function Apps() {
<div className="mb-16">
<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">
{apps.map((app) => {
{appStore.map((app) => {
return (
app.category === router.query.category && (
<AppCard
@ -46,3 +46,26 @@ export default function Apps() {
</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 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 (
<Shell heading={t("app_store")} subtitle={t("app_store_description")} large>
<AppsShell>
<AppStoreCategories categories={popularCategories} />
<Slider />
<AllApps />
<AppStoreCategories categories={categories} />
<Slider items={appStore} />
<AllApps apps={appStore} />
</AppsShell>
</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";
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",