diff --git a/apps/web/server/routers/viewer.tsx b/apps/web/server/routers/viewer.tsx index 2894d3ce..8dcc1bf1 100644 --- a/apps/web/server/routers/viewer.tsx +++ b/apps/web/server/routers/viewer.tsx @@ -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({ diff --git a/packages/app-store/apiHandlers.tsx b/packages/app-store/apiHandlers.tsx index dffe83e9..c8535136 100644 --- a/packages/app-store/apiHandlers.tsx +++ b/packages/app-store/apiHandlers.tsx @@ -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"), }; diff --git a/packages/app-store/components.tsx b/packages/app-store/components.tsx index 5728fe91..39ebc962 100644 --- a/packages/app-store/components.tsx +++ b/packages/app-store/components.tsx @@ -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")), }; diff --git a/packages/app-store/index.ts b/packages/app-store/index.ts index 52e5cbaa..60e0f17e 100644 --- a/packages/app-store/index.ts +++ b/packages/app-store/index.ts @@ -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, }; diff --git a/packages/app-store/metadata.ts b/packages/app-store/metadata.ts index 3725f85e..210531a4 100644 --- a/packages/app-store/metadata.ts +++ b/packages/app-store/metadata.ts @@ -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, }; diff --git a/packages/app-store/metamask/README.mdx b/packages/app-store/metamask/README.mdx new file mode 100644 index 00000000..fccc15c2 --- /dev/null +++ b/packages/app-store/metamask/README.mdx @@ -0,0 +1,17 @@ +--- +items: + - /api/app-store/metamask/example1.png + - /api/app-store/metamask/example2.png +--- + + + +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) diff --git a/packages/app-store/metamask/_metadata.ts b/packages/app-store/metamask/_metadata.ts new file mode 100644 index 00000000..784d5bd1 --- /dev/null +++ b/packages/app-store/metamask/_metadata.ts @@ -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; diff --git a/packages/app-store/metamask/api/add.ts b/packages/app-store/metamask/api/add.ts new file mode 100644 index 00000000..2ecde7d2 --- /dev/null +++ b/packages/app-store/metamask/api/add.ts @@ -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"); +} diff --git a/packages/app-store/metamask/api/index.ts b/packages/app-store/metamask/api/index.ts new file mode 100644 index 00000000..4c0d2ead --- /dev/null +++ b/packages/app-store/metamask/api/index.ts @@ -0,0 +1 @@ +export { default as add } from "./add"; diff --git a/packages/app-store/metamask/components/InstallAppButton.tsx b/packages/app-store/metamask/components/InstallAppButton.tsx new file mode 100644 index 00000000..44098b83 --- /dev/null +++ b/packages/app-store/metamask/components/InstallAppButton.tsx @@ -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, + })} + + ); +} diff --git a/packages/app-store/metamask/components/index.ts b/packages/app-store/metamask/components/index.ts new file mode 100644 index 00000000..0d6008d4 --- /dev/null +++ b/packages/app-store/metamask/components/index.ts @@ -0,0 +1 @@ +export { default as InstallAppButton } from "./InstallAppButton"; diff --git a/packages/app-store/metamask/index.ts b/packages/app-store/metamask/index.ts new file mode 100644 index 00000000..5d372ced --- /dev/null +++ b/packages/app-store/metamask/index.ts @@ -0,0 +1,2 @@ +export * as api from "./api"; +export { metadata } from "./_metadata"; diff --git a/packages/app-store/metamask/package.json b/packages/app-store/metamask/package.json new file mode 100644 index 00000000..53accf78 --- /dev/null +++ b/packages/app-store/metamask/package.json @@ -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": "*" + } +} diff --git a/packages/app-store/metamask/static/example1.png b/packages/app-store/metamask/static/example1.png new file mode 100644 index 00000000..5a4869ba Binary files /dev/null and b/packages/app-store/metamask/static/example1.png differ diff --git a/packages/app-store/metamask/static/example2.png b/packages/app-store/metamask/static/example2.png new file mode 100644 index 00000000..5ddeb1b7 Binary files /dev/null and b/packages/app-store/metamask/static/example2.png differ diff --git a/packages/app-store/metamask/static/icon.svg b/packages/app-store/metamask/static/icon.svg new file mode 100644 index 00000000..6cb41ba9 --- /dev/null +++ b/packages/app-store/metamask/static/icon.svg @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/prisma/migrations/20220502154345_adds_metamask_giphy/migration.sql b/packages/prisma/migrations/20220502154345_adds_metamask_giphy/migration.sql new file mode 100644 index 00000000..6de4fe41 --- /dev/null +++ b/packages/prisma/migrations/20220502154345_adds_metamask_giphy/migration.sql @@ -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'; diff --git a/packages/prisma/seed-app-store.ts b/packages/prisma/seed-app-store.ts index 4b5368ac..85741e7a 100644 --- a/packages/prisma/seed-app-store.ts +++ b/packages/prisma/seed-app-store.ts @@ -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"], {