Add Meta Mask to app store (#2650)
* Adds available apps * Adds App Model * WIP * Create meta mask app folder * Add description and images * Remove credential from installed apps page * Updates seeder script * Seeder fixes * lowercase categories * Upgrades prisma * WIP * WIP * Hopefully fixes circular deps * Type fixes * Fixes seeder * Adds migration to connect Credentials to Apps * Updates app store callbacks * Updates google credentials * Uses dirName from DB * Type fixes * Update reschedule.ts * Seeder fixes * Fixes categories listing * Update index.ts * Update schema.prisma * Updates dependencies * Renames giphy app * Uses dynamic imports for app metadata * Fixes credentials error * Uses dynamic import for api handlers * Dynamic import fixes * Allows for simple folder names in app store * Remove video adaptor * Squashes app migrations * seeder fixes * Renames to metamask * Updates metamask metadata * Fixes dyamic imports * Remove comments * Create migration.sql Co-authored-by: zomars <zomars@me.com> Co-authored-by: Peer Richelsen <peeroke@gmail.com>
This commit is contained in:
parent
6a27fb2959
commit
7f463830bd
18 changed files with 190 additions and 6 deletions
|
@ -532,15 +532,10 @@ const loggedInViewerRouter = createProtectedRouter()
|
|||
});
|
||||
|
||||
if (web3Credential) {
|
||||
return ctx.prisma.credential.update({
|
||||
return ctx.prisma.credential.delete({
|
||||
where: {
|
||||
id: web3Credential.id,
|
||||
},
|
||||
data: {
|
||||
key: {
|
||||
isWeb3Active: !(web3Credential.key as JSONObject).isWeb3Active,
|
||||
},
|
||||
},
|
||||
});
|
||||
} else {
|
||||
return ctx.prisma.credential.create({
|
||||
|
|
|
@ -13,6 +13,7 @@ export const apiHandlers = {
|
|||
wipemycalother: import("./wipemycalother/api"),
|
||||
jitsivideo: import("./jitsivideo/api"),
|
||||
huddle01video: import("./huddle01video/api"),
|
||||
metamask: import("./metamask/api"),
|
||||
giphy: import("./giphy/api"),
|
||||
};
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ export const InstallAppButtonMap = {
|
|||
wipemycalother: dynamic(() => import("./wipemycalother/components/InstallAppButton")),
|
||||
jitsivideo: dynamic(() => import("./jitsivideo/components/InstallAppButton")),
|
||||
huddle01video: dynamic(() => import("./huddle01video/components/InstallAppButton")),
|
||||
metamask: dynamic(() => import("./metamask/components/InstallAppButton")),
|
||||
giphy: dynamic(() => import("./giphy/components/InstallAppButton")),
|
||||
};
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import * as googlevideo from "./googlevideo";
|
|||
import * as hubspotothercalendar from "./hubspotothercalendar";
|
||||
import * as huddle01video from "./huddle01video";
|
||||
import * as jitsivideo from "./jitsivideo";
|
||||
import * as metamask from "./metamask";
|
||||
import * as office365calendar from "./office365calendar";
|
||||
import * as office365video from "./office365video";
|
||||
import * as slackmessaging from "./slackmessaging";
|
||||
|
@ -33,6 +34,7 @@ const appStore = {
|
|||
tandemvideo,
|
||||
zoomvideo,
|
||||
wipemycalother,
|
||||
metamask,
|
||||
giphy,
|
||||
};
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import { metadata as googlevideo } from "./googlevideo/_metadata";
|
|||
import { metadata as hubspotothercalendar } from "./hubspotothercalendar/_metadata";
|
||||
import { metadata as huddle01video } from "./huddle01video/_metadata";
|
||||
import { metadata as jitsivideo } from "./jitsivideo/_metadata";
|
||||
import { metadata as metamask } from "./metamask/_metadata";
|
||||
import { metadata as office365calendar } from "./office365calendar/_metadata";
|
||||
import { metadata as office365video } from "./office365video/_metadata";
|
||||
import { metadata as slackmessaging } from "./slackmessaging/_metadata";
|
||||
|
@ -31,6 +32,7 @@ export const appStoreMetadata = {
|
|||
tandemvideo,
|
||||
zoomvideo,
|
||||
wipemycalother,
|
||||
metamask,
|
||||
giphy,
|
||||
};
|
||||
|
||||
|
|
17
packages/app-store/metamask/README.mdx
Normal file
17
packages/app-store/metamask/README.mdx
Normal file
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
items:
|
||||
- /api/app-store/metamask/example1.png
|
||||
- /api/app-store/metamask/example2.png
|
||||
---
|
||||
|
||||
<Slider items={items} />
|
||||
|
||||
Only book and allow bookings from people who share the same tokens, DAOs, or NFTs.
|
||||
|
||||
Send a group scheduling link that only members of a DAO or token-based community can join.
|
||||
|
||||
Share your booking link and be sure to only receive bookings from owners of your chosen tokens or coins.
|
||||
|
||||
Provide office hours for other DAO members or outsiders who want to learn more from you.
|
||||
|
||||
[Click here to learn more](https://cal.com/web3)
|
26
packages/app-store/metamask/_metadata.ts
Normal file
26
packages/app-store/metamask/_metadata.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
import type { App } from "@calcom/types/App";
|
||||
|
||||
import _package from "./package.json";
|
||||
|
||||
export const metadata = {
|
||||
name: "MetaMask",
|
||||
description: _package.description,
|
||||
installed: true,
|
||||
category: "web3",
|
||||
// If using static next public folder, can then be referenced from the base URL (/).
|
||||
imageSrc: "/api/app-store/metamask/icon.svg",
|
||||
logo: "/api/app-store/metamask/icon.svg",
|
||||
publisher: "Cal.com",
|
||||
rating: 5,
|
||||
reviews: 69,
|
||||
slug: "metamask",
|
||||
title: "Meta Mask",
|
||||
trending: true,
|
||||
type: "metamask_web3",
|
||||
url: "https://cal.com/",
|
||||
variant: "other",
|
||||
verified: true,
|
||||
email: "help@cal.com",
|
||||
} as App;
|
||||
|
||||
export default metadata;
|
39
packages/app-store/metamask/api/add.ts
Normal file
39
packages/app-store/metamask/api/add.ts
Normal file
|
@ -0,0 +1,39 @@
|
|||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
|
||||
import prisma from "@calcom/prisma";
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
if (!req.session?.user?.id) {
|
||||
return res.status(401).json({ message: "You must be logged in to do this" });
|
||||
}
|
||||
|
||||
const appType = "metamask_web3";
|
||||
try {
|
||||
const alreadyInstalled = await prisma.credential.findFirst({
|
||||
where: {
|
||||
type: appType,
|
||||
userId: req.session.user.id,
|
||||
},
|
||||
});
|
||||
if (alreadyInstalled) {
|
||||
throw new Error("Already installed");
|
||||
}
|
||||
const installation = await prisma.credential.create({
|
||||
data: {
|
||||
type: appType,
|
||||
key: { isWeb3Active: true },
|
||||
userId: req.session.user.id,
|
||||
appId: "metamask",
|
||||
},
|
||||
});
|
||||
if (!installation) {
|
||||
throw new Error("Unable to create user credential for metamask");
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof Error) {
|
||||
return res.status(500).json({ message: error.message });
|
||||
}
|
||||
return res.status(500);
|
||||
}
|
||||
return res.redirect("/apps/installed");
|
||||
}
|
1
packages/app-store/metamask/api/index.ts
Normal file
1
packages/app-store/metamask/api/index.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export { default as add } from "./add";
|
18
packages/app-store/metamask/components/InstallAppButton.tsx
Normal file
18
packages/app-store/metamask/components/InstallAppButton.tsx
Normal file
|
@ -0,0 +1,18 @@
|
|||
import useAddAppMutation from "../../_utils/useAddAppMutation";
|
||||
import { InstallAppButtonProps } from "../../types";
|
||||
|
||||
export default function InstallAppButton(props: InstallAppButtonProps) {
|
||||
// @ts-ignore TODO: deprecate App types in favor of DB slugs
|
||||
const mutation = useAddAppMutation("metamask");
|
||||
|
||||
return (
|
||||
<>
|
||||
{props.render({
|
||||
onClick() {
|
||||
mutation.mutate("");
|
||||
},
|
||||
loading: mutation.isLoading,
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}
|
1
packages/app-store/metamask/components/index.ts
Normal file
1
packages/app-store/metamask/components/index.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export { default as InstallAppButton } from "./InstallAppButton";
|
2
packages/app-store/metamask/index.ts
Normal file
2
packages/app-store/metamask/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
export * as api from "./api";
|
||||
export { metadata } from "./_metadata";
|
14
packages/app-store/metamask/package.json
Normal file
14
packages/app-store/metamask/package.json
Normal file
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"private": true,
|
||||
"name": "@calcom/metamask",
|
||||
"version": "0.0.0",
|
||||
"main": "./index.ts",
|
||||
"description": "Only book and allow bookings from people who share the same tokens, DAOs, or NFTs.",
|
||||
"dependencies": {
|
||||
"@calcom/prisma": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@calcom/types": "*"
|
||||
}
|
||||
}
|
BIN
packages/app-store/metamask/static/example1.png
Normal file
BIN
packages/app-store/metamask/static/example1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 88 KiB |
BIN
packages/app-store/metamask/static/example2.png
Normal file
BIN
packages/app-store/metamask/static/example2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 515 KiB |
61
packages/app-store/metamask/static/icon.svg
Normal file
61
packages/app-store/metamask/static/icon.svg
Normal file
|
@ -0,0 +1,61 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 22.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns:ev="http://www.w3.org/2001/xml-events"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 318.6 318.6"
|
||||
style="enable-background:new 0 0 318.6 318.6;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#E2761B;stroke:#E2761B;stroke-linecap:round;stroke-linejoin:round;}
|
||||
.st1{fill:#E4761B;stroke:#E4761B;stroke-linecap:round;stroke-linejoin:round;}
|
||||
.st2{fill:#D7C1B3;stroke:#D7C1B3;stroke-linecap:round;stroke-linejoin:round;}
|
||||
.st3{fill:#233447;stroke:#233447;stroke-linecap:round;stroke-linejoin:round;}
|
||||
.st4{fill:#CD6116;stroke:#CD6116;stroke-linecap:round;stroke-linejoin:round;}
|
||||
.st5{fill:#E4751F;stroke:#E4751F;stroke-linecap:round;stroke-linejoin:round;}
|
||||
.st6{fill:#F6851B;stroke:#F6851B;stroke-linecap:round;stroke-linejoin:round;}
|
||||
.st7{fill:#C0AD9E;stroke:#C0AD9E;stroke-linecap:round;stroke-linejoin:round;}
|
||||
.st8{fill:#161616;stroke:#161616;stroke-linecap:round;stroke-linejoin:round;}
|
||||
.st9{fill:#763D16;stroke:#763D16;stroke-linecap:round;stroke-linejoin:round;}
|
||||
</style>
|
||||
<polygon class="st0" points="274.1,35.5 174.6,109.4 193,65.8 "/>
|
||||
<g>
|
||||
<polygon class="st1" points="44.4,35.5 143.1,110.1 125.6,65.8 "/>
|
||||
<polygon class="st1" points="238.3,206.8 211.8,247.4 268.5,263 284.8,207.7 "/>
|
||||
<polygon class="st1" points="33.9,207.7 50.1,263 106.8,247.4 80.3,206.8 "/>
|
||||
<polygon class="st1" points="103.6,138.2 87.8,162.1 144.1,164.6 142.1,104.1 "/>
|
||||
<polygon class="st1" points="214.9,138.2 175.9,103.4 174.6,164.6 230.8,162.1 "/>
|
||||
<polygon class="st1" points="106.8,247.4 140.6,230.9 111.4,208.1 "/>
|
||||
<polygon class="st1" points="177.9,230.9 211.8,247.4 207.1,208.1 "/>
|
||||
</g>
|
||||
<g>
|
||||
<polygon class="st2" points="211.8,247.4 177.9,230.9 180.6,253 180.3,262.3 "/>
|
||||
<polygon class="st2" points="106.8,247.4 138.3,262.3 138.1,253 140.6,230.9 "/>
|
||||
</g>
|
||||
<polygon class="st3" points="138.8,193.5 110.6,185.2 130.5,176.1 "/>
|
||||
<polygon class="st3" points="179.7,193.5 188,176.1 208,185.2 "/>
|
||||
<g>
|
||||
<polygon class="st4" points="106.8,247.4 111.6,206.8 80.3,207.7 "/>
|
||||
<polygon class="st4" points="207,206.8 211.8,247.4 238.3,207.7 "/>
|
||||
<polygon class="st4" points="230.8,162.1 174.6,164.6 179.8,193.5 188.1,176.1 208.1,185.2 "/>
|
||||
<polygon class="st4" points="110.6,185.2 130.6,176.1 138.8,193.5 144.1,164.6 87.8,162.1 "/>
|
||||
</g>
|
||||
<g>
|
||||
<polygon class="st5" points="87.8,162.1 111.4,208.1 110.6,185.2 "/>
|
||||
<polygon class="st5" points="208.1,185.2 207.1,208.1 230.8,162.1 "/>
|
||||
<polygon class="st5" points="144.1,164.6 138.8,193.5 145.4,227.6 146.9,182.7 "/>
|
||||
<polygon class="st5" points="174.6,164.6 171.9,182.6 173.1,227.6 179.8,193.5 "/>
|
||||
</g>
|
||||
<polygon class="st6" points="179.8,193.5 173.1,227.6 177.9,230.9 207.1,208.1 208.1,185.2 "/>
|
||||
<polygon class="st6" points="110.6,185.2 111.4,208.1 140.6,230.9 145.4,227.6 138.8,193.5 "/>
|
||||
<polygon class="st7" points="180.3,262.3 180.6,253 178.1,250.8 140.4,250.8 138.1,253 138.3,262.3 106.8,247.4 117.8,256.4
|
||||
140.1,271.9 178.4,271.9 200.8,256.4 211.8,247.4 "/>
|
||||
<polygon class="st8" points="177.9,230.9 173.1,227.6 145.4,227.6 140.6,230.9 138.1,253 140.4,250.8 178.1,250.8 180.6,253 "/>
|
||||
<g>
|
||||
<polygon class="st9" points="278.3,114.2 286.8,73.4 274.1,35.5 177.9,106.9 214.9,138.2 267.2,153.5 278.8,140 273.8,136.4
|
||||
281.8,129.1 275.6,124.3 283.6,118.2 "/>
|
||||
<polygon class="st9" points="31.8,73.4 40.3,114.2 34.9,118.2 42.9,124.3 36.8,129.1 44.8,136.4 39.8,140 51.3,153.5 103.6,138.2
|
||||
140.6,106.9 44.4,35.5 "/>
|
||||
</g>
|
||||
<polygon class="st6" points="267.2,153.5 214.9,138.2 230.8,162.1 207.1,208.1 238.3,207.7 284.8,207.7 "/>
|
||||
<polygon class="st6" points="103.6,138.2 51.3,153.5 33.9,207.7 80.3,207.7 111.4,208.1 87.8,162.1 "/>
|
||||
<polygon class="st6" points="174.6,164.6 177.9,106.9 193.1,65.8 125.6,65.8 140.6,106.9 144.1,164.6 145.3,182.8 145.4,227.6
|
||||
173.1,227.6 173.3,182.8 "/>
|
||||
</svg>
|
After Width: | Height: | Size: 3.9 KiB |
|
@ -0,0 +1,3 @@
|
|||
-- Connects each saved Credential to their respective App
|
||||
UPDATE "Credential" SET "appId" = 'metamask' WHERE "type" = 'metamask_web3';
|
||||
UPDATE "Credential" SET "appId" = 'giphy' WHERE "type" = 'giphy_other';
|
|
@ -77,6 +77,7 @@ async function main() {
|
|||
}
|
||||
// Web3 apps
|
||||
await createApp("huddle01", "huddle01video", ["web3", "video"]);
|
||||
await createApp("metamask", "metamask", ["web3"]);
|
||||
// Messaging apps
|
||||
if (process.env.SLACK_CLIENT_ID && process.env.SLACK_CLIENT_SECRET && process.env.SLACK_SIGNING_SECRET) {
|
||||
await createApp("slack", "slackmessaging", ["messaging"], {
|
||||
|
|
Loading…
Reference in a new issue