Files
calendar/packages/features/data-table/lib/dateRange.ts
T
Eunjae LeeGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
aaaff0705b fix(bookings): enable past date selection for cancelled bookings (#25644)
* refactor(data-table): clean up DateRangeFilter range options

- Replace 'past' | 'custom' with 'past' | 'future' | 'any' | 'customOnly'
- Add direction field to PresetOption for preset compatibility filtering
- Derive presets visibility automatically based on compatible presets
- Update bookings list to use new range values:
  - past -> 'past'
  - upcoming -> 'future'
  - unconfirmed/recurring/cancelled -> 'any'

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* feat(playground): add DateRangeFilter playground page with E2E tests

- Add playground page at /settings/admin/playground/date-range-filter
- Demonstrate all 4 range options: past, future, any, customOnly
- Add link to playground index page
- Add E2E tests for presets visibility and date restrictions

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* fix(playground): use correct meta.filter pattern for column filter config

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* clean up the playground esign

* add unit tests instead of e2e

* fix the implementation

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-17 13:47:51 +00:00

108 lines
3.1 KiB
TypeScript

import dayjs from "@calcom/dayjs";
import { ColumnFilterType, type DateRangeFilterValue } from "./types";
export type PresetOptionValue = "c" | "w" | "m" | "y" | "t" | "tdy";
export type PresetDirection = "past" | "future" | "any";
export type PresetOption = {
labelKey: string;
i18nOptions?: Record<string, string | number>;
value: PresetOptionValue;
direction: PresetDirection;
};
export const CUSTOM_PRESET_VALUE = "c" as const;
export const DEFAULT_PRESET: PresetOption = {
labelKey: "last_number_of_days",
i18nOptions: { count: 7 },
value: "w",
direction: "past",
};
export const CUSTOM_PRESET: PresetOption = {
labelKey: "custom_range",
value: CUSTOM_PRESET_VALUE,
direction: "any",
};
export const PRESET_OPTIONS: PresetOption[] = [
{ labelKey: "today", value: "tdy", direction: "past" },
DEFAULT_PRESET,
{ labelKey: "last_number_of_days", i18nOptions: { count: 30 }, value: "t", direction: "past" },
{ labelKey: "month_to_date", value: "m", direction: "past" },
{ labelKey: "year_to_date", value: "y", direction: "past" },
CUSTOM_PRESET,
];
export const getCompatiblePresets = (range: "past" | "future" | "any" | "customOnly"): PresetOption[] => {
if (range === "customOnly") {
return [];
}
return PRESET_OPTIONS.filter((preset) => {
if (preset.direction === "any") return true;
if (range === "any") return true;
return preset.direction === range;
});
};
export const getDefaultStartDate = () => dayjs().subtract(6, "day").startOf("day");
export const getDefaultEndDate = () => dayjs().endOf("day");
export const getDateRangeFromPreset = (val: string | null) => {
let startDate;
let endDate;
const preset = PRESET_OPTIONS.find((o) => o.value === val);
if (!preset) {
return { startDate: getDefaultStartDate(), endDate: getDefaultEndDate(), preset: CUSTOM_PRESET };
}
switch (val) {
case "tdy": // Today
startDate = dayjs().startOf("day");
endDate = dayjs().endOf("day");
break;
case "w": // Last 7 days
startDate = dayjs().subtract(6, "day").startOf("day");
endDate = dayjs().endOf("day");
break;
case "t": // Last 30 days
startDate = dayjs().subtract(29, "day").startOf("day");
endDate = dayjs().endOf("day");
break;
case "m": // Month to Date
startDate = dayjs().startOf("month");
endDate = dayjs().endOf("day");
break;
case "y": // Year to Date
startDate = dayjs().startOf("year");
endDate = dayjs().endOf("day");
break;
default:
throw new Error(`Invalid preset value: ${val}`);
}
return { startDate, endDate, preset };
};
export const recalculateDateRange = (filterValue: DateRangeFilterValue): DateRangeFilterValue => {
// If it's a custom range, return as is
if (filterValue.data.preset === CUSTOM_PRESET_VALUE) {
return filterValue;
}
// Recalculate dates based on the current timestamp
const { startDate, endDate } = getDateRangeFromPreset(filterValue.data.preset);
return {
type: ColumnFilterType.DATE_RANGE,
data: {
...filterValue.data,
startDate: startDate.toISOString(),
endDate: endDate.toISOString(),
},
};
};