github.com/pyroscope-io/pyroscope@v0.37.3-0.20230725203016-5f6947968bd0/webapp/javascript/components/CustomDatePicker.tsx (about)

     1  import React, { useState, useEffect } from 'react';
     2  import { isAfter, isSameSecond } from 'date-fns';
     3  import DatePicker from 'react-datepicker';
     4  import Button from '@webapp/ui/Button';
     5  import { formatAsOBject, getUTCdate } from '@webapp/util/formatDate';
     6  import useTimeZone from '@webapp/hooks/timeZone.hook';
     7  import Select from '@webapp/ui/Select';
     8  import TextField from '@webapp/ui/Form/TextField';
     9  import styles from './CustomDatePicker.module.scss';
    10  
    11  interface CustomDatePickerProps {
    12    from: string;
    13    until: string;
    14    onSubmit: (from: string, until: string) => void;
    15  }
    16  function CustomDatePicker({ from, until, onSubmit }: CustomDatePickerProps) {
    17    const {
    18      options: timeZoneOptions,
    19      changeTimeZoneOffset,
    20      offset,
    21    } = useTimeZone();
    22    const [warning, setWarning] = useState(false);
    23    const [selectedDate, setSelectedDate] = useState({
    24      from: formatAsOBject(from),
    25      until: formatAsOBject(until),
    26    });
    27  
    28    const updateDateRange = () => {
    29      if (
    30        isSameSecond(selectedDate.from, selectedDate.until) ||
    31        isAfter(selectedDate.from, selectedDate.until)
    32      ) {
    33        return setWarning(true);
    34      }
    35  
    36      onSubmit(
    37        Math.round(selectedDate.from.getTime() / 1000).toString(),
    38        Math.round(selectedDate.until.getTime() / 1000).toString()
    39      );
    40      return setWarning(false);
    41    };
    42  
    43    // Since 'from' and 'until' are the source of truth
    44    // Since our component state back when they change
    45    useEffect(() => {
    46      setSelectedDate({
    47        ...selectedDate,
    48        from: formatAsOBject(from),
    49        until: formatAsOBject(until),
    50      });
    51    }, [from, until]);
    52  
    53    const selectFromAsDate = getUTCdate(selectedDate.from, offset);
    54    const selectUntilAsDate = getUTCdate(selectedDate.until, offset);
    55  
    56    const onDateChange = (date: Date | null, area: 'from' | 'until') => {
    57      if (date) {
    58        setSelectedDate({
    59          ...selectedDate,
    60          [area]:
    61            offset === 0
    62              ? new Date(
    63                  date.getTime() + date.getTimezoneOffset() * 60 * 1000 * -1
    64                )
    65              : date,
    66        });
    67      }
    68    };
    69  
    70    return (
    71      <div className="drp-custom">
    72        <h4>Custom Date Range</h4>
    73        <div className="from">
    74          <DatePicker
    75            id="datepicker-from"
    76            selected={selectFromAsDate}
    77            onChange={(date) => onDateChange(date, 'from')}
    78            selectsStart
    79            showTimeSelect
    80            startDate={selectFromAsDate}
    81            dateFormat="yyyy-MM-dd hh:mm aa"
    82            customInput={
    83              <TextField
    84                className={styles.datePickerInput}
    85                label="From:"
    86                variant="light"
    87              />
    88            }
    89          />
    90        </div>
    91        <div className="until">
    92          <DatePicker
    93            id="datepicker-until"
    94            selected={selectUntilAsDate}
    95            onChange={(date) => onDateChange(date, 'until')}
    96            selectsEnd
    97            showTimeSelect
    98            startDate={selectFromAsDate}
    99            endDate={selectUntilAsDate}
   100            minDate={selectFromAsDate}
   101            dateFormat="yyyy-MM-dd hh:mm aa"
   102            customInput={
   103              <TextField
   104                className={styles.datePickerInput}
   105                label="Until:"
   106                variant="light"
   107              />
   108            }
   109          />
   110        </div>
   111        {warning && <p style={{ color: 'red' }}>Warning: invalid date Range</p>}
   112  
   113        <Button type="submit" kind="secondary" onClick={() => updateDateRange()}>
   114          Apply range
   115        </Button>
   116  
   117        <div style={{ marginTop: 10 }}>
   118          <label htmlFor="select-timezone">Time Zone: </label>
   119          <Select
   120            ariaLabel="select-timezone"
   121            onChange={(e) => changeTimeZoneOffset(Number(e.target.value))}
   122            id="select-timezone"
   123            value={String(offset)}
   124            disabled={timeZoneOptions.every((o) => o.value === 0)}
   125            className={styles.timezoneSelect}
   126          >
   127            {timeZoneOptions.map((o) => (
   128              <option key={o.key} value={o.value}>
   129                {o.label}
   130              </option>
   131            ))}
   132          </Select>
   133        </div>
   134      </div>
   135    );
   136  }
   137  
   138  export default CustomDatePicker;