Files
calendar/packages/features/insights/hooks/useInsightsBookings.ts
Eunjae LeeGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Udit Takkar
b7a7797293 feat: add paid, userEmail, userName, and rating filters to insights page (#23299)
* feat: add paid, userEmail, and userName filters to insights page

- Add paid filter as MULTI_SELECT with 'Paid'/'Free' options
- Add userEmail filter as TEXT for searching user emails
- Add userName filter as TEXT for searching user names
- Update DummyTableRow type to include new filter columns
- Add backend filtering logic in buildColumnFilterCondition method
- Use existing columns from BookingTimeStatusDenormalized view
- Follow established patterns from /bookings page implementation

Co-Authored-By: [email protected] <[email protected]>

* fix: change paid filter from MULTI_SELECT to SINGLE_SELECT

- Updated useInsightsBookings.ts to use ColumnFilterType.SINGLE_SELECT for paid filter
- Modified buildColumnFilterCondition to handle single select with isSingleSelectFilterValue
- Simplified backend logic to handle single boolean value instead of array

Co-Authored-By: [email protected] <[email protected]>

* fix paid filter

* feat: add rating filter to insights page

- Add rating field to DummyTableRow type
- Add rating column with SINGLE_SELECT filter type
- Add rating options 1-5 in faceted unique values
- Add rating filtering logic in backend service
- Rating filter allows filtering bookings by 1-5 star ratings

Co-Authored-By: [email protected] <[email protected]>

* feat: change rating filter to NUMBER type

- Update rating filter from SINGLE_SELECT to NUMBER in useInsightsBookings.ts
- Remove rating options from useInsightsBookingFacetedUniqueValues.ts since NUMBER filters don't need predefined options
- Add isNumberFilterValue import and implement number filter logic in InsightsBookingBaseService.ts
- Support eq, gt, gte, lt, lte operators for rating number filter

Co-Authored-By: [email protected] <[email protected]>

* refactor: use makeSqlCondition utility for filter logic

- Import makeSqlCondition from @calcom/features/data-table/lib/server
- Replace manual SQL condition building with makeSqlCondition utility for userEmail, userName, and rating filters
- Maintain existing paid filter logic for boolean conversion
- Follow established pattern from InsightsRoutingBaseService
- Cleaner, more maintainable code with consistent filter handling

Co-Authored-By: [email protected] <[email protected]>

* add missing texts

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Udit Takkar <[email protected]>
2025-08-27 16:00:10 +00:00

139 lines
3.5 KiB
TypeScript

import { createColumnHelper, useReactTable, getCoreRowModel, getSortedRowModel } from "@tanstack/react-table";
import { useMemo } from "react";
import { ColumnFilterType } from "@calcom/features/data-table";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import type { BookingStatus } from "@calcom/prisma/enums";
import { useInsightsBookingFacetedUniqueValues } from "./useInsightsBookingFacetedUniqueValues";
import { useInsightsOrgTeams } from "./useInsightsOrgTeams";
type DummyTableRow = {
userId: number | null;
eventTypeId: number | null;
status: BookingStatus;
paid: boolean;
userEmail: string | null;
userName: string | null;
rating: number | null;
};
const emptyData: DummyTableRow[] = [];
export const useInsightsBookings = () => {
const { t } = useLocale();
const { isAll, teamId, userId } = useInsightsOrgTeams();
const getInsightsFacetedUniqueValues = useInsightsBookingFacetedUniqueValues({
userId,
teamId,
isAll,
});
const columns = useMemo(() => {
const columnHelper = createColumnHelper<DummyTableRow>();
return [
columnHelper.accessor("eventTypeId", {
id: "eventTypeId",
header: t("event_type"),
size: 200,
meta: {
filter: {
type: ColumnFilterType.MULTI_SELECT,
},
},
enableColumnFilter: true,
enableSorting: false,
cell: () => null,
}),
columnHelper.accessor("status", {
id: "status",
header: t("booking_status"),
size: 200,
meta: {
filter: {
type: ColumnFilterType.MULTI_SELECT,
},
},
enableColumnFilter: true,
enableSorting: false,
cell: () => null,
}),
columnHelper.accessor("userId", {
id: "userId",
header: t("member"),
enableColumnFilter: true,
enableSorting: false,
meta: {
filter: {
type: ColumnFilterType.SINGLE_SELECT,
},
},
cell: () => null,
}),
columnHelper.accessor("paid", {
id: "paid",
header: t("paid"),
size: 150,
meta: {
filter: {
type: ColumnFilterType.SINGLE_SELECT,
},
},
enableColumnFilter: true,
enableSorting: false,
cell: () => null,
}),
columnHelper.accessor("userEmail", {
id: "userEmail",
header: t("user_email"),
size: 200,
meta: {
filter: {
type: ColumnFilterType.TEXT,
},
},
enableColumnFilter: true,
enableSorting: false,
cell: () => null,
}),
columnHelper.accessor("userName", {
id: "userName",
header: t("user_name"),
size: 200,
meta: {
filter: {
type: ColumnFilterType.TEXT,
},
},
enableColumnFilter: true,
enableSorting: false,
cell: () => null,
}),
columnHelper.accessor("rating", {
id: "rating",
header: t("rating"),
size: 150,
meta: {
filter: {
type: ColumnFilterType.NUMBER,
},
},
enableColumnFilter: true,
enableSorting: false,
cell: () => null,
}),
];
}, [t]);
const table = useReactTable<DummyTableRow>({
data: emptyData,
columns,
getCoreRowModel: getCoreRowModel(),
getSortedRowModel: getSortedRowModel(),
getFacetedUniqueValues: getInsightsFacetedUniqueValues,
});
return { table };
};