Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
91 changes: 91 additions & 0 deletions integrations/calcom/definitions/actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { z } from '@botpress/sdk'

export const getEventTypesInputSchema = z.object({
username: z.string().describe('The username of the Cal.com account').title('Username'),
})

export const getEventTypesOutputSchema = z.object({
eventTypes: z
.array(
z.object({
id: z.number().describe('The unique identifier of the event type').title('Event Type ID'),
lengthInMinutes: z.number().describe('The duration of the event type in minutes').title('Duration (minutes)'),
title: z.string().describe('The title of the event type').title('Title'),
slug: z.string().describe('The slug of the event type').title('Slug'),
description: z.string().describe('A brief description of the event type').title('Description'),
lengthInMinutesOptions: z
.array(z.number())
.describe('Available duration options for the event type')
.title('Duration Options (minutes)'),
})
)
.describe('A list of event types associated with the Cal.com account')
.title('Event Types'),
})

export const getAvailableTimeSlotsInputSchema = z.object({
eventTypeId: z.number().describe('The ID of the event type').title('Event Type ID'),
startDate: z
.string()
.optional()
.describe('Start date in YYYY-MM-DD format')
.describe('Start date in YYYY-MM-DD format')
.title('Start Date'),
endDate: z
.string()
.optional()
.describe('End date in YYYY-MM-DD format')
.describe('End date in YYYY-MM-DD format')
.title('End Date'),
})

export const getAvailableTimeSlotsOutputSchema = z.object({
slots: z
.record(z.string(), z.array(z.record(z.string(), z.string())))
.describe('Available time slots grouped by date')
.title('Available Time Slots'),
})

export const generateLinkInputSchema = z.object({
conversationId: z
.string()
.describe('The ID of the conversation')
.placeholder('{{ event.conversationId }}')
.title('Conversation ID'),
email: z
.string()
.email('Invalid email address')
.describe('The email of the user to send the link to')
.title('User Email'),
eventTypeId: z.number().describe('The ID of the event type').title('Event Type ID'),
})

export const generateLinkOutputSchema = z.object({
url: z.string().describe('The generated scheduling link').title('Scheduling Link URL'),
})

export const bookEventInputSchema = z.object({
eventTypeId: z.number().describe('The ID of the event type').title('Event Type ID'),
start: z
.string()
.describe('Start time in ISO 8601 format')
.describe('Start time in ISO 8601 format')
.title('Start Time'),
email: z
.string()
.email('Invalid email address')
.describe('The email of the user booking the event')
.title('User Email'),
name: z.string().describe('The name of the user booking the event').title('User Name'),
timeZone: z.string().describe('Time zone in IANA format, e.g., America/New_York').title('Time Zone'),
conversationId: z
.string()
.optional()
.placeholder('{{ event.conversationId }}')
.describe('The ID of the conversation')
.title('Conversation ID'),
})

export const bookEventOutputSchema = z.object({
success: z.boolean().describe('Indicates if the booking was successful').title('Success'),
})
15 changes: 15 additions & 0 deletions integrations/calcom/definitions/calcom.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { z } from '@botpress/sdk'

export const calcomEventTypeShema = z.object({
id: z.number().describe('The unique identifier of the event type').title('Event Type ID'),
lengthInMinutes: z.number().describe('The duration of the event type in minutes').title('Duration (minutes)'),
title: z.string().describe('The title of the event type').title('Title'),
slug: z.string().describe('The slug of the event type').title('Slug'),
description: z.string().describe('A brief description of the event type').title('Description'),
lengthInMinutesOptions: z
.array(z.number())
.optional()
.describe('Available duration options for the event type')
.title('Duration Options (minutes)'),
hidden: z.boolean().describe('Indicates if the event type is hidden').title('Hidden'),
})
1 change: 1 addition & 0 deletions integrations/calcom/hub.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This integration allows you to interact with the Cal.com scheduling platform. It provides actions to list all available events for a sepecific user and to book an event on behalf of a user.
17 changes: 17 additions & 0 deletions integrations/calcom/icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
61 changes: 61 additions & 0 deletions integrations/calcom/integration.definition.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { z, IntegrationDefinition } from '@botpress/sdk'
import {
bookEventInputSchema,
bookEventOutputSchema,
generateLinkInputSchema,
generateLinkOutputSchema,
getAvailableTimeSlotsInputSchema,
getAvailableTimeSlotsOutputSchema,
getEventTypesInputSchema,
getEventTypesOutputSchema,
} from './definitions/actions'

export default new IntegrationDefinition({
name: 'calcom',
title: 'Cal.com',
version: '0.4.0',
readme: 'hub.md',
icon: 'icon.svg',
description: 'Schedule meetings and manage events using the Cal.com scheduling platform.',
configuration: {
schema: z.object({
calcomApiKey: z
.string()
.describe('Your Cal.com API Key. You can find it in your Cal.com account settings.')
.title('Cal.com API Key'),
}),
},
user: {
tags: {
id: { title: 'User ID', description: 'The ID of the user' },
},
},
events: {},
actions: {
getEventTypes: {
title: 'Get Event Types',
description: 'Fetches all event types from Cal.com',
input: { schema: getEventTypesInputSchema },
output: { schema: getEventTypesOutputSchema },
},
getAvailableTimeSlots: {
title: 'Get Available Time Slots',
description:
'Fetches available time slots for a specific event type within a date range ( default to next 7 days if not provided )',
input: { schema: getAvailableTimeSlotsInputSchema },
output: { schema: getAvailableTimeSlotsOutputSchema },
},
generateLink: {
title: 'Generate a link',
description: 'Generates a link to a calendar',
input: { schema: generateLinkInputSchema },
output: { schema: generateLinkOutputSchema },
},
bookEvent: {
title: 'Book an Event',
description: 'Books an event for a user',
input: { schema: bookEventInputSchema },
output: { schema: bookEventOutputSchema },
},
},
})
17 changes: 17 additions & 0 deletions integrations/calcom/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "@botpresshub/calcom",
"scripts": {
"build": "bp add -y && bp build",
"check:type": "tsc --noEmit",
"check:bplint": "bp lint"
},
"private": true,
"dependencies": {
"@botpress/client": "workspace:*",
"@botpress/sdk": "workspace:*",
"axios": "^1.11.0"
},
"devDependencies": {
"@botpress/cli": "workspace:*"
}
}
19 changes: 19 additions & 0 deletions integrations/calcom/src/actions/bookEvent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { ActionHandlerProps } from '@botpress/sdk/dist/integration'
import { CalcomApi } from 'src/calcom.api'
import { TIntegration } from '.botpress'
import { Input } from '.botpress/implementation/typings/actions/bookEvent/input'

export async function bookEvent(props: ActionHandlerProps<TIntegration, 'bookEvent', Input>) {
const { input, logger, ctx, client } = props

const calcom = new CalcomApi(ctx.configuration.calcomApiKey, logger.forBot())

const { start, email, name, eventTypeId, timeZone } = input
if (!email || !name || !eventTypeId) {
throw new Error('Email, Name and Event Type ID are required to book an event.')
}

const success = await calcom.bookEvent(eventTypeId, start, email, name, timeZone)

return { success }
}
17 changes: 17 additions & 0 deletions integrations/calcom/src/actions/generateLink.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { ActionHandlerProps } from '@botpress/sdk/dist/integration'
import { CalcomApi } from 'src/calcom.api'
import { TIntegration } from '.botpress'
import { Input } from '.botpress/implementation/typings/actions/generateLink/input'

export async function generateLink(
props: ActionHandlerProps<TIntegration, 'generateLink', Input>
): Promise<{ url: string }> {
const { input, ctx } = props

const calcom = new CalcomApi(ctx.configuration.calcomApiKey, props.logger.forBot())
const url = await calcom.generateLink(input.email, input.eventTypeId)

return {
url,
}
}
17 changes: 17 additions & 0 deletions integrations/calcom/src/actions/getAvailableTimeSlots.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { ActionHandlerProps } from '@botpress/sdk/dist/integration'
import { CalcomApi } from 'src/calcom.api'
import { TIntegration } from '.botpress'
import { Input } from '.botpress/implementation/typings/actions/getAvailableTimeSlots/input'

export async function getAvailableTimeSlots(props: ActionHandlerProps<TIntegration, 'getAvailableTimeSlots', Input>) {
const { ctx, logger, input } = props

const calcom = new CalcomApi(ctx.configuration.calcomApiKey, logger.forBot())
const startDate = input.startDate ? new Date(input.startDate) : new Date()
const endDate = input.endDate ? new Date(input.endDate) : new Date(startDate.getTime() + 7 * 24 * 60 * 60 * 1000) // Default to next 7 days
const timeSlots = await calcom.getAvailableTimeSlots(input.eventTypeId, startDate, endDate)

return {
slots: timeSlots || {},
}
}
22 changes: 22 additions & 0 deletions integrations/calcom/src/actions/getEventTypes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { ActionHandlerProps } from '@botpress/sdk/dist/integration'
import { CalcomApi, CalcomEventType } from 'src/calcom.api'
import { TIntegration } from '.botpress'
import { Input } from '.botpress/implementation/typings/actions/getEventTypes/input'

export async function getEventTypes(props: ActionHandlerProps<TIntegration, 'getEventTypes', Input>) {
const { ctx, logger, input } = props

const calcom = new CalcomApi(ctx.configuration.calcomApiKey, logger.forBot())
const eventTypes = await calcom.getAllEventTypes(input.username)

return {
eventTypes: eventTypes.map((et) => ({
id: et.id,
lengthInMinutes: et.lengthInMinutes,
title: et.title,
slug: et.slug,
description: et.description,
lengthInMinutesOptions: et.lengthInMinutesOptions ?? [],
})),
}
}
Loading
Loading