Files
calendar/apps/web/pages/api/get-inbound-dynamic-variables.ts
T
+5
devin-ai-integration[bot]GitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>morgan@cal.com <morgan@cal.com>Anik Dhabal BabuBenny JooSahitya ChandraCarina WollendorferCarinaWollimintlify[bot] <109931778+mintlify[bot]@users.noreply.github.com>Ayush KumarSyed Ali ShahbazLauris Skraucissupalarryemrysal
ebeb008f9b refactor: convert findQualifiedHostsWithDelegationCredentials to service class with DI (#22974)
* refactor: convert findQualifiedHostsWithDelegationCredentials to service class with DI

- Create QualifiedHostsService class following UserAvailabilityService pattern
- Add IQualifiedHostsService interface with prisma and bookingRepo dependencies
- Create DI module and container for qualified hosts service
- Update filterHostsBySameRoundRobinHost to accept prisma as parameter
- Update all usage sites to use the new service:
  - loadAndValidateUsers.ts
  - slots/util.ts
  - test mocks in _post.test.ts
- Maintain backward compatibility with original function export
- Fix type issues in team properties (rrResetInterval, rrTimestampBasis)

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* fix: update filterHostsBySameRoundRobinHost test to include prisma parameter

- Add missing prisma parameter to all test function calls
- Resolves unit test failure caused by function signature change

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* fix: resolve type issues in FilterHostsService

- Import PrismaClient type instead of using unknown
- Fix type compatibility for BookingRepository constructor
- Update test mocks to use proper BookingRepository type
- Ensure all DI dependencies are properly typed

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* refactor: rename DI files to CamelCase and update imports

- Rename all files in packages/lib/di from kebab-case to CamelCase
- Update 22 external files with import statements to use new file names
- Update internal DI module files with corrected imports
- Maintain consistency with TypeScript naming conventions

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* chore: bump platform libs

* chore: bump platform libs

* fix: remove obsolete vitest mock after service class refactoring

- Remove obsolete mock for old function module
- Keep correct mock for new DI container
- Resolves CI unit test failures

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* fix: correct import path for calAIPhone zod-utils module

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* fix: Booker active booking limit can't be switched off (#23005)

* refactor: Get rid of `getServerSideProps` for /getting-started pages (#23003)

* refactor

* fix type check

* fix: Remove Reporting page within Routing Forms (#22990)

* fix error in handleNewBooking (#23011)

Co-authored-by: CarinaWolli <wollencarina@gmail.com>

* Documentation edits made through Mintlify web editor (#23007)

Co-authored-by: mintlify[bot] <109931778+mintlify[bot]@users.noreply.github.com>

* fix: Contact support button position changed from absolute to fixed (#23002)

* feat: Add private links to API (#22943)

* --init

* address change requests

* adding further changes

* address feedback

* further changes

* further clean-up

* clean up

* fix module import and others

* add guards

* remove unnecessary comments

* remove unnecessary comments

* cleanup

* sort coderabbig suggestions

* improve check

* chore: bump platform libraries

---------

Co-authored-by: Lauris Skraucis <lauris.skraucis@gmail.com>
Co-authored-by: supalarry <laurisskraucis@gmail.com>

* chore: release v5.5.15

* chore: bump platform libs

* chore: bump platform libs

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: morgan@cal.com <morgan@cal.com>
Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
Co-authored-by: Benny Joo <sldisek783@gmail.com>
Co-authored-by: Sahitya Chandra <sahityajb@gmail.com>
Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com>
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: mintlify[bot] <109931778+mintlify[bot]@users.noreply.github.com>
Co-authored-by: Ayush Kumar <kumarayushkumar@protonmail.com>
Co-authored-by: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com>
Co-authored-by: Lauris Skraucis <lauris.skraucis@gmail.com>
Co-authored-by: supalarry <laurisskraucis@gmail.com>
Co-authored-by: emrysal <me@alexvanandel.com>
2025-08-11 12:24:15 +00:00

114 lines
3.2 KiB
TypeScript

import advancedFormat from "dayjs/plugin/advancedFormat";
import type { NextApiRequest, NextApiResponse } from "next";
import { z } from "zod";
import dayjs from "@calcom/dayjs";
import { ZGetRetellLLMSchema } from "@calcom/features/calAIPhone/zod-utils";
import type { TGetRetellLLMSchema } from "@calcom/features/calAIPhone/zod-utils";
import { getAvailableSlotsService } from "@calcom/lib/di/containers/AvailableSlots";
import { fetcher } from "@calcom/lib/retellAIFetcher";
import { defaultHandler } from "@calcom/lib/server/defaultHandler";
import prisma from "@calcom/prisma";
dayjs.extend(advancedFormat);
const schema = z.object({
llm_id: z.string(),
from_number: z.string(),
to_number: z.string(),
});
const getEventTypeIdFromRetellLLM = (
retellLLM: TGetRetellLLMSchema
): { eventTypeId: number | undefined; timezone: string | undefined } => {
const { general_tools, states } = retellLLM;
const generalTool = general_tools.find((tool) => tool.event_type_id && tool.timezone);
if (generalTool) {
return { eventTypeId: generalTool.event_type_id, timezone: generalTool.timezone };
}
// If no general tool found, search in states
if (states) {
for (const state of states) {
const tool = state.tools.find((tool) => tool.event_type_id && tool.timezone);
if (tool) {
return { eventTypeId: tool.event_type_id, timezone: tool.timezone };
}
}
}
return { eventTypeId: undefined, timezone: undefined };
};
async function handler(req: NextApiRequest, res: NextApiResponse) {
const response = schema.safeParse(req.body);
if (!response.success) {
return res.status(400).send({
message: "Invalid Payload",
});
}
const body = response.data;
const retellLLM = await fetcher(`/get-retell-llm/${body.llm_id}`).then(ZGetRetellLLMSchema.parse);
const { eventTypeId, timezone } = getEventTypeIdFromRetellLLM(retellLLM);
if (!eventTypeId || !timezone)
return res.status(404).json({ message: "eventTypeId or Timezone not found" });
const eventType = await prisma.eventType.findUnique({
where: {
id: eventTypeId,
},
select: {
id: true,
teamId: true,
team: {
select: {
parent: {
select: {
slug: true,
},
},
},
},
},
});
if (!eventType) return res.status(404).json({ message: "eventType not found id" });
const now = dayjs();
const startTime = now.startOf("month").toISOString();
const endTime = now.add(2, "month").endOf("month").toISOString();
const orgSlug = eventType?.team?.parent?.slug ?? null;
const availableSlotsService = getAvailableSlotsService();
const availableSlots = await availableSlotsService.getAvailableSlots({
input: {
startTime,
endTime,
eventTypeId,
isTeamEvent: !!eventType?.teamId,
orgSlug,
},
});
const firstAvailableDate = Object.keys(availableSlots.slots)[0];
const firstSlot = availableSlots?.slots?.[firstAvailableDate]?.[0]?.time;
return res.status(200).json({
next_available: firstSlot
? dayjs.utc(firstSlot).tz(timezone).format(`dddd [the] Do [at] h:mma [${timezone} timezone]`)
: undefined,
});
}
export default defaultHandler({
POST: Promise.resolve({ default: handler }),
});