Skip to content

Commit 7cfb053

Browse files
joeauyeungdevin-ai-integration[bot]claudehariombalharacubic-dev-ai[bot]
authored
feat: add wrong routing tab under Insights for reviewing assignment reports (#27423)
* Add DB table for wrong assignment reports * When report is submitted write to the db * Prevent duplicate reportings * test: add migration and tests for WrongAssignmentReport table Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * fix: add unique constraint on bookingUid and booking access check for hasWrongAssignmentReport - Add @unique constraint on bookingUid in WrongAssignmentReport model to prevent duplicate reports at DB level - Add booking ownership check using BookingAccessService in hasWrongAssignmentReport endpoint - Refactor hasWrongAssignmentReport into separate handler and schema files Addresses Cubic AI review feedback on PR #27405 Co-Authored-By: unknown <> * feat: add routingFormId to WrongAssignmentReport and fix Select clearing - Add routingFormId field to WrongAssignmentReport model in schema.prisma - Add relation to App_RoutingForms_Form with SetNull on delete - Update WrongAssignmentReportRepository.createReport to accept routingFormId - Update BookingRepository.findByUidIncludeEventTypeAndTeamAndAssignmentReason to include routedFromRoutingFormReponse - Extract routingFormId from booking in reportWrongAssignment handler - Fix Select clearing issue: handle null case when user clears team member selection - Update tests to include routingFormId field Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * chore: add migration for routingFormId in WrongAssignmentReport Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * feat: add wrong assignment reports dashboard under routing tab - Add reviewedById and reviewedAt fields to WrongAssignmentReport model - Add repository methods for listing reports by status and updating status - Create tRPC endpoints for fetching reports and updating status - Create dashboard UI with pending/reviewed tabs showing routing form name - Add translation keys for dashboard UI - Integrate dashboard into routing insights page Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * fix: move hooks before early return and fix indentation Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * fix: address Udit's review comments - hasWrongAssignmentReport: throw UNAUTHORIZED error instead of returning false - reportWrongAssignment: add try-catch for Prisma P2002 unique constraint error - WrongAssignmentReport: add Team relation to teamId field - WrongAssignmentReportRepository: use findUnique instead of findFirst - reportWrongAssignment: use i18n for error messages Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * fix: revert hasWrongAssignmentReport to return false when user lacks access Per PR checklist, hasWrongAssignmentReport should return { hasReport: false } when user lacks access to booking, not throw an error. This allows the UI to gracefully treat 'no access' as 'no report exists'. Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * test: update mocks for findUnique and i18n in unit tests Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * fix: throw UNAUTHORIZED in hasWrongAssignmentReport and squash migrations Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * feat: move wrong assignment reports to its own tab under Insights Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * Use data table for wrong reports * Add option to view routing trace * feat: add view routing form submission action to wrong assignment reports Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * feat: add RoutingFormResponseSheet component for viewing form submissions - Create slide-out sheet to display routing form responses - Map option IDs to display labels for select/multiselect fields - Handle both legacy and modern option formats - Add i18n strings: form_submission, no_responses_found Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: improve wrong assignment reports UX - Integrate RoutingFormResponseSheet as slide-out panel instead of new tab - Fix dropdown padding by using StartIcon prop instead of manual Icon - Allow direct status changes for reviewed reports (no need to reopen first) - Remove unused Icon import Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: change User relation onDelete from Cascade to SetNull in WrongAssignmentReport Address Hariom's review feedback: - Changed reportedById from Int to Int? (nullable) - Changed reportedBy relation from onDelete: Cascade to onDelete: SetNull - Updated migration SQL to reflect these changes This preserves wrong assignment reports even when the reporting user is deleted, as the data is still useful for analysis. Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * feat: add missing i18n strings for wrong assignment reports dashboard Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * refactor: move form response display value resolution server-side Replace client-side option ID to label resolution in RoutingFormResponseSheet with a new lean tRPC endpoint (getFormResponseDisplay) that resolves values server-side using the existing getHumanReadableFieldResponseValue utility. This enforces DTO boundaries by returning a clean pre-resolved payload instead of leaking internal option format details to the client. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add report wrong assignment button to routing trace sheet Wire up the WrongAssignmentDialog from the routing trace sheet header so users can flag wrong assignments directly while viewing the trace. The report button is disabled with a tooltip when a report already exists. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: reuse existing WrongAssignmentDialog from parent Replace the duplicate WrongAssignmentDialog in RoutingTraceSheet with a callback to the existing instance in BookingActionsDropdown. This reduces the prop surface from a 6-field reportContext object to an onReport callback and hasExistingReport boolean. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: use repository instead of direct Prisma in getFormResponseDisplay Replace direct Prisma query with PrismaRoutingFormResponseRepository's findByIdIncludeForm method. Extend the method to also select form name, description, userId, and teamId needed for display and auth checks. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: replace direct Prisma calls with repository methods Use MembershipRepository.hasMembership() for auth checks and TeamRepository.findAllByParentId() for child team queries instead of direct Prisma calls. Replace direct user query with UserRepository.getTimeZoneAndDefaultScheduleId(). Remove unused seed script. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: use PBAC services for wrong assignment report auth Replace manual MembershipRepository.hasMembership() checks with PBAC-aware permission checking. getWrongAssignmentReports uses createTeamPbacProcedure middleware since teamId is in input. updateWrongAssignmentReportStatus uses PermissionCheckService directly since teamId is discovered from the report entity. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: resolve type errors in RoutingFormResponseSheet and wrong-routing view Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * feat: add seed script for wrong assignment reports test data Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * Revert "feat: add seed script for wrong assignment reports test data" This reverts commit 0bd60e9. * Only update reviewed fields when not pending Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com> * refactor: wrap handleStatusChange in useCallback to fix useMemo recalculation Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * Fix routing sheet UI * fix: use appropriate error message in getFormResponseDisplay handler Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * refactor: extract WrongAssignmentReportService from tRPC handlers Move business logic (booking lookup, duplicate check, report creation, webhook dispatch, org-level team resolution) into a dedicated service in packages/features. Handlers become thin controllers that only handle auth checks and delegate to the service. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: restrict report status updates to admin/owner roles Remove MembershipRole.MEMBER from fallbackRoles in updateWrongAssignmentReportStatus permission check. Updating report status is an administrative action that should be limited to team admins and owners. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: localize hard-coded success message in WrongAssignmentReportService Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * fix: rename reviewed tab to handled and add missing translations Rename the "Reviewed" tab to "Handled" since it groups three distinct statuses (Reviewed, Resolved, Dismissed). Also add missing translation keys for "resolved" and "dismissed" status badges. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * merge: resolve conflicts with main branch Merge main into devin/1769747741-wrong-assignment-dashboard, resolving conflicts in: - BookingActionsDropdown.tsx: use main's booking prop with PR's fragment structure - reportWrongAssignment.handler.ts: keep PR's service-based approach - reportWrongAssignment.handler.test.ts: use main's class-based mocks with PR's additions - WrongAssignmentReportService.ts: align with main's repo method and field names Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * Add guard when accessing assignmentReasonSortedByCreatedAt Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> * fix: address Cubic AI review feedback - select projection and useLocale refactor Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * fix: remove stale TRPCError assertion in test (service throws ErrorWithCode) Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * refactor: remove unused findByTeamIdAndStatus and findByTeamIdAndStatuses methods Co-Authored-By: alex@cal.com <me@alexvanandel.com> * perf: add composite index on WrongAssignmentReport and narrow findByIdIncludeForm select Co-Authored-By: alex@cal.com <me@alexvanandel.com> * perf: use lightweight findTeamIdById in update-status handler instead of findById Co-Authored-By: alex@cal.com <me@alexvanandel.com> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: hariom@cal.com <hariombalhara@gmail.com> Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> Co-authored-by: alex@cal.com <me@alexvanandel.com>
1 parent 50c5423 commit 7cfb053

31 files changed

Lines changed: 1400 additions & 189 deletions

File tree

apps/web/app/(use-page-wrapper)/apps/routing-forms/[...pages]/RouteBuilder.tsx

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,6 @@ type RouteActionSelectorProps = {
359359
onCustomEventTypeSlugChange?: (slug: string) => void;
360360
eventTypePrefix?: string;
361361
fieldIdentifiers?: string[];
362-
t: (key: string, options?: Record<string, string>) => string;
363362
};
364363

365364
const RouteActionSelector = ({
@@ -375,8 +374,8 @@ const RouteActionSelector = ({
375374
onCustomEventTypeSlugChange,
376375
eventTypePrefix = "",
377376
fieldIdentifiers = [],
378-
t,
379377
}: RouteActionSelectorProps) => {
378+
const { t } = useLocale();
380379
return (
381380
<div className={classNames("flex w-full flex-col gap-2 text-sm lg:flex-row", className)}>
382381
<div className="flex grow items-center gap-2">
@@ -803,7 +802,6 @@ const Route = ({
803802
onCustomEventTypeSlugChange={setCustomFallbackEventTypeSlug}
804803
eventTypePrefix={eventTypePrefix}
805804
fieldIdentifiers={fieldIdentifiers}
806-
t={t}
807805
/>
808806
</div>
809807
{isOrganization && (
@@ -899,7 +897,6 @@ const Route = ({
899897
onCustomEventTypeSlugChange={setCustomEventTypeSlug}
900898
eventTypePrefix={eventTypePrefix}
901899
fieldIdentifiers={fieldIdentifiers}
902-
t={t}
903900
/>
904901
) : (
905902
<div className="bg-default border-subtle my-3 rounded-xl border p-2">
@@ -938,7 +935,6 @@ const Route = ({
938935
onCustomEventTypeSlugChange={setCustomEventTypeSlug}
939936
eventTypePrefix={eventTypePrefix}
940937
fieldIdentifiers={fieldIdentifiers}
941-
t={t}
942938
/>
943939
</div>
944940
{attributesQueryBuilder}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { _generateMetadata } from "app/_utils";
2+
3+
import { UserRepository } from "@calcom/features/users/repositories/UserRepository";
4+
import prisma from "@calcom/prisma";
5+
6+
import InsightsWrongRoutingPage from "~/insights/views/insights-wrong-routing-view";
7+
8+
import { checkInsightsPagePermission } from "../checkInsightsPagePermission";
9+
10+
export const generateMetadata = async () =>
11+
await _generateMetadata(
12+
(t) => t("wrong_routing"),
13+
(t) => t("wrong_routing_description"),
14+
undefined,
15+
undefined,
16+
"/insights/wrong-routing"
17+
);
18+
19+
export default async function Page() {
20+
const session = await checkInsightsPagePermission();
21+
22+
const userRepository = new UserRepository(prisma);
23+
const user = await userRepository.getTimeZoneAndDefaultScheduleId({ userId: session?.user.id ?? -1 });
24+
25+
return <InsightsWrongRoutingPage timeZone={user?.timeZone ?? "UTC"} />;
26+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
"use client";
2+
3+
import { useLocale } from "@calcom/lib/hooks/useLocale";
4+
import { trpc } from "@calcom/trpc/react";
5+
import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetBody } from "@calcom/ui/components/sheet";
6+
7+
interface RoutingFormResponseSheetProps {
8+
isOpen: boolean;
9+
setIsOpen: (open: boolean) => void;
10+
formResponseId: number;
11+
}
12+
13+
export function RoutingFormResponseSheet({
14+
isOpen,
15+
setIsOpen,
16+
formResponseId,
17+
}: RoutingFormResponseSheetProps) {
18+
const { t } = useLocale();
19+
20+
const { data, isLoading } = trpc.viewer.appRoutingForms.getFormResponseDisplay.useQuery(
21+
{ formResponseId },
22+
{
23+
enabled: isOpen && !!formResponseId,
24+
staleTime: 10 * 60 * 1000,
25+
}
26+
);
27+
28+
return (
29+
<Sheet open={isOpen} onOpenChange={setIsOpen}>
30+
<SheetContent>
31+
<SheetHeader>
32+
<SheetTitle>{t("form_submission")}</SheetTitle>
33+
</SheetHeader>
34+
<SheetBody>
35+
{isLoading && (
36+
<div className="flex flex-col gap-4 py-2">
37+
{[1, 2, 3].map((i) => (
38+
<div key={i} className="flex flex-col gap-1.5">
39+
<div className="bg-muted h-3 w-24 animate-pulse rounded" />
40+
<div className="bg-muted h-5 w-full animate-pulse rounded" />
41+
</div>
42+
))}
43+
</div>
44+
)}
45+
{!isLoading && (!data?.responses || data.responses.length === 0) && (
46+
<p className="text-subtle text-sm">{t("no_responses_found")}</p>
47+
)}
48+
{!isLoading && data?.responses && data.responses.length > 0 && (
49+
<div className="flex flex-col gap-4">
50+
{data.form?.name && (
51+
<div className="border-subtle border-b pb-3">
52+
<p className="text-emphasis text-sm font-medium">{data.form.name}</p>
53+
{data.form.description && (
54+
<p className="text-subtle text-xs">{data.form.description}</p>
55+
)}
56+
</div>
57+
)}
58+
{data.responses.map((item) => (
59+
<div key={item.fieldId} className="flex flex-col gap-1">
60+
<label className="text-subtle text-xs font-medium uppercase tracking-wide">
61+
{item.label}
62+
</label>
63+
<p className="text-emphasis text-sm">{item.displayValue}</p>
64+
</div>
65+
))}
66+
</div>
67+
)}
68+
</SheetBody>
69+
</SheetContent>
70+
</Sheet>
71+
);
72+
}

apps/web/components/booking/RoutingTraceSheet.tsx

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,34 @@ import { DomainIcon } from "@calcom/features/routing-trace/components/DomainIcon
55
import { getDomainLabel } from "@calcom/features/routing-trace/presenters/getDomainLabel";
66
import { useLocale } from "@calcom/lib/hooks/useLocale";
77
import { trpc } from "@calcom/trpc/react";
8-
import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetBody } from "@calcom/ui/components/sheet";
8+
import { Button } from "@calcom/ui/components/button";
9+
import {
10+
Sheet,
11+
SheetContent,
12+
SheetHeader,
13+
SheetTitle,
14+
SheetBody,
15+
} from "@calcom/ui/components/sheet";
16+
917

1018
interface RoutingTraceSheetProps {
1119
isOpen: boolean;
1220
setIsOpen: (open: boolean) => void;
1321
bookingUid: string;
22+
/** Callback to open the wrong assignment report dialog. If not provided, report button is hidden */
23+
onReport?: () => void;
24+
hasExistingReport?: boolean;
1425
}
1526

16-
export function RoutingTraceSheet({ isOpen, setIsOpen, bookingUid }: RoutingTraceSheetProps) {
27+
export function RoutingTraceSheet({
28+
isOpen,
29+
setIsOpen,
30+
bookingUid,
31+
onReport,
32+
hasExistingReport,
33+
}: RoutingTraceSheetProps) {
1734
const { t } = useLocale();
35+
const showReportButton = !!onReport;
1836

1937
const { data, isLoading } = trpc.viewer.bookings.getRoutingTrace.useQuery(
2038
{ bookingUid },
@@ -27,8 +45,24 @@ export function RoutingTraceSheet({ isOpen, setIsOpen, bookingUid }: RoutingTrac
2745
return (
2846
<Sheet open={isOpen} onOpenChange={setIsOpen}>
2947
<SheetContent>
30-
<SheetHeader>
31-
<SheetTitle>{t("routing_trace")}</SheetTitle>
48+
<SheetHeader showCloseButton={!showReportButton} className="w-full">
49+
{showReportButton ? (
50+
<div className="flex w-full items-center justify-between">
51+
<SheetTitle>{t("routing_trace")}</SheetTitle>
52+
<div className="flex items-center gap-2 pl-2">
53+
<Button
54+
color="secondary"
55+
size="sm"
56+
StartIcon="flag"
57+
disabled={hasExistingReport}
58+
onClick={onReport}>
59+
{t("report")}
60+
</Button>
61+
</div>
62+
</div>
63+
) : (
64+
<SheetTitle>{t("routing_trace")}</SheetTitle>
65+
)}
3266
</SheetHeader>
3367
<SheetBody>
3468
{isLoading && (
@@ -54,7 +88,9 @@ export function RoutingTraceSheet({ isOpen, setIsOpen, bookingUid }: RoutingTrac
5488
return (
5589
<div key={idx} className="relative flex gap-3 pb-6 last:pb-0">
5690
{/* Timeline connector line */}
57-
{!isLast && <div className="border-subtle absolute left-4 top-8 bottom-0 border-l" />}
91+
{!isLast && (
92+
<div className="border-subtle absolute left-4 top-8 bottom-0 border-l" />
93+
)}
5894
{/* Icon circle */}
5995
<div className="bg-default border-subtle relative z-10 flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full border">
6096
<DomainIcon domain={step.domain} />

apps/web/components/booking/actions/BookingActionsDropdown.tsx

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,9 @@
1-
import { useState } from "react";
2-
import type { z } from "zod";
3-
4-
import { MeetingSessionDetailsDialog } from "@calcom/web/modules/ee/video/components/MeetingSessionDetailsDialog";
5-
import ViewRecordingsDialog from "~/ee/video/components/ViewRecordingsDialog";
61
import { useLocale } from "@calcom/lib/hooks/useLocale";
72
import type { bookingMetadataSchema } from "@calcom/prisma/zod-utils";
83
import { trpc } from "@calcom/trpc/react";
94
import classNames from "@calcom/ui/classNames";
105
import { Button } from "@calcom/ui/components/button";
11-
import { Dialog, DialogContent, DialogFooter, DialogClose } from "@calcom/ui/components/dialog";
6+
import { Dialog, DialogClose, DialogContent, DialogFooter } from "@calcom/ui/components/dialog";
127
import {
138
Dropdown,
149
DropdownItem,
@@ -19,10 +14,10 @@ import {
1914
DropdownMenuSeparator,
2015
DropdownMenuTrigger,
2116
} from "@calcom/ui/components/dropdown";
22-
import { Tooltip } from "@calcom/ui/components/tooltip";
2317
import type { ActionType } from "@calcom/ui/components/table";
2418
import { showToast } from "@calcom/ui/components/toast";
25-
19+
import { Tooltip } from "@calcom/ui/components/tooltip";
20+
import { MeetingSessionDetailsDialog } from "@calcom/web/modules/ee/video/components/MeetingSessionDetailsDialog";
2621
import { AddGuestsDialog } from "@components/dialog/AddGuestsDialog";
2722
import { CancelBookingDialog } from "@components/dialog/CancelBookingDialog";
2823
import { ChargeCardDialog } from "@components/dialog/ChargeCardDialog";
@@ -33,20 +28,22 @@ import { ReportBookingDialog } from "@components/dialog/ReportBookingDialog";
3328
import { RerouteDialog } from "@components/dialog/RerouteDialog";
3429
import { RescheduleDialog } from "@components/dialog/RescheduleDialog";
3530
import { WrongAssignmentDialog } from "@components/dialog/WrongAssignmentDialog";
36-
import { RoutingTraceSheet } from "../RoutingTraceSheet";
37-
31+
import { useState } from "react";
32+
import type { z } from "zod";
33+
import ViewRecordingsDialog from "~/ee/video/components/ViewRecordingsDialog";
3834
import { useBookingConfirmation } from "../hooks/useBookingConfirmation";
35+
import { RoutingTraceSheet } from "../RoutingTraceSheet";
3936
import type { BookingItemProps } from "../types";
4037
import { useBookingActionsStoreContext } from "./BookingActionsStoreProvider";
4138
import {
39+
type BookingActionContext,
40+
getAfterEventActions,
4241
getCancelEventAction,
4342
getEditEventActions,
44-
getAfterEventActions,
43+
getPendingActions,
4544
getReportAction,
4645
shouldShowEditActions,
4746
shouldShowPendingActions,
48-
getPendingActions,
49-
type BookingActionContext,
5047
} from "./bookingActions";
5148

5249
interface BookingActionsDropdownProps {
@@ -455,18 +452,20 @@ export function BookingActionsDropdown({
455452
status={getBookingStatus()}
456453
/>
457454
{isBookingFromRoutingForm && (
458-
<WrongAssignmentDialog
459-
isOpenDialog={isOpenWrongAssignmentDialog}
460-
setIsOpenDialog={setIsOpenWrongAssignmentDialog}
461-
booking={booking}
462-
/>
463-
)}
464-
{booking.assignmentReasonSortedByCreatedAt.length > 0 && (
465-
<RoutingTraceSheet
466-
isOpen={isOpenRoutingTraceSheet}
467-
setIsOpen={setIsOpenRoutingTraceSheet}
468-
bookingUid={booking.uid}
469-
/>
455+
<>
456+
<WrongAssignmentDialog
457+
isOpenDialog={isOpenWrongAssignmentDialog}
458+
setIsOpenDialog={setIsOpenWrongAssignmentDialog}
459+
booking={booking}
460+
/>
461+
<RoutingTraceSheet
462+
isOpen={isOpenRoutingTraceSheet}
463+
setIsOpen={setIsOpenRoutingTraceSheet}
464+
bookingUid={booking.uid}
465+
onReport={() => setIsOpenWrongAssignmentDialog(true)}
466+
hasExistingReport={!!booking.report}
467+
/>
468+
</>
470469
)}
471470
{booking.paid && booking.payment[0] && (
472471
<ChargeCardDialog

apps/web/modules/bookings/components/BookingDetailsSheet.tsx

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
"use client";
22

3-
import Link from "next/link";
4-
import { useMemo } from "react";
5-
import { z } from "zod";
6-
73
import dayjs from "@calcom/dayjs";
84
import { useBookingLocation } from "@calcom/features/bookings/hooks";
95
import { shouldShowFieldInCustomResponses } from "@calcom/lib/bookings/SystemField";
@@ -15,8 +11,8 @@ import { getEveryFreqFor } from "@calcom/lib/recurringStrings";
1511
import { BookingStatus } from "@calcom/prisma/enums";
1612
import {
1713
bookingMetadataSchema,
18-
eventTypeBookingFields,
1914
EventTypeMetaDataSchema,
15+
eventTypeBookingFields,
2016
} from "@calcom/prisma/zod-utils";
2117
import { trpc } from "@calcom/trpc/react";
2218
import type { RecurringEvent } from "@calcom/types/Calendar";
@@ -25,28 +21,30 @@ import { Avatar } from "@calcom/ui/components/avatar";
2521
import { Badge } from "@calcom/ui/components/badge";
2622
import { Button } from "@calcom/ui/components/button";
2723
import { Icon } from "@calcom/ui/components/icon";
24+
import { SegmentedControl } from "@calcom/ui/components/segmented-control";
2825
import {
2926
Sheet,
30-
SheetContent,
3127
SheetBody,
32-
SheetHeader,
28+
SheetContent,
3329
SheetFooter,
30+
SheetHeader,
3431
SheetTitle,
3532
} from "@calcom/ui/components/sheet";
36-
33+
import { BookingHistory } from "@calcom/web/modules/booking-audit/components/BookingHistory";
3734
import assignmentReasonBadgeTitleMap from "@lib/booking/assignmentReasonBadgeTitleMap";
38-
35+
import Link from "next/link";
36+
import { useMemo } from "react";
37+
import type { z } from "zod";
3938
import { AcceptBookingButton } from "../../../components/booking/AcceptBookingButton";
40-
import { RejectBookingButton } from "../../../components/booking/RejectBookingButton";
4139
import { BookingActionsDropdown } from "../../../components/booking/actions/BookingActionsDropdown";
4240
import { BookingActionsStoreProvider } from "../../../components/booking/actions/BookingActionsStoreProvider";
41+
import { RejectBookingButton } from "../../../components/booking/RejectBookingButton";
4342
import type { BookingListingStatus } from "../../../components/booking/types";
4443
import { usePaymentStatus } from "../hooks/usePaymentStatus";
4544
import { useBookingDetailsSheetStore } from "../store/bookingDetailsSheetStore";
4645
import type { BookingOutput } from "../types";
4746
import { JoinMeetingButton } from "./JoinMeetingButton";
48-
import { BookingHistory } from "@calcom/web/modules/booking-audit/components/BookingHistory";
49-
import { SegmentedControl } from "@calcom/ui/components/segmented-control";
47+
5048
type BookingMetaData = z.infer<typeof bookingMetadataSchema>;
5149

5250
interface BookingDetailsSheetProps {
@@ -215,7 +213,8 @@ function BookingDetailsSheetInner({
215213
.map(([question, answer]) => [question, answer] as [string, unknown])
216214
: [];
217215

218-
const reason = booking.assignmentReasonSortedByCreatedAt?.[booking.assignmentReasonSortedByCreatedAt.length - 1];
216+
const reason =
217+
booking.assignmentReasonSortedByCreatedAt?.[booking.assignmentReasonSortedByCreatedAt.length - 1];
219218
const reasonTitle = reason && assignmentReasonBadgeTitleMap(reason.reasonEnum);
220219

221220
return (

0 commit comments

Comments
 (0)