diff --git a/packages/features/troubleshooter/components/EventScheduleItem.tsx b/packages/features/troubleshooter/components/EventScheduleItem.tsx index df124610f5..45aa1d8c1b 100644 --- a/packages/features/troubleshooter/components/EventScheduleItem.tsx +++ b/packages/features/troubleshooter/components/EventScheduleItem.tsx @@ -31,7 +31,7 @@ export function EventScheduleItem() { suffixSlot={ schedule && ( - + {t("edit")} diff --git a/packages/features/troubleshooter/components/EventTypeSelect.tsx b/packages/features/troubleshooter/components/EventTypeSelect.tsx index bd29b4d59f..c430c6b2f6 100644 --- a/packages/features/troubleshooter/components/EventTypeSelect.tsx +++ b/packages/features/troubleshooter/components/EventTypeSelect.tsx @@ -1,4 +1,5 @@ import { useMemo, useEffect, startTransition } from "react"; +import { shallow } from "zustand/shallow"; import { trpc } from "@calcom/trpc"; import { SelectField } from "@calcom/ui/components/form"; @@ -7,67 +8,80 @@ import { getQueryParam } from "../../bookings/Booker/utils/query-param"; import { useTroubleshooterStore } from "../store"; export function EventTypeSelect() { - const { data: eventTypes, isPending } = trpc.viewer.eventTypes.list.useQuery(); - const selectedEventType = useTroubleshooterStore((state) => state.event); - const setSelectedEventType = useTroubleshooterStore((state) => state.setEvent); - - const selectedEventQueryParam = getQueryParam("eventType"); + const { data: eventTypes, isPending } = trpc.viewer.eventTypes.listWithTeam.useQuery(); + const { event: selectedEventType, setEvent: setSelectedEventType } = useTroubleshooterStore( + (state) => ({ + event: state.event, + setEvent: state.setEvent, + }), + shallow + ); const options = useMemo(() => { if (!eventTypes) return []; return eventTypes.map((e) => ({ label: e.title, - value: e.slug, + value: e.id.toString(), id: e.id, duration: e.length, })); }, [eventTypes]); + // Initialize event type from query param or default to first event useEffect(() => { - if (!selectedEventType && eventTypes && eventTypes[0] && !selectedEventQueryParam) { - const { id, slug, length } = eventTypes[0]; - setSelectedEventType({ - id, - slug, - duration: length, - }); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [eventTypes]); + if (!eventTypes || eventTypes.length === 0) return; - useEffect(() => { - if (selectedEventQueryParam) { - // ensure that the update is deferred until the Suspense boundary has finished hydrating + const selectedEventIdParam = getQueryParam("eventTypeId"); + const eventTypeId = selectedEventIdParam ? parseInt(selectedEventIdParam, 10) : null; + + // If we already have a selected event that matches the query param, don't do anything + if (selectedEventType?.id === eventTypeId) return; + + // If there's a query param, try to find and set that event + if (eventTypeId && !isNaN(eventTypeId)) { startTransition(() => { - const foundEventType = eventTypes?.find((et) => et.slug === selectedEventQueryParam); + const foundEventType = eventTypes.find((et) => et.id === eventTypeId); if (foundEventType) { - const { id, slug, length } = foundEventType; - setSelectedEventType({ id, slug, duration: length }); - } else if (eventTypes && eventTypes[0]) { - const { id, slug, length } = eventTypes[0]; setSelectedEventType({ - id, - slug, - duration: length, + id: foundEventType.id, + slug: foundEventType.slug, + duration: foundEventType.length, + teamId: foundEventType.team?.id ?? null, }); + return; } }); } - }, [eventTypes, selectedEventQueryParam, setSelectedEventType]); + + // If no event is selected and no valid query param, default to first event + if (!selectedEventType && !eventTypeId) { + const firstEvent = eventTypes[0]; + setSelectedEventType({ + id: firstEvent.id, + slug: firstEvent.slug, + duration: firstEvent.length, + teamId: firstEvent.team?.id ?? null, + }); + } + }, [eventTypes, selectedEventType, setSelectedEventType]); return ( option.value === selectedEventType?.slug) || options[0]} + value={options.find((option) => option.id === selectedEventType?.id) || options[0]} onChange={(option) => { if (!option) return; - setSelectedEventType({ - slug: option.value, - id: option.id, - duration: option.duration, - }); + const foundEventType = eventTypes?.find((et) => et.id === option.id); + if (foundEventType) { + setSelectedEventType({ + id: foundEventType.id, + slug: foundEventType.slug, + duration: foundEventType.length, + teamId: foundEventType.team?.id ?? null, + }); + } }} /> ); diff --git a/packages/features/troubleshooter/components/LargeCalendar.tsx b/packages/features/troubleshooter/components/LargeCalendar.tsx index de2f725a71..012b63d5cb 100644 --- a/packages/features/troubleshooter/components/LargeCalendar.tsx +++ b/packages/features/troubleshooter/components/LargeCalendar.tsx @@ -28,6 +28,7 @@ export const LargeCalendar = ({ extraDays }: { extraDays: number }) => { .add(extraDays - 1, "day") .utc() .format(), + eventTypeId: event?.id, withSource: true, }, { @@ -35,13 +36,16 @@ export const LargeCalendar = ({ extraDays }: { extraDays: number }) => { } ); + const isTeamEvent = !!event?.teamId; const { data: schedule } = useSchedule({ username: session?.user.username || "", - eventSlug: event?.slug, + // For team events, don't pass eventSlug to avoid slug lookup issues - use eventId instead + eventSlug: isTeamEvent ? null : event?.slug, eventId: event?.id, timezone, month: startDate.format("YYYY-MM"), orgSlug: session?.user.org?.slug, + isTeamEvent, }); const endDate = dayjs(startDate) diff --git a/packages/features/troubleshooter/store.ts b/packages/features/troubleshooter/store.ts index 4d5daa2601..49e23ee4e2 100644 --- a/packages/features/troubleshooter/store.ts +++ b/packages/features/troubleshooter/store.ts @@ -17,6 +17,7 @@ type EventType = { id: number; slug: string; duration: number; + teamId?: number | null; }; export type TroubleshooterStore = { @@ -76,7 +77,7 @@ export const useTroubleshooterStore = create((set, get) => event: null, setEvent: (event: EventType) => { set({ event }); - updateQueryParam("eventType", event.slug ?? ""); + updateQueryParam("eventTypeId", event.id.toString()); }, month: getQueryParam("month") || getQueryParam("date") || dayjs().format("YYYY-MM"), setMonth: (month: string | null) => { diff --git a/packages/trpc/server/routers/viewer/eventTypes/listWithTeam.handler.ts b/packages/trpc/server/routers/viewer/eventTypes/listWithTeam.handler.ts index 6bdff69800..907c6b23a7 100644 --- a/packages/trpc/server/routers/viewer/eventTypes/listWithTeam.handler.ts +++ b/packages/trpc/server/routers/viewer/eventTypes/listWithTeam.handler.ts @@ -11,19 +11,26 @@ type ListWithTeamOptions = { export const listWithTeamHandler = async ({ ctx }: ListWithTeamOptions) => { const userId = ctx.user.id; - const query = Prisma.sql`SELECT "public"."EventType"."id", "public"."EventType"."teamId", "public"."EventType"."title", "public"."EventType"."slug", "j1"."name" as "teamName" + const query = Prisma.sql`SELECT "public"."EventType"."id", "public"."EventType"."teamId", "public"."EventType"."title", "public"."EventType"."slug", "public"."EventType"."length", "j1"."name" as "teamName" FROM "public"."EventType" LEFT JOIN "public"."Team" AS "j1" ON ("j1"."id") = ("public"."EventType"."teamId") WHERE "public"."EventType"."userId" = ${userId} UNION - SELECT "public"."EventType"."id", "public"."EventType"."teamId", "public"."EventType"."title", "public"."EventType"."slug", "j1"."name" as "teamName" + SELECT "public"."EventType"."id", "public"."EventType"."teamId", "public"."EventType"."title", "public"."EventType"."slug", "public"."EventType"."length", "j1"."name" as "teamName" FROM "public"."EventType" INNER JOIN "public"."Team" AS "j1" ON ("j1"."id") = ("public"."EventType"."teamId") INNER JOIN "public"."Membership" AS "t2" ON "t2"."teamId" = "j1"."id" WHERE "t2"."userId" = ${userId} AND "t2"."accepted" = true`; const result = await db.$queryRaw< - { id: number; teamId: number | null; title: string; slug: string; teamName: string | null }[] + { + id: number; + teamId: number | null; + title: string; + slug: string; + length: number; + teamName: string | null; + }[] >(query); return result.map((row) => ({ @@ -31,5 +38,6 @@ export const listWithTeamHandler = async ({ ctx }: ListWithTeamOptions) => { team: row.teamId ? { id: row.teamId, name: row.teamName || "" } : null, title: row.title, slug: row.slug, + length: row.length, })); };