Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: make.com/integromat app #8897

Merged
merged 64 commits into from
Sep 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
aa59464
start make app integration
aar2dee2 May 15, 2023
6d9c0fa
Merge branch 'main' into integromat-app
aar2dee2 May 17, 2023
be0a13d
Merge branch 'main' into integromat-app
aar2dee2 May 25, 2023
e639b88
setup integration
aar2dee2 May 25, 2023
21f3c61
add relevant env vars
aar2dee2 May 25, 2023
75a4731
update app metadata
aar2dee2 May 25, 2023
a47f36a
import setup route in app setups
aar2dee2 May 25, 2023
cacd62b
fix typo
aar2dee2 May 25, 2023
993f8bb
add app store imports
aar2dee2 May 25, 2023
684e231
fix module import error
aar2dee2 May 25, 2023
c356f18
update make readme
aar2dee2 May 27, 2023
c0ea35f
Merge branch 'main' into integromat-app
aar2dee2 May 27, 2023
ea6f486
Merge branch 'main' into integromat-app
aar2dee2 Jun 5, 2023
2a5d2ea
move scheduler to app-store utils
aar2dee2 Jun 5, 2023
f112033
Merge branch 'main' into integromat-app
aar2dee2 Jun 6, 2023
e208d90
move add subscription to node scheduler
aar2dee2 Jun 6, 2023
e63430d
Merge branch 'main' into integromat-app
aar2dee2 Jun 28, 2023
486a24c
move delete subscription to scheduler
aar2dee2 Jul 1, 2023
d7067a1
subscribe unsubscribe in zapier using common nodeScheduler
aar2dee2 Jul 1, 2023
89c8193
Merge branch 'main' into integromat-app
aar2dee2 Jul 1, 2023
c41dbe6
Merge branch 'main' into integromat-app
PeerRich Jul 3, 2023
f5911d8
Merge branch 'main' into integromat-app
CarinaWolli Jul 3, 2023
a25f97a
Merge branch 'main' into integromat-app
aar2dee2 Jul 4, 2023
b0f89df
fix lint errors
aar2dee2 Jul 4, 2023
1ef52c2
Merge branch 'main' into integromat-app
PeerRich Jul 5, 2023
5c94655
revert settings.json
aar2dee2 Jul 5, 2023
3171b26
update icon
aar2dee2 Jul 5, 2023
fb59ff0
add app screenshots
aar2dee2 Jul 5, 2023
02e037e
fix app description
aar2dee2 Jul 5, 2023
b696af8
merge main
aar2dee2 Aug 14, 2023
1f85a27
fix type errors
aar2dee2 Aug 14, 2023
9536f33
update app code
aar2dee2 Aug 14, 2023
01ba41e
Merge branch 'main' into integromat-app
aar2dee2 Aug 14, 2023
230ebbd
Delete .gitkeep
CarinaWolli Aug 24, 2023
70c1f3e
delete unused template files
aar2dee2 Aug 25, 2023
398b6d0
get app invite link from env vars
aar2dee2 Aug 25, 2023
613b3ae
chore: handle error, cleanup readme, address review comments
aar2dee2 Aug 25, 2023
d92a6ab
fix: update link in readme
aar2dee2 Aug 25, 2023
2d7f054
revert yarn.lock
aar2dee2 Aug 25, 2023
28c570b
Merge branch 'main' into integromat-app
aar2dee2 Aug 25, 2023
2a3d58f
fix type errors
aar2dee2 Aug 25, 2023
cc25243
Merge branch 'main' into integromat-app
aar2dee2 Aug 29, 2023
4058cbc
Merge branch 'main' into integromat-app
PeerRich Aug 30, 2023
6bfabe4
Merge branch 'main' into integromat-app
PeerRich Aug 30, 2023
84d8504
Update packages/prisma/seed-app-store.ts
hariombalhara Aug 31, 2023
f21ae3b
Update .env.appStore.example
hariombalhara Aug 31, 2023
6ace33e
Update .env.appStore.example
hariombalhara Aug 31, 2023
d4bb915
update app readme
aar2dee2 Aug 31, 2023
c4bfe98
fix param name in deleteSubcription
aar2dee2 Aug 31, 2023
e0a8cf9
fix listBookings handler
aar2dee2 Aug 31, 2023
786ca13
Update turbo.json
hariombalhara Aug 31, 2023
a236eca
use default installation handler to install app
aar2dee2 Aug 31, 2023
bb29b20
use logger for console logs
aar2dee2 Aug 31, 2023
789b06a
Fix inviteLink reading
hariombalhara Aug 31, 2023
421f601
Merge remote-tracking branch 'aar2dee2/integromat-app' into integroma…
hariombalhara Aug 31, 2023
2d63712
fix app setup handler
aar2dee2 Aug 31, 2023
2bc478b
Fix type issue
hariombalhara Aug 31, 2023
0a50ce6
always show app invite link
aar2dee2 Aug 31, 2023
4a84a16
Merge branch 'main' into integromat-app
Aug 31, 2023
fdcc6a8
fix type error
Aug 31, 2023
d58d71b
Merge branch 'main' into integromat-app
CarinaWolli Aug 31, 2023
c35c0aa
add make invite link
Aug 31, 2023
711c533
Merge branch 'integromat-app' of https://github.com/aar2dee2/cal.com …
Aug 31, 2023
ef684b5
Merge branch 'main' into integromat-app
CarinaWolli Sep 4, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions apps/web/public/static/locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -1053,12 +1053,15 @@
"how_you_want_add_cal_site": "How do you want to add {{appName}} to your site?",
"choose_ways_put_cal_site": "Choose one of the following ways to put {{appName}} on your site.",
"setting_up_zapier": "Setting up your Zapier integration",
"setting_up_make": "Setting up your Make integration",
"generate_api_key": "Generate API key",
"generate_api_key_description": "Generate an API key to use with {{appName}} at",
"your_unique_api_key": "Your unique API key",
"copy_safe_api_key": "Copy this API key and save it somewhere safe. If you lose this key you have to generate a new one.",
"zapier_setup_instructions": "<0>Log into your Zapier account and create a new Zap.</0><1>Select Cal.com as your Trigger app. Also choose a Trigger event.</1><2>Choose your account and then enter your Unique API Key.</2><3>Test your Trigger.</3><4>You're set!</4>",
"make_setup_instructions": "<0>Log into your Make account and create a new Scenario.</0><1>Select Cal.com as your Trigger app. Also choose a Trigger event.</1><2>Choose your account and then enter your Unique API Key.</2><3>Test your Trigger.</3><4>You're set!</4>",
"install_zapier_app": "Please first install the Zapier App in the app store.",
"install_make_app": "Please first install the Make App in the app store.",
"connect_apple_server": "Connect to Apple Server",
"calendar_url": "Calendar URL",
"apple_server_generate_password": "Generate an app specific password to use with {{appName}} at",
Expand Down Expand Up @@ -1089,6 +1092,7 @@
"or_lowercase": "or",
"nevermind": "Nevermind",
"go_to": "Go to: ",
"invite_link_make": "<li>Go to<a>Make Invite Link</a> and install Cal.com appp</li>",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo here. It's app

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thx. will fix in a different PR

"zapier_invite_link": "Zapier Invite Link",
"meeting_url_provided_after_confirmed": "A Meeting URL will be created once the event is confirmed.",
"dynamically_display_attendee_or_organizer": "Dynamically display the name of your attendee for you, or your name if it's viewed by your attendee",
Expand Down
1 change: 1 addition & 0 deletions packages/app-store/_pages/setup/_getStaticProps.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { GetStaticPropsContext } from "next";

export const AppSetupPageMap = {
zapier: import("../../zapier/pages/setup/_getStaticProps"),
make: import("../../make/pages/setup/_getStaticProps"),
};

export const getStaticProps = async (ctx: GetStaticPropsContext) => {
Expand Down
1 change: 1 addition & 0 deletions packages/app-store/_pages/setup/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export const AppSetupMap = {
"exchange2016-calendar": dynamic(() => import("../../exchange2016calendar/pages/setup")),
"caldav-calendar": dynamic(() => import("../../caldavcalendar/pages/setup")),
zapier: dynamic(() => import("../../zapier/pages/setup")),
make: dynamic(() => import("../../make/pages/setup")),
closecom: dynamic(() => import("../../closecom/pages/setup")),
sendgrid: dynamic(() => import("../../sendgrid/pages/setup")),
paypal: dynamic(() => import("../../paypal/pages/setup")),
Expand Down
2 changes: 2 additions & 0 deletions packages/app-store/apps.keys-schemas.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { appKeysSchema as gtm_zod_ts } from "./gtm/zod";
import { appKeysSchema as hubspot_zod_ts } from "./hubspot/zod";
import { appKeysSchema as jitsivideo_zod_ts } from "./jitsivideo/zod";
import { appKeysSchema as larkcalendar_zod_ts } from "./larkcalendar/zod";
import { appKeysSchema as make_zod_ts } from "./make/zod";
import { appKeysSchema as metapixel_zod_ts } from "./metapixel/zod";
import { appKeysSchema as office365calendar_zod_ts } from "./office365calendar/zod";
import { appKeysSchema as office365video_zod_ts } from "./office365video/zod";
Expand Down Expand Up @@ -43,6 +44,7 @@ export const appKeysSchemas = {
hubspot: hubspot_zod_ts,
jitsivideo: jitsivideo_zod_ts,
larkcalendar: larkcalendar_zod_ts,
make: make_zod_ts,
metapixel: metapixel_zod_ts,
office365calendar: office365calendar_zod_ts,
office365video: office365video_zod_ts,
Expand Down
2 changes: 2 additions & 0 deletions packages/app-store/apps.metadata.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { metadata as hubspot__metadata_ts } from "./hubspot/_metadata";
import { metadata as huddle01video__metadata_ts } from "./huddle01video/_metadata";
import { metadata as jitsivideo__metadata_ts } from "./jitsivideo/_metadata";
import { metadata as larkcalendar__metadata_ts } from "./larkcalendar/_metadata";
import make_config_json from "./make/config.json";
import metapixel_config_json from "./metapixel/config.json";
import mirotalk_config_json from "./mirotalk/config.json";
import n8n_config_json from "./n8n/config.json";
Expand Down Expand Up @@ -99,6 +100,7 @@ export const appStoreMetadata = {
huddle01video: huddle01video__metadata_ts,
jitsivideo: jitsivideo__metadata_ts,
larkcalendar: larkcalendar__metadata_ts,
make: make_config_json,
metapixel: metapixel_config_json,
mirotalk: mirotalk_config_json,
n8n: n8n_config_json,
Expand Down
2 changes: 2 additions & 0 deletions packages/app-store/apps.schemas.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { appDataSchema as gtm_zod_ts } from "./gtm/zod";
import { appDataSchema as hubspot_zod_ts } from "./hubspot/zod";
import { appDataSchema as jitsivideo_zod_ts } from "./jitsivideo/zod";
import { appDataSchema as larkcalendar_zod_ts } from "./larkcalendar/zod";
import { appDataSchema as make_zod_ts } from "./make/zod";
import { appDataSchema as metapixel_zod_ts } from "./metapixel/zod";
import { appDataSchema as office365calendar_zod_ts } from "./office365calendar/zod";
import { appDataSchema as office365video_zod_ts } from "./office365video/zod";
Expand Down Expand Up @@ -43,6 +44,7 @@ export const appDataSchemas = {
hubspot: hubspot_zod_ts,
jitsivideo: jitsivideo_zod_ts,
larkcalendar: larkcalendar_zod_ts,
make: make_zod_ts,
metapixel: metapixel_zod_ts,
office365calendar: office365calendar_zod_ts,
office365video: office365video_zod_ts,
Expand Down
1 change: 1 addition & 0 deletions packages/app-store/apps.server.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export const apiHandlers = {
huddle01video: import("./huddle01video/api"),
jitsivideo: import("./jitsivideo/api"),
larkcalendar: import("./larkcalendar/api"),
make: import("./make/api"),
metapixel: import("./metapixel/api"),
mirotalk: import("./mirotalk/api"),
n8n: import("./n8n/api"),
Expand Down
1 change: 1 addition & 0 deletions packages/app-store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const appStore = {
webexvideo: () => import("./webex"),
giphy: () => import("./giphy"),
zapier: () => import("./zapier"),
make: () => import("./make"),
exchange2013calendar: () => import("./exchange2013calendar"),
exchange2016calendar: () => import("./exchange2016calendar"),
exchangecalendar: () => import("./exchangecalendar"),
Expand Down
10 changes: 10 additions & 0 deletions packages/app-store/make/DESCRIPTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
items:
- 1.jpeg
- 2.jpeg
- 3.jpeg
- 4.jpeg
- 5.jpeg
---

Workflow automation for everyone. Use the Cal.com app in Make to automate your workflows when a booking is created, rescheduled, cancelled or when a meeting has ended. You can also get all your booking with the 'List Bookings' module.<br /><br />**After Installation:** Have you lost your API key? You can always generate a new key on the <a href="/apps/make/setup">**<ins>Make Setup Page</ins>**</a>
22 changes: 22 additions & 0 deletions packages/app-store/make/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Setting up Make Integration
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@aar2dee2 I don't see the instructions on how to create the app on make.com.
We have something similar for zapier https://github.com/aar2dee2/cal.com/blob/6bfabe41e5073ff3a9e38d577ef6d72be2d6eca8/packages/app-store/zapier/README.md#L8

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just updated the readme. Request @CarinaWolli to look at point 5 - how did add the app to scenarios once you had the invite link?
5. Search for Cal.com in the apps list and select from the list of triggers - Booking Created, Booking Deleted, Booking Rescheduled, Meeting Ended



1. Install the app from the Cal app store and generate an API key. Copy the API key.
2. Go to `/admin/apps/automation` in Cal and set the `invite_link` for Make to `https://www.make.com/en/hq/app-invitation/6cb2772b61966508dd8f414ba3b44510` to use the app.
3. Create a [Make account](https://www.make.com/en/login), if you don't have one.
4. Go to `Scenarios` in the sidebar and click on **Create a new scenario**.
5. Search for `Cal.com` in the apps list and select from the list of triggers - Booking Created, Booking Deleted, Booking Rescheduled, Meeting Ended
6. To create a **connection** you will need your Cal deployment url and the app API Key generated above. You only need to create a **connection** once, all webhooks can use that connection.
7. Setup the webhook for the desired event in Make.
8. To delete a webhook, go to `Webhooks` in the left sidebar in Make, pick the webhook you want to delete and click **delete**.

## Localhost or Self-hosting

Localhost urls can not be used as the base URL for api endpoints

Possible solution: using [https://ngrok.com/](https://ngrok.com/)

1. Create Account
2. [Download](https://ngrok.com/download) ngrok and start a tunnel to your running localhost
- Use forwarding url as your baseUrl for the URL endpoints
3. Use the ngrok url as your Cal deployment url when creating the **Connection** in Make.
20 changes: 20 additions & 0 deletions packages/app-store/make/api/add.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { createDefaultInstallation } from "@calcom/app-store/_utils/installation";
import type { AppDeclarativeHandler } from "@calcom/types/AppHandler";

import appConfig from "../config.json";

const handler: AppDeclarativeHandler = {
appType: appConfig.type,
variant: appConfig.variant,
slug: appConfig.slug,
supportsMultipleInstalls: false,
handlerType: "add",
redirect: {
newTab: true,
url: "/apps/make/setup",
},
createCredential: ({ appType, user, slug, teamId }) =>
createDefaultInstallation({ appType, userId: user.id, slug, key: {}, teamId }),
};

export default handler;
5 changes: 5 additions & 0 deletions packages/app-store/make/api/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export { default as add } from "./add";
export { default as listBookings } from "./subscriptions/listBookings";
export { default as deleteSubscription } from "./subscriptions/deleteSubscription";
export { default as addSubscription } from "./subscriptions/addSubscription";
export { default as me } from "./subscriptions/me";
38 changes: 38 additions & 0 deletions packages/app-store/make/api/subscriptions/addSubscription.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import type { NextApiRequest, NextApiResponse } from "next";

import findValidApiKey from "@calcom/features/ee/api-keys/lib/findValidApiKey";
import { addSubscription } from "@calcom/features/webhooks/lib/scheduleTrigger";
import { defaultHandler, defaultResponder } from "@calcom/lib/server";

async function handler(req: NextApiRequest, res: NextApiResponse) {
const apiKey = req.query.apiKey as string;

if (!apiKey) {
return res.status(401).json({ message: "No API key provided" });
}

const validKey = await findValidApiKey(apiKey, "make");

if (!validKey) {
return res.status(401).json({ message: "API key not valid" });
}

const { subscriberUrl, triggerEvent } = req.body;

const createAppSubscription = await addSubscription({
appApiKey: validKey,
triggerEvent: triggerEvent,
subscriberUrl: subscriberUrl,
appId: "make",
});

if (!createAppSubscription) {
return res.status(500).json({ message: "Could not create subscription." });
}

res.status(200).json(createAppSubscription);
}

export default defaultHandler({
POST: Promise.resolve({ default: defaultResponder(handler) }),
});
40 changes: 40 additions & 0 deletions packages/app-store/make/api/subscriptions/deleteSubscription.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import type { NextApiRequest, NextApiResponse } from "next";
import z from "zod";

import findValidApiKey from "@calcom/features/ee/api-keys/lib/findValidApiKey";
import { deleteSubscription } from "@calcom/features/webhooks/lib/scheduleTrigger";
import { defaultHandler, defaultResponder } from "@calcom/lib/server";

const querySchema = z.object({
apiKey: z.string(),
id: z.string(),
});

async function handler(req: NextApiRequest, res: NextApiResponse) {
const { apiKey, id } = querySchema.parse(req.query);

if (!apiKey) {
return res.status(401).json({ message: "No API key provided" });
}

const validKey = await findValidApiKey(apiKey, "make");

if (!validKey) {
return res.status(401).json({ message: "API key not valid" });
}

const deleteEventSubscription = await deleteSubscription({
appApiKey: validKey,
webhookId: id,
appId: "make",
});

if (!deleteEventSubscription) {
return res.status(500).json({ message: "Could not delete subscription." });
}
res.status(204).json({ message: "Subscription is deleted." });
}

export default defaultHandler({
DELETE: Promise.resolve({ default: defaultResponder(handler) }),
});
35 changes: 35 additions & 0 deletions packages/app-store/make/api/subscriptions/listBookings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import type { NextApiRequest, NextApiResponse } from "next";

import findValidApiKey from "@calcom/features/ee/api-keys/lib/findValidApiKey";
import { listBookings } from "@calcom/features/webhooks/lib/scheduleTrigger";
import { defaultHandler, defaultResponder } from "@calcom/lib/server";

async function handler(req: NextApiRequest, res: NextApiResponse) {
const apiKey = req.query.apiKey as string;

if (!apiKey) {
return res.status(401).json({ message: "No API key provided" });
}

const validKey = await findValidApiKey(apiKey, "make");

if (!validKey) {
return res.status(401).json({ message: "API key not valid" });
}
const bookings = await listBookings(validKey);

if (!bookings) {
return res.status(500).json({ message: "Unable to get bookings." });
}
if (bookings.length === 0) {
const requested = validKey.teamId ? "teamId: " + validKey.teamId : "userId: " + validKey.userId;
return res.status(404).json({
message: `There are no bookings to retrieve, please create a booking first. Requested: \`${requested}\``,
});
}
res.status(201).json(bookings);
}

export default defaultHandler({
GET: Promise.resolve({ default: defaultResponder(handler) }),
});
35 changes: 35 additions & 0 deletions packages/app-store/make/api/subscriptions/me.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import type { NextApiRequest, NextApiResponse } from "next";

import findValidApiKey from "@calcom/features/ee/api-keys/lib/findValidApiKey";
import prisma from "@calcom/prisma";

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const apiKey = req.query.apiKey as string;

if (!apiKey) {
return res.status(401).json({ message: "No API key provided" });
}

const validKey = await findValidApiKey(apiKey, "make");

if (!validKey) {
return res.status(401).json({ message: "API key not valid" });
}

if (req.method === "GET") {
try {
const user = await prisma.user.findFirst({
where: {
id: validKey.userId,
},
select: {
username: true,
},
});
res.status(201).json(user);
} catch (error) {
console.error(error);
return res.status(500).json({ message: "Unable to get User." });
}
}
}
18 changes: 18 additions & 0 deletions packages/app-store/make/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"/*": "Don't modify slug - If required, do it using cli edit command",
"name": "Make",
"slug": "make",
"type": "make_automation",
"logo": "icon.svg",
"url": "https://cal.com/apps/make",
"variant": "automation",
"categories": ["automation"],
"publisher": "aa2dee2",
"email": "support@cal.com",
"description": "Automate workflows",
"isTemplate": false,
"__createdUsingCli": true,
"__template": "basic",
"imageSrc": "icon.svg",
"dirName": "make"
}
1 change: 1 addition & 0 deletions packages/app-store/make/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * as api from "./api";
15 changes: 15 additions & 0 deletions packages/app-store/make/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"$schema": "https://json.schemastore.org/package.json",
"private": true,
"name": "@calcom/make",
"version": "0.0.0",
"main": "./index.ts",
"description": "Workflow automation for everyone. Use the Cal.com Make app to trigger your workflows when a booking is created, rescheduled, or cancelled, or after a meeting ends.",
"dependencies": {
"@calcom/lib": "*"
},
"devDependencies": {
"@calcom/types": "*",
"@types/node-schedule": "^2.1.0"
}
}
20 changes: 20 additions & 0 deletions packages/app-store/make/pages/setup/_getStaticProps.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import type { GetStaticPropsContext } from "next";

import getAppKeysFromSlug from "../../../_utils/getAppKeysFromSlug";

export interface IMakeSetupProps {
inviteLink: string;
}

export const getStaticProps = async (ctx: GetStaticPropsContext) => {
if (typeof ctx.params?.slug !== "string") return { notFound: true } as const;
let inviteLink = "";
const appKeys = await getAppKeysFromSlug("make");
if (typeof appKeys.invite_link === "string") inviteLink = appKeys.invite_link;

return {
props: {
inviteLink,
},
};
};
Loading