From 61a2a3ef5a067b7b846b5775cb4523ae5ce8b4de Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Mon, 27 Jan 2025 17:13:10 +0100 Subject: [PATCH] chore: clean up ColumnFilterType (#18915) --- .../components/filters/DateRangeFilter.tsx | 6 +-- .../components/filters/FilterOptions.tsx | 11 +++-- .../components/filters/FilterPopover.tsx | 23 ++++++---- .../filters/MultiSelectFilterOptions.tsx | 6 +-- .../filters/NumberFilterOptions.tsx | 6 +-- .../filters/SingleSelectFilterOptions.tsx | 6 +-- .../components/filters/TextFilterOptions.tsx | 6 +-- .../data-table/hooks/useFilterableColumns.ts | 5 +- packages/features/data-table/lib/types.ts | 46 ++++++++++--------- .../components/RoutingFormResponsesTable.tsx | 21 +++++---- .../insights/server/routing-events.ts | 7 +-- .../components/UserTable/UserListTable.tsx | 9 ++-- .../organizations/listMembers.handler.ts | 3 +- 13 files changed, 84 insertions(+), 71 deletions(-) diff --git a/packages/features/data-table/components/filters/DateRangeFilter.tsx b/packages/features/data-table/components/filters/DateRangeFilter.tsx index 7d9c08e675..104b43152d 100644 --- a/packages/features/data-table/components/filters/DateRangeFilter.tsx +++ b/packages/features/data-table/components/filters/DateRangeFilter.tsx @@ -10,7 +10,7 @@ import { Select } from "@calcom/ui"; import "../../../insights/filters/DateSelect.css"; import { useDataTable, useFilterValue } from "../../hooks"; import type { FilterableColumn } from "../../lib/types"; -import { ZDateRangeFilterValue } from "../../lib/types"; +import { ZDateRangeFilterValue, ColumnFilterType } from "../../lib/types"; type PresetOption = { labelKey: string; @@ -20,7 +20,7 @@ type PresetOption = { type DateRangeFilterProps = { className?: string; - column: Extract; + column: Extract; }; const CUSTOM_PRESET_VALUE = "c" as const; @@ -112,7 +112,7 @@ export const DateRangeFilter = ({ className, column }: DateRangeFilterProps) => if (startDate && endDate) { updateFilter(column.id, { - type: "date_range", + type: ColumnFilterType.DATE_RANGE, data: { startDate: startDate.toDate().toISOString(), endDate: endDate.toDate().toISOString(), diff --git a/packages/features/data-table/components/filters/FilterOptions.tsx b/packages/features/data-table/components/filters/FilterOptions.tsx index 77ef8b37c3..f1f6312cee 100644 --- a/packages/features/data-table/components/filters/FilterOptions.tsx +++ b/packages/features/data-table/components/filters/FilterOptions.tsx @@ -1,6 +1,7 @@ "use client"; import type { FilterableColumn } from "../../lib/types"; +import { ColumnFilterType } from "../../lib/types"; import { DateRangeFilter } from "./DateRangeFilter"; import { MultiSelectFilterOptions } from "./MultiSelectFilterOptions"; import { NumberFilterOptions } from "./NumberFilterOptions"; @@ -12,15 +13,15 @@ export type FilterOptionsProps = { }; export function FilterOptions({ column }: FilterOptionsProps) { - if (column.type === "text") { + if (column.type === ColumnFilterType.TEXT) { return ; - } else if (column.type === "multi_select") { + } else if (column.type === ColumnFilterType.MULTI_SELECT) { return ; - } else if (column.type === "single_select") { + } else if (column.type === ColumnFilterType.SINGLE_SELECT) { return ; - } else if (column.type === "number") { + } else if (column.type === ColumnFilterType.NUMBER) { return ; - } else if (column.type === "date_range") { + } else if (column.type === ColumnFilterType.DATE_RANGE) { return ; } else { return null; diff --git a/packages/features/data-table/components/filters/FilterPopover.tsx b/packages/features/data-table/components/filters/FilterPopover.tsx index 37655870d6..33ce27f4ee 100644 --- a/packages/features/data-table/components/filters/FilterPopover.tsx +++ b/packages/features/data-table/components/filters/FilterPopover.tsx @@ -5,7 +5,7 @@ import type { IconName } from "@calcom/ui"; import { Button, Icon, Popover, PopoverContent, PopoverTrigger } from "@calcom/ui"; import { useFilterValue } from "../../hooks"; -import { type FilterableColumn, type FilterValue, ZFilterValue } from "../../lib/types"; +import { type FilterableColumn, type FilterValue, ZFilterValue, ColumnFilterType } from "../../lib/types"; import { isSingleSelectFilterValue, isMultiSelectFilterValue, @@ -14,12 +14,12 @@ import { } from "../../lib/utils"; import { FilterOptions } from "./FilterOptions"; -const FILTER_ICONS: Record = { - text: "file-text", - number: "binary", - multi_select: "layers", - single_select: "disc", - date_range: "calendar-range", +const FILTER_ICONS: Record = { + [ColumnFilterType.TEXT]: "file-text", + [ColumnFilterType.NUMBER]: "binary", + [ColumnFilterType.MULTI_SELECT]: "layers", + [ColumnFilterType.SINGLE_SELECT]: "disc", + [ColumnFilterType.DATE_RANGE]: "calendar-range", }; type FilterPopoverProps = { @@ -38,11 +38,11 @@ const useSelectedLabels = ({ } else if (isNumberFilterValue(filterValue)) { return { text: filterValue.data.operand, moreCount: 0 }; } else if (isSingleSelectFilterValue(filterValue)) { - const options = (column as Extract).options; + const options = (column as Extract).options; const text = options.find((opt) => opt.value === filterValue.data)?.label; return { text, moreCount: 0 }; } else if (isMultiSelectFilterValue(filterValue)) { - const options = (column as Extract).options; + const options = (column as Extract).options; const text = options.find((opt) => opt.value === filterValue.data[0])?.label; return { text, moreCount: filterValue.data.length - 1 }; } else { @@ -54,6 +54,11 @@ export function FilterPopover({ column }: FilterPopoverProps) { const icon = column.icon || FILTER_ICONS[column.type]; const filterValue = useFilterValue(column.id, ZFilterValue); const { text, moreCount } = useSelectedLabels({ column, filterValue }); + console.log("💡 icon", { + icon: column.icon, + type: column.type, + FILTER_ICONS, + }); return ( diff --git a/packages/features/data-table/components/filters/MultiSelectFilterOptions.tsx b/packages/features/data-table/components/filters/MultiSelectFilterOptions.tsx index 5e61c52958..8e82b0c836 100644 --- a/packages/features/data-table/components/filters/MultiSelectFilterOptions.tsx +++ b/packages/features/data-table/components/filters/MultiSelectFilterOptions.tsx @@ -16,10 +16,10 @@ import { import { useDataTable, useFilterValue } from "../../hooks"; import type { FilterableColumn } from "../../lib/types"; -import { ZMultiSelectFilterValue } from "../../lib/types"; +import { ZMultiSelectFilterValue, ColumnFilterType } from "../../lib/types"; export type MultiSelectFilterOptionsProps = { - column: Extract; + column: Extract; }; export function MultiSelectFilterOptions({ column }: MultiSelectFilterOptionsProps) { @@ -44,7 +44,7 @@ export function MultiSelectFilterOptions({ column }: MultiSelectFilterOptionsPro const newFilterValue = filterValue?.data.includes(optionValue) ? filterValue?.data.filter((value) => value !== optionValue) : [...(filterValue?.data || []), optionValue]; - updateFilter(column.id, { type: "multi_select", data: newFilterValue }); + updateFilter(column.id, { type: ColumnFilterType.MULTI_SELECT, data: newFilterValue }); }}>
; + column: Extract; }; export function NumberFilterOptions({ column }: NumberFilterOptionsProps) { @@ -48,7 +48,7 @@ export function NumberFilterOptions({ column }: NumberFilterOptionsProps) { handleSubmit={({ operatorOption, operand }) => { if (operatorOption) { updateFilter(column.id, { - type: "number", + type: ColumnFilterType.NUMBER, data: { operator: operatorOption.value, operand: Number(operand), diff --git a/packages/features/data-table/components/filters/SingleSelectFilterOptions.tsx b/packages/features/data-table/components/filters/SingleSelectFilterOptions.tsx index dee0f22535..003de718d3 100644 --- a/packages/features/data-table/components/filters/SingleSelectFilterOptions.tsx +++ b/packages/features/data-table/components/filters/SingleSelectFilterOptions.tsx @@ -16,10 +16,10 @@ import { import { useDataTable, useFilterValue } from "../../hooks"; import type { FilterableColumn } from "../../lib/types"; -import { ZSingleSelectFilterValue } from "../../lib/types"; +import { ZSingleSelectFilterValue, ColumnFilterType } from "../../lib/types"; export type SingleSelectFilterOptionsProps = { - column: Extract; + column: Extract; }; export function SingleSelectFilterOptions({ column }: SingleSelectFilterOptionsProps) { @@ -41,7 +41,7 @@ export function SingleSelectFilterOptions({ column }: SingleSelectFilterOptionsP { - updateFilter(column.id, { type: "single_select", data: optionValue }); + updateFilter(column.id, { type: ColumnFilterType.SINGLE_SELECT, data: optionValue }); }}>
{ }; export type TextFilterOptionsProps = { - column: Extract; + column: Extract; }; export function TextFilterOptions({ column }: TextFilterOptionsProps) { @@ -55,7 +55,7 @@ export function TextFilterOptions({ column }: TextFilterOptionsProps) { handleSubmit={({ operatorOption, operand }) => { if (operatorOption) { updateFilter(column.id, { - type: "text", + type: ColumnFilterType.TEXT, data: { operator: operatorOption.value, operand: operatorOption.requiresOperand ? operand : "", diff --git a/packages/features/data-table/hooks/useFilterableColumns.ts b/packages/features/data-table/hooks/useFilterableColumns.ts index 56c0ee6222..fd988d6594 100644 --- a/packages/features/data-table/hooks/useFilterableColumns.ts +++ b/packages/features/data-table/hooks/useFilterableColumns.ts @@ -5,6 +5,7 @@ import { type Table } from "@tanstack/react-table"; import { useMemo } from "react"; import type { FilterableColumn } from "../lib/types"; +import { ColumnFilterType } from "../lib/types"; export function useFilterableColumns(table: Table) { const columns = useMemo( @@ -16,14 +17,14 @@ export function useFilterableColumns(table: Table) { () => columns .map((column) => { - const type = column.columnDef.meta?.filter?.type || "multi_select"; + const type = column.columnDef.meta?.filter?.type || ColumnFilterType.MULTI_SELECT; const base = { id: column.id, title: typeof column.columnDef.header === "string" ? column.columnDef.header : column.id, ...(column.columnDef.meta?.filter || {}), type, }; - if (type === "multi_select" || type === "single_select") { + if (type === ColumnFilterType.MULTI_SELECT || type === ColumnFilterType.SINGLE_SELECT) { const values = column.getFacetedUniqueValues(); const options = Array.from(values.keys()).map((option) => { if (typeof option === "string") { diff --git a/packages/features/data-table/lib/types.ts b/packages/features/data-table/lib/types.ts index f664e0ec57..792d31a547 100644 --- a/packages/features/data-table/lib/types.ts +++ b/packages/features/data-table/lib/types.ts @@ -2,6 +2,14 @@ import { z } from "zod"; import type { IconName } from "@calcom/ui"; +export enum ColumnFilterType { + SINGLE_SELECT = "ss", + MULTI_SELECT = "ms", + TEXT = "t", + NUMBER = "n", + DATE_RANGE = "dr", +} + export const ZTextFilterOperator = z.enum([ "equals", "notEquals", @@ -16,21 +24,21 @@ export const ZTextFilterOperator = z.enum([ export type TextFilterOperator = z.infer; export const ZSingleSelectFilterValue = z.object({ - type: z.literal("single_select"), + type: z.literal(ColumnFilterType.SINGLE_SELECT), data: z.union([z.string(), z.number()]), }); export type SingleSelectFilterValue = z.infer; export const ZMultiSelectFilterValue = z.object({ - type: z.literal("multi_select"), + type: z.literal(ColumnFilterType.MULTI_SELECT), data: z.union([z.string(), z.number()]).array(), }); export type MultiSelectFilterValue = z.infer; export const ZTextFilterValue = z.object({ - type: z.literal("text"), + type: z.literal(ColumnFilterType.TEXT), data: z.object({ operator: ZTextFilterOperator, operand: z.string(), @@ -51,7 +59,7 @@ export const ZNumberFilterOperator = z.enum([ export type NumberFilterOperator = z.infer; export const ZNumberFilterValue = z.object({ - type: z.literal("number"), + type: z.literal(ColumnFilterType.NUMBER), data: z.object({ operator: ZNumberFilterOperator, operand: z.number(), @@ -61,7 +69,7 @@ export const ZNumberFilterValue = z.object({ export type NumberFilterValue = z.infer; export const ZDateRangeFilterValue = z.object({ - type: z.literal("date_range"), + type: z.literal(ColumnFilterType.DATE_RANGE), data: z.object({ startDate: z.string().nullable(), endDate: z.string().nullable(), @@ -81,8 +89,6 @@ export const ZFilterValue = z.union([ export type FilterValue = z.infer; -export type ColumnFilterType = "single_select" | "multi_select" | "text" | "number" | "date_range"; - export type ColumnFilterMeta = { type?: ColumnFilterType; icon?: IconName; @@ -91,28 +97,24 @@ export type ColumnFilterMeta = { export type FilterableColumn = { id: string; title: string; + icon?: IconName; } & ( | { - type: "single_select"; - icon?: IconName; + type: ColumnFilterType.SINGLE_SELECT; options: Array<{ label: string; value: string | number }>; } | { - type: "multi_select"; - icon?: IconName; + type: ColumnFilterType.MULTI_SELECT; options: Array<{ label: string; value: string | number }>; } | { - type: "text"; - icon?: IconName; + type: ColumnFilterType.TEXT; } | { - type: "number"; - icon?: IconName; + type: ColumnFilterType.NUMBER; } | { - type: "date_range"; - icon?: IconName; + type: ColumnFilterType.DATE_RANGE; } ); @@ -125,15 +127,15 @@ export type ColumnFilter = z.infer; export type TypedColumnFilter = { id: string; - value: T extends "text" + value: T extends ColumnFilterType.TEXT ? TextFilterValue - : T extends "number" + : T extends ColumnFilterType.NUMBER ? NumberFilterValue - : T extends "single_select" + : T extends ColumnFilterType.SINGLE_SELECT ? SingleSelectFilterValue - : T extends "multi_select" + : T extends ColumnFilterType.MULTI_SELECT ? MultiSelectFilterValue - : T extends "date_range" + : T extends ColumnFilterType.DATE_RANGE ? DateRangeFilterValue : never; }; diff --git a/packages/features/insights/components/RoutingFormResponsesTable.tsx b/packages/features/insights/components/RoutingFormResponsesTable.tsx index d1b2b0ed71..2ed9acd8e6 100644 --- a/packages/features/insights/components/RoutingFormResponsesTable.tsx +++ b/packages/features/insights/components/RoutingFormResponsesTable.tsx @@ -31,6 +31,7 @@ import { ZMultiSelectFilterValue, ZSingleSelectFilterValue, DateRangeFilter, + ColumnFilterType, type FilterableColumn, } from "@calcom/features/data-table"; import classNames from "@calcom/lib/classNames"; @@ -261,10 +262,10 @@ export function RoutingFormResponsesTable() { ); } -const createdAtColumn: Extract = { +const createdAtColumn: Extract = { id: "createdAt", title: "createdAt", - type: "date_range", + type: ColumnFilterType.DATE_RANGE, }; export function RoutingFormResponsesTableContent() { @@ -354,7 +355,7 @@ export function RoutingFormResponsesTableContent() { enableColumnFilter: true, enableSorting: false, meta: { - filter: { type: "single_select" }, + filter: { type: ColumnFilterType.SINGLE_SELECT }, }, cell: () => null, }), @@ -364,7 +365,7 @@ export function RoutingFormResponsesTableContent() { enableColumnFilter: true, enableSorting: false, meta: { - filter: { type: "multi_select" }, + filter: { type: ColumnFilterType.MULTI_SELECT }, }, cell: () => null, }), @@ -393,12 +394,12 @@ export function RoutingFormResponsesTableContent() { const isMultiSelect = fieldHeader.type === RoutingFormFieldType.MULTI_SELECT; const filterType = isSingleSelect - ? "single_select" + ? ColumnFilterType.SINGLE_SELECT : isNumber - ? "number" + ? ColumnFilterType.NUMBER : isText - ? "text" - : "multi_select"; + ? ColumnFilterType.TEXT + : ColumnFilterType.MULTI_SELECT; const optionMap = fieldHeader.options?.reduce((acc, option) => { @@ -457,7 +458,7 @@ export function RoutingFormResponsesTableContent() {
), meta: { - filter: { type: "multi_select", icon: "circle" }, + filter: { type: ColumnFilterType.MULTI_SELECT, icon: "circle" }, }, filterFn: (row, id, filterValue) => { return multiSelectFilter(row.original.bookingStatusOrder, filterValue); @@ -498,7 +499,7 @@ export function RoutingFormResponsesTableContent() { header: t("routing_form_insights_assignment_reason"), enableSorting: false, meta: { - filter: { type: "text" }, + filter: { type: ColumnFilterType.TEXT }, }, cell: (info) => { const assignmentReason = info.getValue(); diff --git a/packages/features/insights/server/routing-events.ts b/packages/features/insights/server/routing-events.ts index 8bd351f675..7b82b4cfb0 100644 --- a/packages/features/insights/server/routing-events.ts +++ b/packages/features/insights/server/routing-events.ts @@ -9,7 +9,8 @@ import { routingFormResponseInDbSchema, } from "@calcom/app-store/routing-forms/zod"; import dayjs from "@calcom/dayjs"; -import type { ColumnFilter, TypedColumnFilter, ColumnFilterType } from "@calcom/features/data-table"; +import type { ColumnFilter, TypedColumnFilter } from "@calcom/features/data-table"; +import { ColumnFilterType } from "@calcom/features/data-table"; import { makeWhereClause, makeOrderBy } from "@calcom/features/data-table/lib/server"; import type { RoutingFormResponsesInput } from "@calcom/features/insights/server/raw-data.schema"; import { readonlyPrisma as prisma } from "@calcom/prisma"; @@ -235,7 +236,7 @@ class RoutingEventsInsights { }); const getLowercasedFilterValue = (filter: TypedColumnFilter) => { - if (filter.value.type === "text") { + if (filter.value.type === ColumnFilterType.TEXT) { return { ...filter.value, data: { @@ -250,7 +251,7 @@ class RoutingEventsInsights { const bookingStatusOrder = columnFilters.find((filter) => filter.id === "bookingStatusOrder"); const bookingAssignmentReason = columnFilters.find( (filter) => filter.id === "bookingAssignmentReason" - ) as TypedColumnFilter<"text"> | undefined; + ) as TypedColumnFilter | undefined; const assignmentReasonValue = bookingAssignmentReason ? getLowercasedFilterValue(bookingAssignmentReason) : undefined; diff --git a/packages/features/users/components/UserTable/UserListTable.tsx b/packages/features/users/components/UserTable/UserListTable.tsx index 5b26ac4238..1e9c4baf4f 100644 --- a/packages/features/users/components/UserTable/UserListTable.tsx +++ b/packages/features/users/components/UserTable/UserListTable.tsx @@ -19,6 +19,7 @@ import { isMultiSelectFilterValue, singleSelectFilter, multiSelectFilter, + ColumnFilterType, } from "@calcom/features/data-table"; import { useOrgBranding } from "@calcom/features/ee/organizations/context/provider"; import classNames from "@calcom/lib/classNames"; @@ -184,12 +185,12 @@ function UserListTableContent() { const isSingleSelect = attribute.type === "SINGLE_SELECT"; const isMultiSelect = attribute.type === "MULTI_SELECT"; const filterType = isNumber - ? "number" + ? ColumnFilterType.NUMBER : isText - ? "text" + ? ColumnFilterType.TEXT : isSingleSelect - ? "single_select" - : "multi_select"; + ? ColumnFilterType.SINGLE_SELECT + : ColumnFilterType.MULTI_SELECT; return { id: attribute.id, diff --git a/packages/trpc/server/routers/viewer/organizations/listMembers.handler.ts b/packages/trpc/server/routers/viewer/organizations/listMembers.handler.ts index 22ba89b2e5..ee58c213c2 100644 --- a/packages/trpc/server/routers/viewer/organizations/listMembers.handler.ts +++ b/packages/trpc/server/routers/viewer/organizations/listMembers.handler.ts @@ -1,4 +1,5 @@ import { makeWhereClause } from "@calcom/features/data-table/lib/server"; +import { ColumnFilterType } from "@calcom/features/data-table/lib/types"; import { UserRepository } from "@calcom/lib/server/repository/user"; import { prisma } from "@calcom/prisma"; import type { Prisma } from "@calcom/prisma/client"; @@ -122,7 +123,7 @@ export const listMembersHandler = async ({ ctx, input }: GetOptions) => { break; // We assume that if the filter is not one of the above, it must be an attribute filter default: - if (filter.value.type === "multi_select" && isAllString(filter.value.data)) { + if (filter.value.type === ColumnFilterType.MULTI_SELECT && isAllString(filter.value.data)) { const attributeOptionValues: string[] = []; filter.value.data.forEach((filterValueItem) => { attributeOptionValues.push(filterValueItem);