From 38fa0fae1d46b188cc6b55089cbd2227b32297d3 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Fri, 27 Sep 2024 07:36:32 +0400 Subject: [PATCH] fix: insights UI/UX (#16610) * remove old code remnant * - * WIP * type change * -- * typefix * fix type * fix type * change type name * add basewhere to eventsByStatus * add basewhere to the rest * fix rendering null popular event list item * URL params for start and endtime to have YYYY-MM-DD format * remove console log * resolve suggestion --------- Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com> --- apps/web/public/static/locales/en/common.json | 4 + .../components/AverageEventDurationChart.tsx | 5 +- .../insights/components/BookingKPICards.tsx | 1 + .../components/PopularEventsTable.tsx | 27 +- .../insights/context/FiltersProvider.tsx | 6 +- .../features/insights/filters/DateSelect.tsx | 128 ++- packages/features/insights/filters/index.tsx | 2 +- .../features/insights/server/trpc-router.ts | 1019 +++++------------ .../form/date-range-picker/Calendar.tsx | 12 +- .../date-range-picker/DateRangePicker.tsx | 6 + 10 files changed, 425 insertions(+), 785 deletions(-) diff --git a/apps/web/public/static/locales/en/common.json b/apps/web/public/static/locales/en/common.json index 25f060ccf8..ece75ba18d 100644 --- a/apps/web/public/static/locales/en/common.json +++ b/apps/web/public/static/locales/en/common.json @@ -2618,5 +2618,9 @@ "you_are_unauthorized_to_make_this_change_to_the_booking": "You are unauthorized to make this change to the booking", "hide_calendar_event_details": "Hide calendar event details on shared calendars", "description_hide_calendar_event_details": "When a calendar is shared, events are visible to readers but their details are hidden from those without write access.", + "last_number_of_days": "last {{count}} days", + "month_to_date": "month to date", + "year_to_date": "year to date", + "custom_range": "custom range", "ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Add your new strings above here ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑" } diff --git a/packages/features/insights/components/AverageEventDurationChart.tsx b/packages/features/insights/components/AverageEventDurationChart.tsx index aca9a5136d..86888a4ef8 100644 --- a/packages/features/insights/components/AverageEventDurationChart.tsx +++ b/packages/features/insights/components/AverageEventDurationChart.tsx @@ -14,13 +14,14 @@ export const AverageEventDurationChart = () => { const { filter } = useFilterContext(); const { dateRange, selectedMemberUserId, isAll, initialConfig } = filter; const [startDate, endDate] = dateRange; - const { selectedTeamId: teamId, selectedUserId } = filter; + const { selectedTeamId: teamId, selectedUserId, selectedEventTypeId } = filter; const initialConfigIsReady = !!(initialConfig?.teamId || initialConfig?.userId || initialConfig?.isAll); const { data, isSuccess, isPending } = trpc.viewer.insights.averageEventDuration.useQuery( { startDate: startDate.toISOString(), endDate: endDate.toISOString(), - teamId: teamId ?? undefined, + teamId, + eventTypeId: selectedEventTypeId ?? undefined, memberUserId: selectedMemberUserId ?? undefined, userId: selectedUserId ?? undefined, isAll, diff --git a/packages/features/insights/components/BookingKPICards.tsx b/packages/features/insights/components/BookingKPICards.tsx index e9cc929b90..81cf50a16b 100644 --- a/packages/features/insights/components/BookingKPICards.tsx +++ b/packages/features/insights/components/BookingKPICards.tsx @@ -11,6 +11,7 @@ import { KPICard } from "./KPICard"; export const BookingKPICards = () => { const { t } = useLocale(); const { filter } = useFilterContext(); + const { dateRange, selectedEventTypeId, selectedUserId, selectedMemberUserId, isAll, initialConfig } = filter; const initialConfigIsReady = !!(initialConfig?.teamId || initialConfig?.userId || initialConfig?.isAll); diff --git a/packages/features/insights/components/PopularEventsTable.tsx b/packages/features/insights/components/PopularEventsTable.tsx index 2ec8b3cde1..59f6b23255 100644 --- a/packages/features/insights/components/PopularEventsTable.tsx +++ b/packages/features/insights/components/PopularEventsTable.tsx @@ -10,7 +10,8 @@ import { LoadingInsight } from "./LoadingInsights"; export const PopularEventsTable = () => { const { t } = useLocale(); const { filter } = useFilterContext(); - const { dateRange, selectedMemberUserId, selectedUserId, isAll, initialConfig } = filter; + const { dateRange, selectedMemberUserId, selectedUserId, isAll, initialConfig, selectedEventTypeId } = + filter; const [startDate, endDate] = dateRange; const { selectedTeamId: teamId } = filter; @@ -20,6 +21,7 @@ export const PopularEventsTable = () => { endDate: endDate.toISOString(), teamId: teamId ?? undefined, userId: selectedUserId ?? undefined, + eventTypeId: selectedEventTypeId ?? undefined, memberUserId: selectedMemberUserId ?? undefined, isAll, }, @@ -41,16 +43,19 @@ export const PopularEventsTable = () => { {t("popular_events")} - {data.map((item) => ( - - {item.eventTypeName} - - - {item.count} - - - - ))} + {data.map( + (item) => + item.eventTypeId && ( + + {item.eventTypeName} + + + {item.count} + + + + ) + )}
{data.length === 0 && ( diff --git a/packages/features/insights/context/FiltersProvider.tsx b/packages/features/insights/context/FiltersProvider.tsx index 091a0688fd..ec557a9730 100644 --- a/packages/features/insights/context/FiltersProvider.tsx +++ b/packages/features/insights/context/FiltersProvider.tsx @@ -60,7 +60,7 @@ export function FiltersProvider({ children }: { children: React.ReactNode }) { dateRange: [ startTimeParsed ? dayjs(startTimeParsed) : dayjs().subtract(1, "week"), endTimeParsed ? dayjs(endTimeParsed) : dayjs(), - "w", + !startTimeParsed && !endTimeParsed ? "w" : null, ], selectedTimeView: "week", selectedUserId: userIdParsed || null, @@ -131,8 +131,8 @@ export function FiltersProvider({ children }: { children: React.ReactNode }) { setParamsIfDefined("userId", selectedUserId || initialConfig?.userId); setParamsIfDefined("eventTypeId", selectedEventTypeId); setParamsIfDefined("isAll", isAll || initialConfig?.isAll); - setParamsIfDefined("startTime", startTime?.toISOString()); - setParamsIfDefined("endTime", endTime?.toISOString()); + setParamsIfDefined("startTime", startTime?.format("YYYY-MM-DD")); + setParamsIfDefined("endTime", endTime?.format("YYYY-MM-DD")); setParamsIfDefined("filter", selectedFilter?.[0]); router.push(`${pathname}?${newSearchParams.toString()}`); }, diff --git a/packages/features/insights/filters/DateSelect.tsx b/packages/features/insights/filters/DateSelect.tsx index d16630bfdb..3f340dae74 100644 --- a/packages/features/insights/filters/DateSelect.tsx +++ b/packages/features/insights/filters/DateSelect.tsx @@ -1,68 +1,102 @@ -import { DateRangePicker } from "@tremor/react"; +import { useState } from "react"; import dayjs from "@calcom/dayjs"; import { useLocale } from "@calcom/lib/hooks/useLocale"; +import { DateRangePicker } from "@calcom/ui"; +import { Select } from "@calcom/ui"; import { useFilterContext } from "../context/provider"; import "./DateSelect.css"; -type RangeType = "tdy" | "w" | "t" | "m" | "y" | undefined | null; - export const DateSelect = () => { const { t } = useLocale(); + const presetOptions = [ + { label: t("today"), value: "tdy" }, + { label: t("last_number_of_days", { count: 7 }), value: "w" }, + { label: t("last_number_of_days", { count: 30 }), value: "t" }, + { label: t("month_to_date"), value: "m" }, + { label: t("year_to_date"), value: "y" }, + { label: t("custom_range"), value: null }, + ]; + const { filter, setConfigFilters } = useFilterContext(); const currentDate = dayjs(); - const [startDate, endDate, range] = filter?.dateRange || [null, null, null]; + const [initialStartDate, initialEndDate, range] = filter?.dateRange || [null, null, null]; + const [startDate, setStartDate] = useState(initialStartDate); + const [endDate, setEndDate] = useState(initialEndDate); const startValue = startDate?.toDate() || null; const endValue = endDate?.toDate() || null; + const [selectedPreset, setSelectedPreset] = useState(presetOptions.find((c) => c.value === range)); + + const updateDateRange = (val: string | null) => { + setSelectedPreset(presetOptions.find((c) => c.value === val)); + let startDate = dayjs(); + let endDate = dayjs(); + + switch (val) { + case "tdy": // Today + startDate = dayjs().startOf("day"); + endDate = dayjs().endOf("day"); + break; + case "w": // Last 7 days + startDate = dayjs().subtract(7, "day").startOf("day"); + endDate = dayjs().endOf("day"); + break; + case "t": // Last 30 days + startDate = dayjs().subtract(30, "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: + break; + } + // Update the datepicker date selection + setStartDate(startDate); + setEndDate(endDate); + // Update the configuration filter + setConfigFilters({ + dateRange: [dayjs(startDate), dayjs(endDate), val], + }); + }; + return ( -
+
{ - const [selected, ...rest] = datesArray; - const [start, end, range] = datesArray; - // If range has value and it's of type RangeType - - if ( - range && - (range === "tdy" || range === "w" || range === "t" || range === "m" || range === "y") - ) { - setConfigFilters({ - dateRange: [dayjs(start).startOf("d"), dayjs(end).endOf("d"), range], - }); - - return; - } else if (start && !end) { - // If only start time has value that means selected date should push to dateRange with last value null - const currentDates = filter.dateRange; - if (currentDates && currentDates.length > 0) { - // remove last position of array - currentDates.pop(); - // push new value to array - currentDates.push(dayjs(selected)); - // if lenght > 2 then remove first value - if (currentDates.length > 2) { - currentDates.shift(); - } - setConfigFilters({ - dateRange: [currentDates[0], currentDates[1], null], - }); - } - - return; - } - - // If range has value and it's of type RangeType + dates={{ + startDate: startValue, + endDate: endValue, }} - options={undefined} - enableDropdown={true} - placeholder={t("select_date_range")} - enableYearPagination={true} minDate={currentDate.subtract(2, "year").toDate()} maxDate={currentDate.toDate()} - color="gray" + disabled={false} + onDatesChange={({ startDate, endDate }) => { + setConfigFilters({ + dateRange: [dayjs(startDate), dayjs(endDate), null], + }); + setStartDate(dayjs(startDate)); + setEndDate(dayjs(endDate)); + setSelectedPreset(presetOptions.find((c) => c.value === null)); + }} + /> +