From e9a94189360ba2e019052a6e0eb6a0ecac171e95 Mon Sep 17 00:00:00 2001
From: Alexander Polyankin <alexander.polyankin@metabase.com>
Date: Tue, 18 Oct 2022 16:08:49 +0300
Subject: [PATCH] Extract date picker filter utilities (#25964)

---
 .../lib/queries/utils/date-filters.ts         | 36 +++++++++++++++++++
 .../pickers/DatePicker/RangeDatePicker.tsx    | 34 +++++++++---------
 .../pickers/DatePicker/SingleDatePicker.tsx   | 16 +++++----
 3 files changed, 62 insertions(+), 24 deletions(-)

diff --git a/frontend/src/metabase-lib/lib/queries/utils/date-filters.ts b/frontend/src/metabase-lib/lib/queries/utils/date-filters.ts
index ad5c7aa5af8..88472ec411a 100644
--- a/frontend/src/metabase-lib/lib/queries/utils/date-filters.ts
+++ b/frontend/src/metabase-lib/lib/queries/utils/date-filters.ts
@@ -392,3 +392,39 @@ export const isDayOfWeekDateFilter = testTemporalUnit("day-of-week");
 export const isMonthOfYearDateFilter = testTemporalUnit("month-of-year");
 export const isQuarterofYearDateFilter = testTemporalUnit("quarter-of-year");
 export const isHourOfDayDateFilter = testTemporalUnit("hour-of-day");
+
+export function getDateFilterValue(mbql: any[]) {
+  const [_op, _field, value] = mbql;
+  return value;
+}
+
+export function setDateFilterValue(mbql: any[], newValue: string | null) {
+  const [op, field] = mbql;
+  return [op, field, newValue];
+}
+
+export function clearDateFilterTime(mbql: any[]) {
+  return setDateFilterValue(mbql, setTimeComponent(getDateFilterValue(mbql)));
+}
+
+export function getDateRangeFilterValue(mbql: any[]) {
+  const [_op, _field, startValue, endValue] = mbql;
+  return [startValue, endValue];
+}
+
+export function setDateRangeFilterValue(
+  mbql: any[],
+  [startValue, endValue]: [string | null, string | null],
+) {
+  const [op, field] = mbql;
+  return [op, field, startValue, endValue];
+}
+
+export function clearDateRangeFilterTime(mbql: any[]) {
+  const [startValue, endValue] = getDateRangeFilterValue(mbql);
+
+  return setDateRangeFilterValue(mbql, [
+    setTimeComponent(startValue),
+    setTimeComponent(endValue),
+  ]);
+}
diff --git a/frontend/src/metabase/query_builder/components/filters/pickers/DatePicker/RangeDatePicker.tsx b/frontend/src/metabase/query_builder/components/filters/pickers/DatePicker/RangeDatePicker.tsx
index 7d446939dd8..830ab8b4ce5 100644
--- a/frontend/src/metabase/query_builder/components/filters/pickers/DatePicker/RangeDatePicker.tsx
+++ b/frontend/src/metabase/query_builder/components/filters/pickers/DatePicker/RangeDatePicker.tsx
@@ -1,8 +1,12 @@
 import React, { useCallback, useState } from "react";
 import moment, { Moment } from "moment-timezone";
 import Calendar from "metabase/components/Calendar";
-import { setTimeComponent } from "metabase-lib/lib/queries/utils/query-time";
 import Filter from "metabase-lib/lib/queries/structured/Filter";
+import {
+  clearDateRangeFilterTime,
+  getDateRangeFilterValue,
+  setDateRangeFilterValue,
+} from "metabase-lib/lib/queries/utils/date-filters";
 import SingleDatePicker, { SingleDatePickerProps } from "./SingleDatePicker";
 import SpecificDatePicker from "./SpecificDatePicker";
 import { DateContainer, DateDivider } from "./RangeDatePicker.styled";
@@ -17,11 +21,12 @@ export interface BetweenPickerProps {
 
 export const BetweenPicker = ({
   className,
-  filter: [op, field, startValue, endValue],
+  filter,
   primaryColor,
   hideTimeSelectors,
   onFilterChange,
 }: BetweenPickerProps) => {
+  const [startValue, endValue] = getDateRangeFilterValue(filter);
   const [isStartDateActive, setIsStartDateActive] = useState(true);
 
   const handleStartDateFocus = useCallback(() => {
@@ -35,41 +40,36 @@ export const BetweenPicker = ({
   const handleDateClick = useCallback(
     (newValue: string, newDate: Moment) => {
       if (isStartDateActive) {
-        onFilterChange([op, field, newValue, null]);
+        onFilterChange(setDateRangeFilterValue(filter, [newValue, null]));
       } else if (newDate.isBefore(startValue)) {
-        onFilterChange([op, field, newValue, startValue]);
+        onFilterChange(setDateRangeFilterValue(filter, [newValue, startValue]));
       } else {
-        onFilterChange([op, field, startValue, newValue]);
+        onFilterChange(setDateRangeFilterValue(filter, [startValue, newValue]));
       }
       setIsStartDateActive(isActive => !isActive);
     },
-    [op, field, startValue, isStartDateActive, onFilterChange],
+    [filter, startValue, isStartDateActive, onFilterChange],
   );
 
   const handleStartDateChange = useCallback(
     (newValue: string | null) => {
-      onFilterChange([op, field, newValue, endValue]);
+      onFilterChange(setDateRangeFilterValue(filter, [newValue, endValue]));
       setIsStartDateActive(isActive => !isActive);
     },
-    [op, field, endValue, onFilterChange],
+    [filter, endValue, onFilterChange],
   );
 
   const handleEndDateChange = useCallback(
     (newValue: string | null) => {
-      onFilterChange([op, field, startValue, newValue]);
+      onFilterChange(setDateRangeFilterValue(filter, [startValue, newValue]));
       setIsStartDateActive(isActive => !isActive);
     },
-    [op, field, startValue, onFilterChange],
+    [filter, startValue, onFilterChange],
   );
 
   const handleEndDateClear = useCallback(() => {
-    onFilterChange([
-      op,
-      field,
-      setTimeComponent(startValue),
-      setTimeComponent(endValue),
-    ]);
-  }, [op, field, startValue, endValue, onFilterChange]);
+    onFilterChange(clearDateRangeFilterTime(filter));
+  }, [filter, onFilterChange]);
 
   return (
     <div className={className} data-testid="between-date-picker">
diff --git a/frontend/src/metabase/query_builder/components/filters/pickers/DatePicker/SingleDatePicker.tsx b/frontend/src/metabase/query_builder/components/filters/pickers/DatePicker/SingleDatePicker.tsx
index 8bae4a03155..1ba385a8ee8 100644
--- a/frontend/src/metabase/query_builder/components/filters/pickers/DatePicker/SingleDatePicker.tsx
+++ b/frontend/src/metabase/query_builder/components/filters/pickers/DatePicker/SingleDatePicker.tsx
@@ -1,9 +1,11 @@
-/* eslint-disable react/prop-types */
 import React from "react";
-
 import { SelectAll } from "metabase/components/Calendar";
-import { setTimeComponent } from "metabase-lib/lib/queries/utils/query-time";
 import Filter from "metabase-lib/lib/queries/structured/Filter";
+import {
+  clearDateFilterTime,
+  getDateFilterValue,
+  setDateFilterValue,
+} from "metabase-lib/lib/queries/utils/date-filters";
 import SpecificDatePicker from "./SpecificDatePicker";
 
 export type SingleDatePickerProps = {
@@ -17,7 +19,7 @@ export type SingleDatePickerProps = {
 
 const SingleDatePicker = ({
   className,
-  filter: [op, field, value],
+  filter,
   onFilterChange,
   hideTimeSelectors,
   selectAll,
@@ -25,11 +27,11 @@ const SingleDatePicker = ({
 }: SingleDatePickerProps) => (
   <SpecificDatePicker
     className={className}
-    value={value}
+    value={getDateFilterValue(filter)}
     primaryColor={primaryColor}
     selectAll={selectAll}
-    onChange={value => onFilterChange([op, field, value])}
-    onClear={() => onFilterChange([op, field, setTimeComponent(value)])}
+    onChange={value => onFilterChange(setDateFilterValue(filter, value))}
+    onClear={() => onFilterChange(clearDateFilterTime(filter))}
     autoFocus
     hasCalendar
     hideTimeSelectors={hideTimeSelectors}
-- 
GitLab