WIP
parent
a7523a7d5d
commit
3522af1a16
|
@ -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">
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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(),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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",
|
Loading…
Reference in New Issue