date-fns#addDays JavaScript Examples

The following examples show how to use date-fns#addDays. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: locations.js    From app-personium-trails with Apache License 2.0 6 votes vote down vote up
async getVisitsByDate(date) {
    const from = date.getTime();
    const to = addDays(date, 1).getTime() - 1;
    return await (
      await fetch(
        `${handler.boxUrl}index/Visit?$filter=startTime ge ${from} and endTime lt ${to}`
      )
    ).json();
  }
Example #2
Source File: locations.js    From app-personium-trails with Apache License 2.0 6 votes vote down vote up
async getStaysByDate(date) {
    const from = date.getTime();
    const to = addDays(date, 1).getTime() - 1;
    return await (
      await fetch(
        `${handler.boxUrl}index/Stay?$filter=startTime ge ${from} and endTime lt ${to}`
      )
    ).json();
  }
Example #3
Source File: Map.test.js    From ProjectLockdown with GNU General Public License v3.0 6 votes vote down vote up
props = {
    dark: "false",
    selectedDate: toJsonString(addDays(new Date(), startingPoint)),
    startDate: addDays(new Date(), startingPoint),
    onOpen: jest.fn(),
    daysRange: 70,
    isCountrySearchVisible: false,
    mapCord: coords,
}
Example #4
Source File: locations_direct.js    From app-personium-trails with Apache License 2.0 6 votes vote down vote up
async getTimelineByDate(date) {
    // fetch stat and fire event
    const from = getYMDFromDate(date);
    const to = getYMDFromDate(addDays(date, 1));
    const days = Array.from(new Set([from, to]));
    return Promise.all(
      days.map(ymd =>
        statDirectory(
          `${this.current_box_url}locations/${ymd}`,
          this.current_access_token
        )
      )
    )
      .then(results => new Map([].concat(...results.map(res => [...res]))))
      .then(results => {
        [...results].forEach(([key, val]) => statListener.fire(key, val));
        return results;
      });
  }
Example #5
Source File: utils.js    From nyc-makers-vs-covid with GNU General Public License v3.0 6 votes vote down vote up
export function shouldFormatDateDistance(date) {
  let deliveryDate = parse(date, 'MM/dd/yyyy', new Date())
  let fourDaysFromDeliveryDate = addDays(deliveryDate, 4)
  return isBefore(startOfToday(), fourDaysFromDeliveryDate)
}
Example #6
Source File: locations_direct.js    From app-personium-trails with Apache License 2.0 6 votes vote down vote up
async getEntityByDate(entityName, date) {
    this.refreshOHandler();
    const from = date.getTime();
    const to = addDays(date, 1).getTime() - 1;

    return await this.oHandler
      .get(entityName)
      .query({
        $filter: `startTime ge ${from} and startTime lt ${to}`,
        $format: 'json',
      })
      .then(res => {
        console.log(res);
        return res;
      })
      .then(res => res.d.results);
  }
Example #7
Source File: GroupingLegend.js    From discovery-mobile-ui with MIT License 5 votes vote down vote up
formatDays = (numDays) => {
  const d = new Date();
  return formatDistanceStrict(d, addDays(d, numDays), { unit: 'day' });
}
Example #8
Source File: DatePicker.js    From react-horizontal-datepicker with MIT License 5 votes vote down vote up
DatePicker = (props) => {
    const next = (event) => {
        event.preventDefault();
        const e = document.getElementById('container');
        const width = e ? e.getBoundingClientRect().width : null;
        e.scrollLeft += width - 60;
    };

    const prev = (event) => {
        event.preventDefault();
        const e = document.getElementById('container');
        const width = e ? e.getBoundingClientRect().width : null;
        e.scrollLeft -= width - 60;
    };

    const primaryColor = props.color? (props.color.indexOf("rgb") > 0?props.color:hexToRgb(props.color)):'rgb(54, 105, 238)';

    const startDate = props.startDate || new Date();
    const lastDate = addDays(startDate, props.days || 90);

    let buttonzIndex = {zIndex: 2};
    let buttonStyle = {background: primaryColor};
    let Component = DateView;

    if (props.type === "month") {
        buttonzIndex = {zIndex: 5};
        Component = MonthView;
        buttonStyle = {background: primaryColor, marginBottom: "5px"};
    }

    return (
        <div className={styles.container}>
            <div className={styles.buttonWrapper} style={buttonzIndex}>
                <button className={styles.button} style={buttonStyle} onClick={prev}>&lt;</button>
            </div>
            <Component {...props} primaryColor={primaryColor} startDate={startDate} lastDate={lastDate}/>
            <div className={styles.buttonWrapper} style={buttonzIndex}>
                <button className={styles.button} style={buttonStyle} onClick={next}>&gt;</button>
            </div>
        </div>
    )
}
Example #9
Source File: DatePicker.js    From react-horizontal-datepicker with MIT License 5 votes vote down vote up
DatePicker = props => {
  const next = event => {
    event.preventDefault();
    const e = document.getElementById('container');
    const width = e ? e.getBoundingClientRect().width : null;
    e.scrollLeft += width - 60;
  };

  const prev = event => {
    event.preventDefault();
    const e = document.getElementById('container');
    const width = e ? e.getBoundingClientRect().width : null;
    e.scrollLeft -= width - 60;
  };

  const primaryColor = props.color ? props.color.indexOf("rgb") > 0 ? props.color : hexToRgb(props.color) : 'rgb(54, 105, 238)';
  const startDate = props.startDate || new Date();
  const lastDate = addDays(startDate, props.days || 90);
  let buttonzIndex = {
    zIndex: 2
  };
  let buttonStyle = {
    background: primaryColor
  };
  let Component = DateView;

  if (props.type === "month") {
    buttonzIndex = {
      zIndex: 5
    };
    Component = MonthView;
    buttonStyle = {
      background: primaryColor,
      marginBottom: "5px"
    };
  }

  return /*#__PURE__*/React.createElement("div", {
    className: styles.container
  }, /*#__PURE__*/React.createElement("div", {
    className: styles.buttonWrapper,
    style: buttonzIndex
  }, /*#__PURE__*/React.createElement("button", {
    className: styles.button,
    style: buttonStyle,
    onClick: prev
  }, "<")), /*#__PURE__*/React.createElement(Component, _extends({}, props, {
    primaryColor: primaryColor,
    startDate: startDate,
    lastDate: lastDate
  })), /*#__PURE__*/React.createElement("div", {
    className: styles.buttonWrapper,
    style: buttonzIndex
  }, /*#__PURE__*/React.createElement("button", {
    className: styles.button,
    style: buttonStyle,
    onClick: next
  }, ">")));
}
Example #10
Source File: LocationFilter.js    From app-personium-trails with Apache License 2.0 5 votes vote down vote up
export function LocationFilter({ year, month, day }) {
  const [modalOpen, setModalOpen] = useState(false);
  const handleOpen = useCallback(() => setModalOpen(true), [setModalOpen]);
  const handleClose = useCallback(() => setModalOpen(false), [setModalOpen]);
  const history = useHistory();

  const handleDayClick = useCallback(
    date => {
      history.push(
        `/locations/${date.getFullYear()}-${date.getMonth() +
          1}-${date.getDate()}`
      );
      setModalOpen(false);
    },
    [history, setModalOpen]
  );

  const handleNextClick = useCallback(() => {
    const date = new Date(year, month - 1, day);
    history.push(getDateString(addDays(date, 1)));
  }, [year, month, day, history]);

  const handlePrevClick = useCallback(() => {
    const date = new Date(year, month - 1, day);
    history.push(getDateString(addDays(date, -1)));
  }, [year, month, day, history]);

  return (
    <>
      <Modal size="small" onClose={handleClose} open={modalOpen} basic>
        <Card centered raised>
          <Calendar
            value={new Date(year, month - 1, day)}
            onClickDay={handleDayClick}
          />
        </Card>
      </Modal>
      <Grid>
        <Grid.Column width={3}>
          <Button
            color="teal"
            icon="chevron left"
            fluid
            onClick={handlePrevClick}
          />
        </Grid.Column>
        <Grid.Column width={10}>
          <Button basic color="teal" onClick={handleOpen} fluid>
            <Icon name="calendar" />
            {new Date(
              Number(year),
              Number(month - 1),
              Number(day)
            ).toLocaleDateString()}
          </Button>
        </Grid.Column>
        <Grid.Column width={3}>
          <Button
            color="teal"
            icon="chevron right"
            fluid
            onClick={handleNextClick}
          />
        </Grid.Column>
      </Grid>
      <Divider />
    </>
  );
}
Example #11
Source File: init.client.js    From audiobookshelf with GNU General Public License v3.0 5 votes vote down vote up
Vue.prototype.$addDaysToDate = (jsdate, daysToAdd) => {
  var date = addDays(jsdate, daysToAdd)
  if (!date || !isDate(date)) return null
  return date
}
Example #12
Source File: init.client.js    From audiobookshelf with GNU General Public License v3.0 5 votes vote down vote up
Vue.prototype.$addDaysToToday = (daysToAdd) => {
  var date = addDays(new Date(), daysToAdd)
  if (!date || !isDate(date)) return null
  return date
}
Example #13
Source File: Calendar.js    From umami with MIT License 5 votes vote down vote up
DaySelector = ({ date, minDate, maxDate, locale, onSelect }) => {
  const dateLocale = getDateLocale(locale);
  const weekStartsOn = dateLocale?.options?.weekStartsOn || 0;
  const startWeek = startOfWeek(date, {
    locale: dateLocale,
    weekStartsOn,
  });
  const startMonth = startOfMonth(date);
  const startDay = subDays(startMonth, startMonth.getDay() - weekStartsOn);
  const month = date.getMonth();
  const year = date.getFullYear();

  const daysOfWeek = [];
  for (let i = 0; i < 7; i++) {
    daysOfWeek.push(addDays(startWeek, i));
  }

  const days = [];
  for (let i = 0; i < 35; i++) {
    days.push(addDays(startDay, i));
  }

  return (
    <table>
      <thead>
        <tr>
          {daysOfWeek.map((day, i) => (
            <th key={i} className={locale}>
              {dateFormat(day, 'EEE', locale)}
            </th>
          ))}
        </tr>
      </thead>
      <tbody>
        {chunk(days, 7).map((week, i) => (
          <tr key={i}>
            {week.map((day, j) => {
              const disabled = isBefore(day, minDate) || isAfter(day, maxDate);
              return (
                <td
                  key={j}
                  className={classNames({
                    [styles.selected]: isSameDay(date, day),
                    [styles.faded]: day.getMonth() !== month || day.getFullYear() !== year,
                    [styles.disabled]: disabled,
                  })}
                  onClick={!disabled ? () => onSelect(day) : null}
                >
                  {day.getDate()}
                </td>
              );
            })}
          </tr>
        ))}
      </tbody>
    </table>
  );
}
Example #14
Source File: date.js    From umami with MIT License 5 votes vote down vote up
dateFuncs = {
  minute: [differenceInMinutes, addMinutes, startOfMinute],
  hour: [differenceInHours, addHours, startOfHour],
  day: [differenceInCalendarDays, addDays, startOfDay],
  month: [differenceInCalendarMonths, addMonths, startOfMonth],
  year: [differenceInCalendarYears, addYears, startOfYear],
}
Example #15
Source File: DateView.js    From react-horizontal-datepicker with MIT License 4 votes vote down vote up
DateView = ({
  startDate,
  lastDate,
  selectDate,
  getSelectedDay,
  primaryColor,
  labelFormat
}) => {
  const [selectedDate, setSelectedDate] = useState(null);
  const firstSection = {
    marginLeft: '40px'
  };
  const selectedStyle = {
    fontWeight: "bold",
    width: "45px",
    height: "45px",
    borderRadius: "50%",
    border: `2px solid ${primaryColor}`,
    color: primaryColor
  };
  const labelColor = {
    color: primaryColor
  };

  const getStyles = day => {
    return isSameDay(day, selectedDate) ? selectedStyle : null;
  };

  const getId = day => {
    return isSameDay(day, selectedDate) ? 'selected' : "";
  };

  const renderDays = () => {
    const dayFormat = "E";
    const dateFormat = "d";
    const months = [];
    let days = [];

    for (let i = 0; i <= differenceInMonths(lastDate, startDate); i++) {
      let start, end;
      const month = startOfMonth(addMonths(startDate, i));
      start = i === 0 ? Number(format(startDate, dateFormat)) - 1 : 0;
      end = i === differenceInMonths(lastDate, startDate) ? Number(format(lastDate, "d")) : Number(format(lastDayOfMonth(month), "d"));

      for (let j = start; j < end; j++) {
        let currentDay = addDays(month, j);
        days.push( /*#__PURE__*/React.createElement("div", {
          id: `${getId(currentDay)}`,
          className: styles.dateDayItem,
          style: getStyles(currentDay),
          key: currentDay,
          onClick: () => onDateClick(currentDay)
        }, /*#__PURE__*/React.createElement("div", {
          className: styles.dayLabel
        }, format(currentDay, dayFormat)), /*#__PURE__*/React.createElement("div", {
          className: styles.dateLabel
        }, format(currentDay, dateFormat))));
      }

      months.push( /*#__PURE__*/React.createElement("div", {
        className: styles.monthContainer,
        key: month
      }, /*#__PURE__*/React.createElement("span", {
        className: styles.monthYearLabel,
        style: labelColor
      }, format(month, labelFormat || "MMMM yyyy")), /*#__PURE__*/React.createElement("div", {
        className: styles.daysContainer,
        style: i === 0 ? firstSection : null
      }, days)));
      days = [];
    }

    return /*#__PURE__*/React.createElement("div", {
      id: "container",
      className: styles.dateListScrollable
    }, months);
  };

  const onDateClick = day => {
    setSelectedDate(day);

    if (getSelectedDay) {
      getSelectedDay(day);
    }
  };

  useEffect(() => {
    if (getSelectedDay) {
      if (selectDate) {
        getSelectedDay(selectDate);
      } else {
        getSelectedDay(startDate);
      }
    }
  }, []);
  useEffect(() => {
    if (selectDate) {
      if (!isSameDay(selectedDate, selectDate)) {
        setSelectedDate(selectDate);
        setTimeout(() => {
          let view = document.getElementById('selected');

          if (view) {
            view.scrollIntoView({
              behavior: "smooth",
              inline: "center",
              block: "nearest"
            });
          }
        }, 20);
      }
    }
  }, [selectDate]);
  return /*#__PURE__*/React.createElement(React.Fragment, null, renderDays());
}
Example #16
Source File: dateFns.js    From the-eye-knows-the-garbage with MIT License 4 votes vote down vote up
generateConfig = {
  // get
  getNow: function getNow() {
    return new Date();
  },
  getWeekDay: function getWeekDay(date) {
    return getDay(date);
  },
  getYear: function getYear(date) {
    return _getYear(date);
  },
  getMonth: function getMonth(date) {
    return _getMonth(date);
  },
  getDate: function getDate(date) {
    return _getDate(date);
  },
  getHour: function getHour(date) {
    return getHours(date);
  },
  getMinute: function getMinute(date) {
    return getMinutes(date);
  },
  getSecond: function getSecond(date) {
    return getSeconds(date);
  },
  // set
  addYear: function addYear(date, diff) {
    return addYears(date, diff);
  },
  addMonth: function addMonth(date, diff) {
    return addMonths(date, diff);
  },
  addDate: function addDate(date, diff) {
    return addDays(date, diff);
  },
  setYear: function setYear(date, year) {
    return _setYear(date, year);
  },
  setMonth: function setMonth(date, month) {
    return _setMonth(date, month);
  },
  setDate: function setDate(date, num) {
    return _setDate(date, num);
  },
  setHour: function setHour(date, hour) {
    return setHours(date, hour);
  },
  setMinute: function setMinute(date, minute) {
    return setMinutes(date, minute);
  },
  setSecond: function setSecond(date, second) {
    return setSeconds(date, second);
  },
  // Compare
  isAfter: function isAfter(date1, date2) {
    return _isAfter(date1, date2);
  },
  isValidate: function isValidate(date) {
    return isValid(date);
  },
  locale: {
    getWeekFirstDay: function getWeekFirstDay(locale) {
      var clone = Locale[dealLocal(locale)];
      return clone.options.weekStartsOn;
    },
    getWeek: function getWeek(locale, date) {
      return _getWeek(date, {
        locale: Locale[dealLocal(locale)]
      });
    },
    format: function format(locale, date, _format) {
      if (!isValid(date)) {
        return null;
      }

      return formatDate(date, _format, {
        locale: Locale[dealLocal(locale)]
      });
    },
    parse: function parse(locale, text, formats) {
      for (var i = 0; i < formats.length; i += 1) {
        var format = formats[i];
        var formatText = text;
        var date = parseDate(formatText, format, new Date(), {
          locale: Locale[dealLocal(locale)]
        });

        if (isValid(date)) {
          return date;
        }
      }

      return null;
    }
  }
}
Example #17
Source File: index.js    From neutron with Mozilla Public License 2.0 4 votes vote down vote up
DialogPauseNotifications = () => {
  // const classes = useStyles();
  const dispatch = useDispatch();

  const pauseNotificationsInfo = useSelector((state) => state.notifications.pauseNotificationsInfo);
  const showDateTimePicker = useSelector((state) => state.notifications.showDateTimePicker);

  const shouldPauseNotifications = pauseNotificationsInfo !== null;

  const quickShortcuts = [
    {
      name: '15 minutes',
      calcDate: () => addMinutes(new Date(), 15),
    },
    {
      name: '30 minutes',
      calcDate: () => addMinutes(new Date(), 30),
    },
    {
      name: '45 minutes',
      calcDate: () => addMinutes(new Date(), 45),
    },
    {
      name: '1 hour',
      calcDate: () => addHours(new Date(), 1),
    },
    {
      name: '2 hours',
      calcDate: () => addHours(new Date(), 2),
    },
    {
      name: '4 hours',
      calcDate: () => addHours(new Date(), 4),
    },
    {
      name: '6 hours',
      calcDate: () => addHours(new Date(), 6),
    },
    {
      name: '8 hours',
      calcDate: () => addHours(new Date(), 8),
    },
    {
      name: '10 hours',
      calcDate: () => addHours(new Date(), 8),
    },
    {
      name: '12 hours',
      calcDate: () => addHours(new Date(), 12),
    },
    {
      name: 'Until tomorrow',
      calcDate: () => addDays(new Date(), 1),
    },
    {
      name: 'Until next week',
      calcDate: () => addWeeks(new Date(), 1),
    },
  ];

  const pauseNotif = (tilDate) => {
    requestSetPreference('pauseNotifications', `pause:${tilDate.toString()}`);
    requestShowNotification({
      title: 'Notifications paused',
      body: `Notifications paused until ${formatDate(tilDate)}.`,
    });
    getCurrentWindow().close();
  };

  const renderList = () => {
    if (shouldPauseNotifications) {
      return (
        <List
          dense
          disablePadding
        >
          <ListItem sx={{
            background: `url(${nightBackgroundPng})`,
            height: 210,
            backgroundSize: 400,
            alignItems: 'flex-end',
          }}
          >
            <ListItemText
              primary={`Notifications paused until
              ${formatDate(new Date(pauseNotificationsInfo.tilDate))}.`}
              sx={{
                color: 'common.white',
              }}
            />
          </ListItem>
          <ListItem button>
            <ListItemText
              primary="Resume notifications"
              onClick={() => {
                if (pauseNotificationsInfo.reason === 'scheduled') {
                  requestSetPreference('pauseNotifications', `resume:${pauseNotificationsInfo.tilDate}`);
                } else if (pauseNotificationsInfo.schedule
                  && new Date() < new Date(pauseNotificationsInfo.schedule.to)) {
                  requestSetPreference('pauseNotifications', `resume:${pauseNotificationsInfo.schedule.to}`);
                } else {
                  requestSetPreference('pauseNotifications', null);
                }
                requestShowNotification({
                  title: 'Notifications resumed',
                  body: 'Notifications are now resumed.',
                });
                getCurrentWindow().close();
              }}
            />
          </ListItem>
          {pauseNotificationsInfo.reason !== 'scheduled' && (
            <>
              <Divider />
              <ListItem
                button
                onClick={() => {
                  const template = quickShortcuts.map((shortcut) => ({
                    label: shortcut.name,
                    click: () => pauseNotif(shortcut.calcDate()),
                  }));
                  template.push({
                    label: 'Custom',
                    click: () => dispatch(updateShowDateTimePicker(true)),
                  });
                  const menu = Menu.buildFromTemplate(template);
                  menu.popup({
                    window: getCurrentWindow(),
                  });
                }}
              >
                <ListItemText primary="Adjust time" />
                <ChevronRightIcon color="action" />
              </ListItem>
            </>
          )}
          <Divider />
          <ListItem button>
            <ListItemText
              primary={pauseNotificationsInfo.reason === 'scheduled' ? 'Adjust schedule...' : 'Pause notifications by schedule...'}
              onClick={() => {
                requestShowPreferencesWindow('notifications');
                getCurrentWindow().close();
              }}
            />
          </ListItem>
        </List>
      );
    }

    return (
      <List
        dense
        disablePadding
        subheader={<ListSubheader component="div">Pause notifications</ListSubheader>}
      >
        {quickShortcuts.map((shortcut) => (
          <ListItem
            button
            key={shortcut.name}
            onClick={() => pauseNotif(shortcut.calcDate())}
          >
            <ListItemText primary={shortcut.name} />
          </ListItem>
        ))}
        <ListItem
          button
          onClick={() => dispatch(updateShowDateTimePicker(true))}
        >
          <ListItemText primary="Custom..." />
        </ListItem>
        <Divider />
        <DateTimePicker
          value={new Date()}
          onChange={pauseNotif}
          label="Custom"
          open={showDateTimePicker}
          onOpen={() => dispatch(updateShowDateTimePicker(true))}
          onClose={() => dispatch(updateShowDateTimePicker(false))}
          disablePast
          showTodayButton
          // eslint-disable-next-line react/jsx-props-no-spreading
          renderInput={() => (
            <ListItem button>
              <ListItemText
                primary="Pause notifications by schedule..."
                onClick={() => {
                  requestShowPreferencesWindow('notifications');
                  getCurrentWindow().close();
                }}
              />
            </ListItem>
          )}
        />
      </List>
    );
  };

  return (
    <>
      {renderList()}
    </>
  );
}
Example #18
Source File: DateView.js    From react-horizontal-datepicker with MIT License 4 votes vote down vote up
DateView = ({startDate, lastDate, selectDate, getSelectedDay, primaryColor, labelFormat, marked}) => {
    const [selectedDate, setSelectedDate] = useState(null);
    const firstSection = {marginLeft: '40px'};
    const selectedStyle = {fontWeight:"bold",width:"45px",height:"45px",borderRadius:"50%",border:`2px solid ${primaryColor}`,color:primaryColor};
    const labelColor = {color: primaryColor};
    const markedStyle = {color: "#8c3737", padding: "2px", fontSize: 12};

    const getStyles = (day) => {
        return isSameDay(day, selectedDate)?selectedStyle:null;
    };

    const getId = (day) => {
        return isSameDay(day, selectedDate)?'selected':"";
    };

    const getMarked = (day) => {
        let markedRes = marked.find(i => isSameDay(i.date, day));
        if (markedRes) {
            if (!markedRes?.marked) {
                return;
            }

            return <div style={{ ...markedRes?.style ?? markedStyle }} className={styles.markedLabel}>
                {markedRes.text}
            </div>;
        }

        return "";
    };

    const renderDays = () => {
        const dayFormat = "E";
        const dateFormat = "d";

        const months = [];
        let days = [];

        // const styleItemMarked = marked ? styles.dateDayItemMarked : styles.dateDayItem;

        for (let i = 0; i <= differenceInMonths(lastDate, startDate); i++) {
            let start, end;
            const month = startOfMonth(addMonths(startDate, i));

            start = i === 0 ? Number(format(startDate, dateFormat)) - 1 : 0;
            end = i === differenceInMonths(lastDate, startDate) ? Number(format(lastDate, "d")) : Number(format(lastDayOfMonth(month), "d"));

            for (let j = start; j < end; j++) {
                let currentDay = addDays(month, j);

                days.push(
                    <div id={`${getId(currentDay)}`}
                         className={marked ? styles.dateDayItemMarked : styles.dateDayItem}
                         style={getStyles(currentDay)}
                         key={currentDay}
                         onClick={() => onDateClick(currentDay)}
                    >
                        <div className={styles.dayLabel}>{format(currentDay, dayFormat)}</div>
                        <div className={styles.dateLabel}>{format(currentDay, dateFormat)}</div>
                        {getMarked(currentDay)}
                    </div>
                );
            }
            months.push(
                <div className={styles.monthContainer}
                     key={month}
                >
                    <span className={styles.monthYearLabel} style={labelColor}>
                        {format(month, labelFormat || "MMMM yyyy")}
                    </span>
                    <div className={styles.daysContainer} style={i===0?firstSection:null}>
                        {days}
                    </div>
                </div>
            );
            days = [];

        }

        return <div id={"container"} className={styles.dateListScrollable}>{months}</div>;
    }

    const onDateClick = day => {
        setSelectedDate(day);
        if (getSelectedDay) {
            getSelectedDay(day);
        }
    };

    useEffect(() => {
        if (getSelectedDay) {
            if (selectDate) {
                getSelectedDay(selectDate);
            } else {
                getSelectedDay(startDate);
            }
        }
    }, []);

    useEffect(() => {
        if (selectDate) {
            if (!isSameDay(selectedDate, selectDate)) {
                setSelectedDate(selectDate);
                setTimeout(() => {
                    let view = document.getElementById('selected');
                    if (view) {
                        view.scrollIntoView({behavior: "smooth", inline: "center", block: "nearest"});
                    }
                }, 20);
            }
        }
    }, [selectDate]);

    return <React.Fragment>{renderDays()}</React.Fragment>
}
Example #19
Source File: DateRangePickerCalendar.test.js    From react-nice-dates with MIT License 4 votes vote down vote up
describe('DateRangePickerCalendar', () => {
  it('should render', () => {
    const { getAllByText } = render(
      <DateRangePickerCalendar
        locale={locale}
        onStartDateChange={() => {}}
        onEndDateChange={() => {}}
        onFocusChange={() => {}}
      />
    )

    expect(getAllByText('1').length).toBeGreaterThan(0)
  })

  it('should call callbacks on date selection', () => {
    const handleStartDateChange = jest.fn()
    const handleEndDateChange = jest.fn()
    const handleFocusChange = jest.fn()

    const { getAllByText, rerender } = render(
      <DateRangePickerCalendar
        locale={locale}
        focus={START_DATE}
        onStartDateChange={handleStartDateChange}
        onEndDateChange={handleEndDateChange}
        onFocusChange={handleFocusChange}
      />
    )

    fireEvent.click(getAllByText('1')[0])

    expect(handleStartDateChange).toHaveBeenCalledTimes(1)
    expect(handleEndDateChange).toHaveBeenCalledTimes(0)
    expect(handleFocusChange).toHaveBeenCalledWith(END_DATE)

    rerender(
      <DateRangePickerCalendar
        locale={locale}
        focus={END_DATE}
        startDate={startOfMonth(new Date())}
        onStartDateChange={handleStartDateChange}
        onEndDateChange={handleEndDateChange}
        onFocusChange={handleFocusChange}
      />
    )

    fireEvent.click(getAllByText('2')[0])

    expect(handleStartDateChange).toHaveBeenCalledTimes(1)
    expect(handleEndDateChange).toHaveBeenCalledTimes(1)
    expect(handleFocusChange).toHaveBeenCalledWith(null)
  })

  it('should display selected date range', () => {
    const startDate = startOfMonth(new Date())
    const endDate = addDays(startDate, 2)

    const { container, getAllByText, rerender } = render(
      <DateRangePickerCalendar locale={locale} startDate={startDate} />
    )

    expect(getAllByText('1')[0].parentElement).toHaveClass('-selected')
    expect(container.querySelectorAll('.-selected').length).toBe(1)

    rerender(<DateRangePickerCalendar locale={locale} startDate={startDate} endDate={endDate} />)

    expect(getAllByText('1')[0].parentElement).toHaveClass('-selected -selected-start')
    expect(getAllByText('2')[0].parentElement).toHaveClass('-selected -selected-middle')
    expect(getAllByText('3')[0].parentElement).toHaveClass('-selected -selected-end')
    expect(container.querySelectorAll('.-selected').length).toBe(3)
  })

  it('should display pre-selected start date’s month on initial render', () => {
    const today = new Date()
    const pastDate = subMonths(today, 1)
    const monthName = format(pastDate, 'LLLL', { locale })

    const { getByText } = render(<DateRangePickerCalendar locale={locale} startDate={pastDate} endDate={today} />)

    expect(getByText(monthName, { exact: false })).toBeInTheDocument()
  })

  it('should display pre-selected end date’s month on initial render', () => {
    const pastDate = subMonths(new Date(), 1)
    const monthName = format(pastDate, 'LLLL', { locale })

    const { getByText } = render(<DateRangePickerCalendar locale={locale} endDate={pastDate} />)

    expect(getByText(monthName, { exact: false })).toBeInTheDocument()
  })

  it('should maintain the selected start date’s time when selecting a new date', () => {
    const handleStartDateChange = jest.fn()

    const { getByText } = render(
      <DateRangePickerCalendar
        locale={locale}
        focus={START_DATE}
        startDate={new Date(2020, 1, 24, 18, 30)}
        onStartDateChange={handleStartDateChange}
      />
    )

    fireEvent.click(getByText('25'))

    expect(handleStartDateChange).toHaveBeenCalledWith(new Date(2020, 1, 25, 18, 30))
  })

  it('should maintain the selected end date’s time when selecting a new date', () => {
    const handleEndDateChange = jest.fn()

    const { getByText } = render(
      <DateRangePickerCalendar
        locale={locale}
        focus={END_DATE}
        endDate={new Date(2020, 1, 24, 18, 30)}
        onEndDateChange={handleEndDateChange}
      />
    )

    fireEvent.click(getByText('25'))

    expect(handleEndDateChange).toHaveBeenCalledWith(new Date(2020, 1, 25, 18, 30))
  })

  it('should allow same day selection by default (when minimumLength is 0)', () => {
    const startDate = startOfDay(set(new Date(), { date: 13 }))

    const { getByText } = render(<DateRangePickerCalendar locale={locale} focus={END_DATE} startDate={startDate} />)

    expect(getByText('13').parentElement).not.toHaveClass('-disabled')
  })

  it('should disable dates before the start date when selecting an end date with no existing end date selected', () => {
    const startDate = startOfDay(set(new Date(), { date: 18 }))

    const { getByText } = render(<DateRangePickerCalendar locale={locale} focus={END_DATE} startDate={startDate} />)

    expect(getByText('16').parentElement).toHaveClass('-disabled')
    expect(getByText('17').parentElement).toHaveClass('-disabled')
    expect(getByText('18').parentElement).not.toHaveClass('-disabled')
  })

  it('should disable dates after the end date when selecting a start date with no existing start date selected', () => {
    const endDate = startOfDay(set(new Date(), { date: 13 }))

    const { getByText } = render(<DateRangePickerCalendar locale={locale} focus={START_DATE} endDate={endDate} />)

    expect(getByText('13').parentElement).not.toHaveClass('-disabled')
    expect(getByText('14').parentElement).toHaveClass('-disabled')
    expect(getByText('15').parentElement).toHaveClass('-disabled')
  })

  it('should disable in-between dates when minimumLength is set', () => {
    const startDate = startOfDay(set(new Date(), { date: 18 }))

    const { getByText } = render(
      <DateRangePickerCalendar locale={locale} focus={END_DATE} startDate={startDate} minimumLength={3} />
    )

    expect(getByText('18').parentElement).toHaveClass('-disabled')
    expect(getByText('19').parentElement).toHaveClass('-disabled')
    expect(getByText('20').parentElement).toHaveClass('-disabled')
    expect(getByText('21').parentElement).not.toHaveClass('-disabled')
  })

  it('should disable in-between dates when selecting start date and minimumLength is set', () => {
    const endDate = startOfDay(set(new Date(), { date: 18 }))

    const { getByText } = render(
      <DateRangePickerCalendar locale={locale} focus={START_DATE} endDate={endDate} minimumLength={3} />
    )

    expect(getByText('18').parentElement).toHaveClass('-disabled')
    expect(getByText('17').parentElement).toHaveClass('-disabled')
    expect(getByText('16').parentElement).toHaveClass('-disabled')
    expect(getByText('15').parentElement).not.toHaveClass('-disabled')
  })

  it('should disable later dates when maximumLength is set', () => {
    const startDate = startOfDay(set(new Date(), { date: 13 }))

    const { getByText } = render(
      <DateRangePickerCalendar locale={locale} focus={END_DATE} startDate={startDate} maximumLength={3} />
    )

    expect(getByText('13').parentElement).not.toHaveClass('-disabled')
    expect(getByText('14').parentElement).not.toHaveClass('-disabled')
    expect(getByText('15').parentElement).not.toHaveClass('-disabled')
    expect(getByText('16').parentElement).not.toHaveClass('-disabled')
    expect(getByText('17').parentElement).toHaveClass('-disabled')
  })

  it('should disable earlier dates when selecting start date and maximumLength is set', () => {
    const endDate = startOfDay(set(new Date(), { date: 18 }))

    const { getByText } = render(
      <DateRangePickerCalendar locale={locale} focus={START_DATE} endDate={endDate} maximumLength={3} />
    )

    expect(getByText('18').parentElement).not.toHaveClass('-disabled')
    expect(getByText('17').parentElement).not.toHaveClass('-disabled')
    expect(getByText('16').parentElement).not.toHaveClass('-disabled')
    expect(getByText('15').parentElement).not.toHaveClass('-disabled')
    expect(getByText('14').parentElement).toHaveClass('-disabled')
  })
})
Example #20
Source File: TimeseriesBrush.js    From covid19india-react with MIT License 4 votes vote down vote up
function TimeseriesBrush({
  timeseries,
  dates,
  currentBrushSelection,
  endDate,
  lookback,
  setBrushSelectionEnd,
  setLookback,
  animationIndex,
}) {
  const chartRef = useRef();
  const [wrapperRef, {width, height}] = useMeasure();

  const endDateMin =
    lookback !== null
      ? min([
          formatISO(addDays(parseIndiaDate(dates[0]), lookback), {
            representation: 'date',
          }),
          endDate,
        ])
      : endDate;

  const xScale = useMemo(() => {
    const T = dates.length;

    // Chart extremes
    const chartRight = width - margin.right;

    return scaleTime()
      .clamp(true)
      .domain([
        parseIndiaDate(dates[0] || endDate),
        parseIndiaDate(dates[T - 1] || endDate),
      ])
      .range([margin.left, chartRight]);
  }, [width, endDate, dates]);

  useEffect(() => {
    if (!width || !height) return;

    // Chart extremes
    const chartBottom = height - margin.bottom;

    const xAxis = (g) =>
      g
        .attr('class', 'x-axis')
        .call(axisBottom(xScale).ticks(numTicksX(width)));

    // Switched to daily confirmed instead of cumulative ARD
    const timeseriesStacked = stack()
      .keys(BRUSH_STATISTICS)
      .value((date, statistic) =>
        Math.max(0, getStatistic(timeseries[date], 'delta', statistic))
      )(dates);

    const yScale = scaleLinear()
      .clamp(true)
      .domain([
        0,
        max(
          timeseriesStacked[timeseriesStacked.length - 1],
          ([, y1]) => yBufferTop * y1
        ),
      ])
      .range([chartBottom, margin.top]);

    const svg = select(chartRef.current);

    const t = svg.transition().duration(D3_TRANSITION_DURATION);

    svg
      .select('.x-axis')
      .attr('pointer-events', 'none')
      .style('transform', `translate3d(0, ${chartBottom}px, 0)`)
      .transition(t)
      .call(xAxis);

    const areaPath = area()
      .curve(curveMonotoneX)
      .x((d) => xScale(parseIndiaDate(d.data)))
      .y0((d) => yScale(d[0]))
      .y1((d) => yScale(d[1]));

    svg
      .select('.trend-areas')
      .selectAll('.trend-area')
      .data(timeseriesStacked)
      .join(
        (enter) =>
          enter
            .append('path')
            .attr('class', 'trend-area')
            .attr('fill', ({key}) => STATISTIC_CONFIGS[key].color)
            .attr('fill-opacity', 0.4)
            .attr('stroke', ({key}) => STATISTIC_CONFIGS[key].color)
            .attr('d', areaPath)
            .attr('pointer-events', 'none'),
        (update) =>
          update
            .transition(t)
            .attrTween('d', function (date) {
              const previous = select(this).attr('d');
              const current = areaPath(date);
              return interpolatePath(previous, current);
            })
            .selection()
      );
  }, [dates, width, height, xScale, timeseries]);

  const defaultSelection = currentBrushSelection.map((date) =>
    xScale(parseIndiaDate(date))
  );

  const brush = useMemo(() => {
    if (!width || !height) return;
    // Chart extremes
    const chartRight = width - margin.right;
    const chartBottom = height - margin.bottom;

    const brush = brushX()
      .extent([
        [margin.left, margin.top],
        [chartRight, chartBottom],
      ])
      .handleSize(20);
    return brush;
  }, [width, height]);

  const brushed = useCallback(
    ({sourceEvent, selection}) => {
      if (!sourceEvent) return;
      const [brushStartDate, brushEndDate] = selection.map(xScale.invert);

      ReactDOM.unstable_batchedUpdates(() => {
        setBrushSelectionEnd(formatISO(brushEndDate, {representation: 'date'}));
        setLookback(differenceInDays(brushEndDate, brushStartDate));
      });
    },
    [xScale, setBrushSelectionEnd, setLookback]
  );

  const beforebrushstarted = useCallback(
    (event) => {
      const svg = select(chartRef.current);
      const selection = brushSelection(svg.select('.brush').node());

      if (!selection) return;

      const dx = selection[1] - selection[0];
      const [[cx]] = pointers(event);
      const [x0, x1] = [cx - dx / 2, cx + dx / 2];
      const [X0, X1] = xScale.range();
      svg
        .select('.brush')
        .call(
          brush.move,
          x1 > X1 ? [X1 - dx, X1] : x0 < X0 ? [X0, X0 + dx] : [x0, x1]
        );
    },
    [brush, xScale]
  );

  const brushended = useCallback(
    ({sourceEvent, selection}) => {
      if (!sourceEvent || !selection) return;
      const domain = selection
        .map(xScale.invert)
        .map((date) => formatISO(date, {representation: 'date'}));

      const svg = select(chartRef.current);
      svg
        .select('.brush')
        .call(
          brush.move,
          domain.map((date) => xScale(parseIndiaDate(date)))
        )
        .call((g) => g.select('.overlay').attr('cursor', 'pointer'));
    },
    [brush, xScale]
  );

  useEffect(() => {
    if (!brush) return;
    brush.on('start brush', brushed).on('end', brushended);
    const svg = select(chartRef.current);
    svg
      .select('.brush')
      .call(brush)
      .call((g) =>
        g
          .select('.overlay')
          .attr('cursor', 'pointer')
          .datum({type: 'selection'})
          .on('mousedown touchstart', beforebrushstarted)
      );
  }, [brush, brushed, brushended, beforebrushstarted]);

  useEffect(() => {
    if (!brush) return;
    const svg = select(chartRef.current);
    svg.select('.brush').call(brush.move, defaultSelection);
  }, [brush, defaultSelection]);

  const handleWheel = (event) => {
    if (event.deltaX) {
      setBrushSelectionEnd(
        max([
          endDateMin,
          dates[
            Math.max(
              0,
              Math.min(
                dates.length - 1,
                dates.indexOf(currentBrushSelection[1]) +
                  Math.sign(event.deltaX) * brushWheelDelta
              )
            )
          ],
        ])
      );
    }
  };

  return (
    <div className="Timeseries">
      <div
        className={classnames('svg-parent is-brush fadeInUp')}
        ref={wrapperRef}
        onWheel={handleWheel}
        style={{animationDelay: `${animationIndex * 250}ms`}}
      >
        <svg ref={chartRef} preserveAspectRatio="xMidYMid meet">
          <defs>
            <clipPath id="clipPath">
              <rect
                x={0}
                y={`${margin.top}`}
                width={width}
                height={`${Math.max(0, height - margin.bottom)}`}
              />
            </clipPath>
            <mask id="mask">
              <rect
                x={0}
                y={`${margin.top}`}
                width={width}
                height={`${Math.max(0, height - margin.bottom)}`}
                fill="hsl(0, 0%, 40%)"
              />
              <use href="#selection" fill="white" />
            </mask>
          </defs>

          <g className="brush" clipPath="url(#clipPath)">
            <g mask="url(#mask)">
              <rect className="overlay" />
              <g className="trend-areas" />
              <rect className="selection" id="selection" />
            </g>
          </g>
          <g className="x-axis" />
        </svg>
      </div>
    </div>
  );
}
Example #21
Source File: Home.js    From covid19india-react with MIT License 4 votes vote down vote up
function Home() {
  const [regionHighlighted, setRegionHighlighted] = useState({
    stateCode: 'TT',
    districtName: null,
  });

  const [anchor, setAnchor] = useLocalStorage('anchor', null);
  const [expandTable, setExpandTable] = useLocalStorage('expandTable', false);
  const [mapStatistic, setMapStatistic] = useSessionStorage(
    'mapStatistic',
    'active'
  );
  const [mapView, setMapView] = useLocalStorage('mapView', MAP_VIEWS.DISTRICTS);

  const [date, setDate] = useState('');
  const location = useLocation();

  const {data: timeseries} = useStickySWR(
    `${DATA_API_ROOT}/timeseries.min.json`,
    fetcher,
    {
      revalidateOnMount: true,
      refreshInterval: API_REFRESH_INTERVAL,
    }
  );

  const {data} = useStickySWR(
    `${DATA_API_ROOT}/data${date ? `-${date}` : ''}.min.json`,
    fetcher,
    {
      revalidateOnMount: true,
      refreshInterval: API_REFRESH_INTERVAL,
    }
  );

  const homeRightElement = useRef();
  const isVisible = useIsVisible(homeRightElement);
  const {width} = useWindowSize();

  const hideDistrictData = date !== '' && date < DISTRICT_START_DATE;
  const hideDistrictTestData =
    date === '' ||
    date >
      formatISO(
        addDays(parseIndiaDate(DISTRICT_TEST_END_DATE), TESTED_EXPIRING_DAYS),
        {representation: 'date'}
      );

  const hideVaccinated =
    getStatistic(data?.['TT'], 'total', 'vaccinated') === 0;

  const lastDataDate = useMemo(() => {
    const updatedDates = [
      data?.['TT']?.meta?.date,
      data?.['TT']?.meta?.tested?.date,
      data?.['TT']?.meta?.vaccinated?.date,
    ].filter((date) => date);
    return updatedDates.length > 0
      ? formatISO(max(updatedDates.map((date) => parseIndiaDate(date))), {
          representation: 'date',
        })
      : null;
  }, [data]);

  const lastUpdatedDate = useMemo(() => {
    const updatedDates = Object.keys(data || {})
      .map((stateCode) => data?.[stateCode]?.meta?.['last_updated'])
      .filter((datetime) => datetime);
    return updatedDates.length > 0
      ? formatDateObjIndia(
          max(updatedDates.map((datetime) => parseIndiaDate(datetime)))
        )
      : null;
  }, [data]);

  const noDistrictDataStates = useMemo(
    () =>
      // Heuristic: All cases are in Unknown
      Object.entries(data || {}).reduce((res, [stateCode, stateData]) => {
        res[stateCode] = !!(
          stateData?.districts &&
          stateData.districts?.[UNKNOWN_DISTRICT_KEY] &&
          PRIMARY_STATISTICS.every(
            (statistic) =>
              getStatistic(stateData, 'total', statistic) ===
              getStatistic(
                stateData.districts[UNKNOWN_DISTRICT_KEY],
                'total',
                statistic
              )
          )
        );
        return res;
      }, {}),
    [data]
  );

  const noRegionHighlightedDistrictData =
    regionHighlighted?.stateCode &&
    regionHighlighted?.districtName &&
    regionHighlighted.districtName !== UNKNOWN_DISTRICT_KEY &&
    noDistrictDataStates[regionHighlighted.stateCode];

  return (
    <>
      <Helmet>
        <title>Coronavirus Outbreak in India - covid19india.org</title>
        <meta
          name="title"
          content="Coronavirus Outbreak in India: Latest Map and Case Count"
        />
      </Helmet>

      <div className="Home">
        <div className={classnames('home-left', {expanded: expandTable})}>
          <div className="header">
            <Suspense fallback={<div />}>
              <Search />
            </Suspense>

            {!data && !timeseries && <div style={{height: '60rem'}} />}

            <>
              {!timeseries && <div style={{minHeight: '61px'}} />}
              {timeseries && (
                <Suspense fallback={<div style={{minHeight: '61px'}} />}>
                  <Actions
                    {...{
                      date,
                      setDate,
                      dates: Object.keys(timeseries['TT']?.dates),
                      lastUpdatedDate,
                    }}
                  />
                </Suspense>
              )}
            </>
          </div>

          <div style={{position: 'relative', marginTop: '1rem'}}>
            {data && (
              <Suspense fallback={<div style={{height: '50rem'}} />}>
                {width >= 769 && !expandTable && (
                  <MapSwitcher {...{mapStatistic, setMapStatistic}} />
                )}
                <Level data={data['TT']} />
              </Suspense>
            )}

            <>
              {!timeseries && <div style={{height: '123px'}} />}
              {timeseries && (
                <Suspense fallback={<div style={{height: '123px'}} />}>
                  <Minigraphs
                    timeseries={timeseries['TT']?.dates}
                    {...{date}}
                  />
                </Suspense>
              )}
            </>
          </div>

          {!hideVaccinated && <VaccinationHeader data={data['TT']} />}

          {data && (
            <Suspense fallback={<TableLoader />}>
              <Table
                {...{
                  data,
                  regionHighlighted,
                  setRegionHighlighted,
                  expandTable,
                  setExpandTable,
                  hideDistrictData,
                  hideDistrictTestData,
                  hideVaccinated,
                  lastDataDate,
                  noDistrictDataStates,
                }}
              />
            </Suspense>
          )}
        </div>

        <div
          className={classnames('home-right', {expanded: expandTable})}
          ref={homeRightElement}
          style={{minHeight: '4rem'}}
        >
          {(isVisible || location.hash) && (
            <>
              {data && (
                <div
                  className={classnames('map-container', {
                    expanded: expandTable,
                    stickied:
                      anchor === 'mapexplorer' || (expandTable && width >= 769),
                  })}
                >
                  <Suspense fallback={<div style={{height: '50rem'}} />}>
                    <StateHeader data={data['TT']} stateCode={'TT'} />
                    <MapExplorer
                      {...{
                        stateCode: 'TT',
                        data,
                        mapStatistic,
                        setMapStatistic,
                        mapView,
                        setMapView,
                        regionHighlighted,
                        setRegionHighlighted,
                        anchor,
                        setAnchor,
                        expandTable,
                        lastDataDate,
                        hideDistrictData,
                        hideDistrictTestData,
                        hideVaccinated,
                        noRegionHighlightedDistrictData,
                      }}
                    />
                  </Suspense>
                </div>
              )}

              {timeseries && (
                <Suspense fallback={<div style={{height: '50rem'}} />}>
                  <TimeseriesExplorer
                    stateCode="TT"
                    {...{
                      timeseries,
                      date,
                      regionHighlighted,
                      setRegionHighlighted,
                      anchor,
                      setAnchor,
                      expandTable,
                      hideVaccinated,
                      noRegionHighlightedDistrictData,
                    }}
                  />
                </Suspense>
              )}
            </>
          )}
        </div>
      </div>

      {isVisible && (
        <Suspense fallback={<div />}>
          <Footer />
        </Suspense>
      )}
    </>
  );
}
Example #22
Source File: timeseries.js    From covid19Nepal-react with MIT License 4 votes vote down vote up
function TimeSeries({timeseriesProp, chartType, mode, logMode, isTotal}) {
  const {t} = useTranslation();
  const [lastDaysCount, setLastDaysCount] = useState(
    window.innerWidth > 512 ? Infinity : 30
  );
  const [timeseries, setTimeseries] = useState({});
  const [datapoint, setDatapoint] = useState({});
  const [index, setIndex] = useState(0);
  const [moving, setMoving] = useState(false);

  const svgRef1 = useRef();
  const svgRef2 = useRef();
  const svgRef3 = useRef();
  const svgRef4 = useRef();
  const svgRef5 = useRef();

  const wrapperRef = useRef();
  const dimensions = useResizeObserver(wrapperRef);

  const transformTimeSeries = useCallback(
    (timeseries) => {
      if (timeseries.length > 1) {
        const slicedTimeseries = sliceTimeseriesFromEnd(
          timeseries,
          lastDaysCount
        );
        setIndex(slicedTimeseries.length - 1);
        setTimeseries(slicedTimeseries);
      }
    },
    [lastDaysCount]
  );

  useEffect(() => {
    transformTimeSeries(timeseriesProp);
  }, [lastDaysCount, timeseriesProp, transformTimeSeries]);

  const graphData = useCallback(
    (timeseries) => {
      if (!dimensions) return;
      const width = dimensions.width;
      const height = dimensions.height;

      // Margins
      const margin = {top: 15, right: 35, bottom: 25, left: 25};
      const chartRight = width - margin.right;
      const chartBottom = height - margin.bottom;

      const T = timeseries.length;
      const yBufferTop = 1.2;
      const yBufferBottom = 1.1;

      setDatapoint(timeseries[T - 1]);
      setIndex(T - 1);

      const svg1 = d3.select(svgRef1.current);
      const svg2 = d3.select(svgRef2.current);
      const svg3 = d3.select(svgRef3.current);
      const svg4 = d3.select(svgRef4.current);
      const svg5 = d3.select(svgRef5.current);

      const dateMin = subDays(timeseries[0].date, 1);
      const dateMax = addDays(timeseries[T - 1].date, 1);

      const xScale = d3
        .scaleTime()
        .clamp(true)
        .domain([dateMin, dateMax])
        .range([margin.left, chartRight]);

      // Number of x-axis ticks
      const numTicksX = width < 480 ? 4 : 7;

      const xAxis = (g) =>
        g.attr('class', 'x-axis').call(d3.axisBottom(xScale).ticks(numTicksX));

      const xAxis2 = (g, yScale) => {
        g.attr('class', 'x-axis2')
          .call(d3.axisBottom(xScale).tickValues([]).tickSize(0))
          .select('.domain')
          .style('transform', `translateY(${yScale(0)}px)`);

        if (yScale(0) !== chartBottom) g.select('.domain').attr('opacity', 0.4);
        else g.select('.domain').attr('opacity', 0);
      };

      const yAxis = (g, yScale) =>
        g
          .attr('class', 'y-axis')
          .call(d3.axisRight(yScale).ticks(4, '0~s').tickPadding(5));

      // Arrays of objects
      const plotTotal = chartType === 1;
      const dataTypesTotal = [
        'totalconfirmed',
        'totalactive',
        'totalrecovered',
        'totaldeceased',
        'totaltested',
      ];
      const dataTypesDaily = [
        'dailyconfirmed',
        'dailyactive',
        'dailyrecovered',
        'dailydeceased',
        'dailytested',
      ];

      const colors = ['#ff073a', '#007bff', '#28a745', '#6c757d', '#201aa2'];

      const svgArray = [svg1, svg2, svg3, svg4, svg5];

      let yScales;
      if (plotTotal) {
        const uniformScaleMin = d3.min(timeseries, (d) =>
          Math.min(d.totalactive, d.totalrecovered, d.totaldeceased)
        );
        const uniformScaleMax = d3.max(timeseries, (d) => d.totalconfirmed);
        const yScaleUniformLinear = d3
          .scaleLinear()
          .clamp(true)
          .domain([uniformScaleMin, Math.max(1, yBufferTop * uniformScaleMax)])
          .nice()
          .range([chartBottom, margin.top]);

        const yScaleUniformLog = d3
          .scaleLog()
          .clamp(true)
          .domain([
            Math.max(1, uniformScaleMin),
            Math.max(10, yBufferTop * uniformScaleMax),
          ])
          .nice()
          .range([chartBottom, margin.top]);

        yScales = dataTypesTotal.map((type) => {
          const yScaleLinear = d3
            .scaleLinear()
            .clamp(true)
            .domain([
              d3.min(timeseries, (d) => d[type]),
              Math.max(1, yBufferTop * d3.max(timeseries, (d) => d[type])),
            ])
            .nice()
            .range([chartBottom, margin.top]);
          const yScaleLog = d3
            .scaleLog()
            .clamp(true)
            .domain([
              Math.max(
                1,
                d3.min(timeseries, (d) => d[type])
              ),
              Math.max(10, yBufferTop * d3.max(timeseries, (d) => d[type])),
            ])
            .nice()
            .range([chartBottom, margin.top]);
          if (mode && type !== 'totaltested')
            return logMode ? yScaleUniformLog : yScaleUniformLinear;
          else return logMode ? yScaleLog : yScaleLinear;
        });
      } else {
        const yScaleDailyUniform = d3
          .scaleLinear()
          .clamp(true)
          .domain([
            yBufferBottom *
              Math.min(
                0,
                d3.min(timeseries, (d) => d.dailyactive)
              ),
            Math.max(
              1,
              yBufferTop *
                d3.max(timeseries, (d) =>
                  Math.max(d.dailyconfirmed, d.dailyrecovered, d.dailydeceased)
                )
            ),
          ])
          .nice()
          .range([chartBottom, margin.top]);

        yScales = dataTypesDaily.map((type) => {
          if (mode && type !== 'dailytested') return yScaleDailyUniform;
          const yScaleLinear = d3
            .scaleLinear()
            .clamp(true)
            .domain([
              yBufferBottom *
                Math.min(
                  0,
                  d3.min(timeseries, (d) => d[type])
                ),
              Math.max(1, yBufferTop * d3.max(timeseries, (d) => d[type])),
            ])
            .nice()
            .range([chartBottom, margin.top]);
          return yScaleLinear;
        });
      }

      /* Focus dots */
      const focus = svgArray.map((svg, i) => {
        return svg
          .selectAll('.focus')
          .data([timeseries[T - 1]], (d) => d.date)
          .join((enter) =>
            enter.append('circle').attr('cx', (d) => xScale(d.date))
          )
          .attr('class', 'focus')
          .attr('fill', colors[i])
          .attr('stroke', colors[i])
          .attr('r', 4);
      });

      function mousemove() {
        const xm = d3.mouse(this)[0];
        const date = xScale.invert(xm);
        const bisectDate = d3.bisector((d) => d.date).left;
        let i = bisectDate(timeseries, date, 1);
        if (0 <= i && i < T) {
          if (date - timeseries[i - 1].date < timeseries[i].date - date) --i;
          setDatapoint(timeseries[i]);
          setIndex(i);
          setMoving(true);
          const d = timeseries[i];
          focus.forEach((f, j) => {
            const yScale = yScales[j];
            const type = plotTotal ? dataTypesTotal[j] : dataTypesDaily[j];
            if (!isNaN(d[type]))
              f.attr('cx', xScale(d.date))
                .attr('cy', yScale(d[type]))
                .attr('opacity', 1);
            else f.attr('opacity', 0);
          });
        }
      }

      function mouseout() {
        setDatapoint(timeseries[T - 1]);
        setIndex(T - 1);
        setMoving(false);
        focus.forEach((f, j) => {
          const yScale = yScales[j];
          const type = plotTotal ? dataTypesTotal[j] : dataTypesDaily[j];
          if (!isNaN(timeseries[T - 1][type]))
            f.attr('cx', xScale(timeseries[T - 1].date))
              .attr('cy', yScale(timeseries[T - 1][type]))
              .attr('opacity', 1);
          else f.attr('opacity', 0);
        });
      }

      /* Begin drawing charts */
      svgArray.forEach((svg, i) => {
        // Transition interval
        const t = svg.transition().duration(500);
        const typeTotal = dataTypesTotal[i];
        const typeDaily = dataTypesDaily[i];
        const type = plotTotal ? typeTotal : typeDaily;

        const filteredTimeseries = timeseries.filter((d) => !isNaN(d[type]));
        const color = colors[i];
        const yScale = yScales[i];

        /* X axis */
        svg
          .select('.x-axis')
          .style('transform', `translateY(${chartBottom}px)`)
          .transition(t)
          .call(xAxis);
        svg.select('.x-axis2').transition(t).call(xAxis2, yScale);
        /* Y axis */
        svg
          .select('.y-axis')
          .style('transform', `translateX(${chartRight}px)`)
          .transition(t)
          .call(yAxis, yScale);

        /* Path dots */
        svg
          .selectAll('.dot')
          .data(filteredTimeseries, (d) => d.date)
          .join((enter) =>
            enter
              .append('circle')
              .attr('cy', chartBottom)
              .attr('cx', (d) => xScale(d.date))
          )
          .attr('class', 'dot')
          .attr('fill', color)
          .attr('stroke', color)
          .attr('r', 2)
          .transition(t)
          .attr('cx', (d) => xScale(d.date))
          .attr('cy', (d) => yScale(d[type]));

        if (!isNaN(timeseries[T - 1][type]))
          focus[i]
            .transition(t)
            .attr('cx', (d) => xScale(d.date))
            .attr('cy', (d) => yScale(d[type]))
            .attr('opacity', 1);
        else focus[i].transition(t).attr('opacity', 0);

        if (plotTotal) {
          /* TOTAL TRENDS */
          svg.selectAll('.stem').remove();
          const path = svg
            .selectAll('.trend')
            .data([[...filteredTimeseries].reverse()])
            .join('path')
            .attr('class', 'trend')
            .attr('fill', 'none')
            .attr('stroke', color + '99')
            .attr('stroke-width', 4);
          // HACK
          // Path interpolation is non-trivial. Ideally, a custom path tween
          // function should be defined which takes care that old path dots
          // transition synchronously along with the path transition. This hack
          // simulates that behaviour.
          if (path.attr('d')) {
            const n = path.node().getTotalLength();
            const p = path.node().getPointAtLength(n);
            // Append points at end of path for better interpolation
            path.attr(
              'd',
              () => path.attr('d') + `L${p.x},${p.y}`.repeat(3 * T)
            );
          }
          path
            .transition(t)
            .attr('opacity', plotTotal ? 1 : 0)
            .attr(
              'd',
              d3
                .line()
                .x((d) => xScale(d.date))
                .y((d) => yScale(d[typeTotal]))
                .curve(d3.curveMonotoneX)
            );
          // Using d3-interpolate-path
          // .attrTween('d', function (d) {
          //   var previous = path.attr('d');
          //   var current = line(d);
          //   return interpolatePath(previous, current);
          // });
        } else {
          /* DAILY TRENDS */
          svg.selectAll('.trend').remove();
          svg
            .selectAll('.stem')
            .data(filteredTimeseries, (d) => d.date)
            .join((enter) =>
              enter
                .append('line')
                .attr('x1', (d) => xScale(d.date))
                .attr('y1', chartBottom)
                .attr('x2', (d) => xScale(d.date))
                .attr('y2', chartBottom)
            )
            .attr('class', 'stem')
            .style('stroke', color + '99')
            .style('stroke-width', 4)
            .transition(t)
            .attr('x1', (d) => xScale(d.date))
            .attr('y1', yScale(0))
            .attr('x2', (d) => xScale(d.date))
            .attr('y2', (d) => yScale(d[typeDaily]));
        }

        svg
          .on('mousemove', mousemove)
          .on('touchmove', mousemove)
          .on('mouseout', mouseout)
          .on('touchend', mouseout);
      });
    },
    [chartType, dimensions, logMode, mode]
  );

  useEffect(() => {
    if (timeseries.length > 1) {
      graphData(timeseries);
    }
  }, [timeseries, graphData]);

  const dateStr = datapoint.date ? format(datapoint.date, 'dd MMMM') : '';

  const chartKey1 = chartType === 1 ? 'totalconfirmed' : 'dailyconfirmed';
  const chartKey2 = chartType === 1 ? 'totalactive' : 'dailyactive';
  const chartKey3 = chartType === 1 ? 'totalrecovered' : 'dailyrecovered';
  const chartKey4 = chartType === 1 ? 'totaldeceased' : 'dailydeceased';
  const chartKey5 = chartType === 1 ? 'totaltested' : 'dailytested';

  // Function for calculate increased/decreased count for each type of data
  const currentStatusCount = (chartType) => {
    if (timeseries.length <= 0 || index <= 0 || index >= timeseries.length)
      return '';
    const currentDiff =
      timeseries[index][chartType] - timeseries[index - 1][chartType];
    const formatedDiff = formatNumber(currentDiff);
    return currentDiff >= 0 ? `+${formatedDiff}` : formatedDiff;
  };

  return (
    <React.Fragment>
      <div className="TimeSeries fadeInUp" style={{animationDelay: '2.7s'}}>
        <div className="svg-parent" ref={wrapperRef}>
          <div className="stats">
            <h5 className={`${!moving ? 'title' : ''}`}>{t('Confirmed')}</h5>
            <h5 className={`${moving ? 'title' : ''}`}>{`${dateStr}`}</h5>
            <div className="stats-bottom">
              <h2>{formatNumber(datapoint[chartKey1])}</h2>
              <h6>{currentStatusCount(chartKey1)}</h6>
            </div>
          </div>
          <svg ref={svgRef1} preserveAspectRatio="xMidYMid meet">
            <g className="x-axis" />
            <g className="x-axis2" />
            <g className="y-axis" />
          </svg>
        </div>

        <div className="svg-parent is-blue">
          <div className="stats is-blue">
            <h5 className={`${!moving ? 'title' : ''}`}>{t('Active')}</h5>
            <h5 className={`${moving ? 'title' : ''}`}>{`${dateStr}`}</h5>
            <div className="stats-bottom">
              <h2>{formatNumber(datapoint[chartKey2])}</h2>
              <h6>{currentStatusCount(chartKey2)}</h6>
            </div>
          </div>
          <svg ref={svgRef2} preserveAspectRatio="xMidYMid meet">
            <g className="x-axis" />
            <g className="x-axis2" />
            <g className="y-axis" />
          </svg>
        </div>

        <div className="svg-parent is-green">
          <div className="stats is-green">
            <h5 className={`${!moving ? 'title' : ''}`}>{t('Recovered')}</h5>
            <h5 className={`${moving ? 'title' : ''}`}>{`${dateStr}`}</h5>
            <div className="stats-bottom">
              <h2>{formatNumber(datapoint[chartKey3])}</h2>
              <h6>{currentStatusCount(chartKey3)}</h6>
            </div>
          </div>
          <svg ref={svgRef3} preserveAspectRatio="xMidYMid meet">
            <g className="x-axis" />
            <g className="x-axis2" />
            <g className="y-axis" />
          </svg>
        </div>

        <div className="svg-parent is-gray">
          <div className="stats is-gray">
            <h5 className={`${!moving ? 'title' : ''}`}>{t('Deceased')}</h5>
            <h5 className={`${moving ? 'title' : ''}`}>{`${dateStr}`}</h5>
            <div className="stats-bottom">
              <h2>{formatNumber(datapoint[chartKey4])}</h2>
              <h6>{currentStatusCount(chartKey4)}</h6>
            </div>
          </div>
          <svg ref={svgRef4} preserveAspectRatio="xMidYMid meet">
            <g className="x-axis" />
            <g className="x-axis2" />
            <g className="y-axis" />
          </svg>
        </div>

        <div className="svg-parent is-purple">
          <div className="stats is-purple">
            <h5 className={`${!moving ? 'title' : ''}`}>
              {t('Tested')} {isTotal ? testedToolTip : ''}
            </h5>
            <h5 className={`${moving ? 'title' : ''}`}>{`${dateStr}`}</h5>
            <div className="stats-bottom">
              <h2>{formatNumber(datapoint[chartKey5])}</h2>
              <h6>{currentStatusCount(chartKey5)}</h6>
            </div>
          </div>
          <svg ref={svgRef5} preserveAspectRatio="xMidYMid meet">
            <g className="x-axis" />
            <g className="x-axis2" />
            <g className="y-axis" />
          </svg>
        </div>
      </div>

      <div className="pills">
        <button
          type="button"
          onClick={() => setLastDaysCount(Infinity)}
          className={lastDaysCount === Infinity ? 'selected' : ''}
        >
          {t('Beginning')}
        </button>
        <button
          type="button"
          onClick={() => setLastDaysCount(30)}
          className={lastDaysCount === 30 ? 'selected' : ''}
          aria-label="1 month"
        >
          {`1 ${t('Month')}`}
        </button>
        <button
          type="button"
          onClick={() => setLastDaysCount(14)}
          className={lastDaysCount === 14 ? 'selected' : ''}
          aria-label="14 days"
        >
          {`2 ${t('Weeks')}`}
        </button>
      </div>

      <div className="alert">
        <Icon.AlertOctagon />
        <div className="alert-right">
          {t('Tested chart is independent of uniform scaling')}
        </div>
      </div>
    </React.Fragment>
  );
}
Example #23
Source File: TimeSlider.js    From ProjectLockdown with GNU General Public License v3.0 4 votes vote down vote up
TimeSlider = (props) => {
  const dark = toBool(props.dark);
  const [currentDateValue, setCurrentDateValue] = useState(
    firstDayDefaultOffset,
  );

  const {
    currentSelectedDay,
    setCurrentSelectedDay,
    firstDay,
    lastDay,
    days,
    playerState,
    onPlayerStateToggle
  } = props;
  const [datePickerPosition, setDatePickerPosition] = useState('left');
  const [showDatePicker, setShowDatePicker] = useState(false);
  const [currentSliderRange, setCurrentSliderRange] = useState([]);

  const currentRange = mobileRange;

  const dateRef = useRef();
  const range = useRef();
  const container = useRef();

  const toSliderString = (date, currentLanguage) => {
    let isoLanguage = 'enUS';
    if (currentLanguage) {
      isoLanguage = currentLanguage.replace('-', '');
      if (isoLanguage === 'ar') {
        isoLanguage = 'arSA';
      } else if (isoLanguage === 'zhHK') {
        isoLanguage = 'zhTW';
      }
    }
    if (
      languages[isoLanguage] === undefined ||
      languages[isoLanguage] === null
    ) {
      isoLanguage = currentLanguage.split('-')[0];
      if (
        languages[isoLanguage] === undefined ||
        languages[isoLanguage] === null
      ) {
        isoLanguage = 'enUS';
      }
    }
      return format(date, 'yyyy-MM-dd', {
      locale: languages ? languages[isoLanguage] : enUS,
    });
  };

  

  useEffect(() => {
    setCurrentSliderRange(days);
  }, [days]);
  const onSliderChange = (e) => {
    const sliderDOM = dateRef.current;
    const rangeDOM = range.current;
    const containerDOM = container.current;
    const newValue = e.target.value;
    const basicWidth = containerDOM.offsetWidth - rangeDOM.offsetWidth;
    const finalWidth = basicWidth / 2 - sliderDOM.offsetWidth / 4;
    const stepsWidth = rangeDOM.offsetWidth / currentRange;
    sliderDOM.style.left = `${finalWidth + stepsWidth * newValue}px`;
    setCurrentDateValue(newValue);
    const currentRangeDate =  new Date(currentSliderRange[0][parseInt(newValue)]);
    setCurrentSelectedDay(
      toSliderString(
        currentRangeDate,
        props.i18n.locale,
      ),
    );
    submitChanges();
  };
  const onBtnClick = (newRange) => {
    setShowDatePicker((prevState) => !prevState);
    setDatePickerPosition(newRange);
  };
  const onChooseDate = (date) => {
    props.setCurrentSelectedDay(date);
    props.onChange(date);
    props.setFirstDay(addDays(new Date(), -300));
    const sliderDOM = dateRef.current;
    const rangeDOM = range.current;
    const containerDOM = container.current;
    const basicWidth = containerDOM.offsetWidth - rangeDOM.offsetWidth;
    const finalWidth = basicWidth / 2 - sliderDOM.offsetWidth / 4;
    const stepsWidth = rangeDOM.offsetWidth / currentRange;
    sliderDOM.style.left = `${
      finalWidth +
      stepsWidth *
        ((datePickerPosition === 'left' ? 0 : currentRange - 1) + 0.5)
    }px`;
    calendarWillClose();

    if (datePickerPosition === 'left') {
      let plusDays = 1;
      days.push(date);
      for (let i = 2; i <= currentRange; i++) {
        days.push(rangePreProcces(date, plusDays));
        plusDays++;
      }
    } else {
      let lessDays = currentRange - 1;
      for (let i = 1; i < currentRange; i++) {
        days.push(rangePreProcces(date, -1 * lessDays));
        lessDays--;
      }
      days.push(date);
    }
    setCurrentSliderRange(days);
    setCurrentSelectedDay(toSliderString(date, props.i18n.locale));
    submitChanges();
    setCurrentDateValue(datePickerPosition === 'left' ? 0 : currentRange - 1);
    submitChanges();
  };

  const calendarWillClose = () => {
    setDatePickerPosition(`${datePickerPosition} hide`);
    return () => setTimeout(() => closeDatePicker(), 400);
  };
  const closeDatePicker = () => {
    setShowDatePicker(false);
    setDatePickerPosition(datePickerPosition.replace(' hide', ''));
  };

  const rangePreProcces = (date, numDays) => {
    const newDate = new Date(date);
    newDate.setDate(date.getDate() + numDays);
    return newDate;
  };

  const submitChanges = () => {
    props.onChange(
      currentSliderRange[0][parseInt(currentDateValue, 10)],
      currentSliderRange[0],
      currentSliderRange[currentSliderRange.length - 1],
    );
  };
  return (

      <div className={`sliderWrapper ${sliderWrapper} ${dark ? 'dark': ''}`}>

      <PlayButton state={playerState} toggleState={onPlayerStateToggle} />
      
        <div className={`${selectStyles} ${dark ? 'dark': ''} ${rangeStyles}`} ref={container}>
        <DatePicker
          startDate={new Date(firstDay)}
          close={calendarWillClose}
          onSelect={onChooseDate}
          show={showDatePicker}
          customClass={datePickerPosition}
        />
        <div className={`${sliderSelector} ${dark ? 'dark': ''}`} ref={dateRef}>
          <span>{currentSelectedDay?.toString()}</span>
        </div>
        <span
          title="Select Start Date"
          className={`first ${tooltipCss}`}
          onClick={(e) => onBtnClick('left')}
        >
          <IconBtn /> {toSliderString(new Date(currentSelectedDay? currentSelectedDay : null), 'en')}
        </span>
        <button
          onClick={(e) => onBtnClick('left')}
          className={`first ${popBtn}`}
        />
        <input
          ref={range}
          onInput={onSliderChange}
          type="range"
          min="0"
          max={currentRange - 1}
          step="1"
          value={currentDateValue}
        />
        <span title="Select End Date" className={`last ${tooltipCss}`}>
          {toSliderString(new Date(lastDay? lastDay : null), 'en')}
        </span>
      </div>
    </div>
  );
}
Example #24
Source File: App.js    From ProjectLockdown with GNU General Public License v3.0 4 votes vote down vote up
App = (props) => {
  
  const [environment, setEnvironment] = useState({});
  const [loading, setIsLoading] = useState(false);
  const [isDark, setIsDark] = useState('true');
  const [playerState, setPlayerState] = useState(PAUSED);
  const [days, setDays] = useState([]);
  const [selectedDate, setSelectedDate] = useState(toJsonString(addDays(new Date(), startingPoint)));
  const [startDate, setStartDate] = useState(addDays(new Date(), startingPoint));
  const [endDate, setEndDate] = useState(addDays(new Date(), startingPoint + daysRange));
  const [dialog, setDialog] = useState({
    opened: false,
    template: '',
    title: '',
    iso2: '',
    country: '',
  });
  const [isLegendVisible, setIsLegendVisible] = useState(false);
  const [isTimeSliderVisible, setIsTimeSliderVisible] = useState(false);
  const [isCountrySearchVisible, setIsCountrySearchVisible] = useState(false);
  const [isStatsBarVisible, setIsStatsBarVisible] = useState(false);
  const [isTabMenuVisible, setIsTabMenuVisible] = useState(false);
  const [isZoomVisible, setIsZoomVisible] = useState(false);
  const [mapCord , setMapCord] = useState({
      lng: coords.lng,
      lat: coords.lat,
      zoom: coords.zoom,
  })
  const [windowDimensions, setWindowDimensions] = useState(getWindowDimensions());

   const getEnvData = useCallback( async () =>{
        const data = await fetchEnvironments();
        if(data && data.environment) {
          const envt  = data.environment;
          const {components} = envt;
          setEnvironment(envt)
          setIsLegendVisible(_find(components,UIComponent.Legend).is_visible || false);
          setIsTimeSliderVisible(_find(components, UIComponent.TimeSlider).is_visible || false);
          setIsCountrySearchVisible(_find(components, UIComponent.CountriesSearcher).is_visible || false);
          setIsStatsBarVisible(_find(components,UIComponent.StatsBar).is_visible || false);
          setIsTabMenuVisible(_find(components,UIComponent.TabMenu).is_visible || false);
          setIsZoomVisible(_find(components,UIComponent.Zoom).is_visible || false);
        }
   }, []);

  const setNewDays = useCallback(
    () => {
        let date = startDate;
        const newDays = [...days];
        for (let i = 0; i <= daysRange; i++) {
          newDays.push(format(date, 'yyyy-MM-dd'));
          date = addDays(date, 1);
        }
        setDays((oldDays) => [...oldDays, newDays]);
    },
    [days,startDate],
  )


  const pausePlayerState =  useCallback(
    () => {
        const formattedSelectedDate = new Date(selectedDate);
        if (
          formattedSelectedDate.getDate() === endDate.getDate() &&
          formattedSelectedDate.getMonth() === endDate.getMonth() &&
          formattedSelectedDate.getFullYear() === endDate.getFullYear()
        ) {          
          setPlayerState(PAUSED);
          setSelectedDate(format(startDate, 'yyyy-MM-dd'))
        }
    },
    [endDate,selectedDate,startDate],
  ) 

  const toggleState = useCallback(
    (newState) => {
        setPlayerState(newState)
    },
    [],
  ) 

  const updatePlayerState = useCallback(
    () => {
        const formattedSelectedDate = new Date(selectedDate);
        let loop = null;
        if (playerState === PLAYING) {
          loop = setInterval(() => {
            if (playerState === PAUSED || formattedSelectedDate === endDate) {
              console.log('Stopped');
              clearInterval(loop);
            } else {
              setSelectedDate(format(
                addDays(formattedSelectedDate, 1),
                'yyyy-MM-dd',
              ))
            }
          }, playSpeed);
        }
    
        return () => clearInterval(loop);
    },
    [selectedDate,endDate,playerState],
  ) 

  const updateIsDark = useCallback(
    () => {
        const darkModePreference = window.localStorage.getItem('darkmode');
    
        if (!darkModePreference) {
          const isDarkTheme = !window.matchMedia('(prefers-color-scheme: dark)').matches;
          setIsDark(isDarkTheme.toString());
          document.getElementsByTagName('html')[0].classList.add('dark');
          window.localStorage.setItem('darkmode', isDarkTheme.toString());
        }
        if (darkModePreference === 'true') {
          document.getElementsByTagName('html')[0].classList.add('dark');
          setIsDark("true");
        } else if (darkModePreference === 'false') {
          setIsDark("false");
        }

    },
    [],
  ) 


  const closeDialog = useCallback(
    () => {
        setDialog(prevState => ({
          ...prevState,
          opened: false, template: '', title: '' 
          }));
    },
    [],
  ); 

  const openDialog = useCallback(
    (countryIfo) => {
        setDialog(prevState => ({
          ...prevState,
          opened: true,
          template: '',
          title: '',
          iso2: countryIfo.iso2,
          country: countryIfo.country,
        }
      ));
    },
    [],
  );

  useEffect(() =>{
    getEnvData();
   },[getEnvData]);

   useEffect(() => {
    updateIsDark();
   },[updateIsDark]);
 
  useEffect(() => {
    setNewDays();
    pausePlayerState();
    router.resetLocalStorage();
    updatePlayerState();
  
  // eslint-disable-next-line react-hooks/exhaustive-deps
  },[]);

    const _find = (arr, param) => arr.find(value => value.name === param);

    const updateEnv = async (queryString, value) =>{
      const data = await fetchEnvironments();
      if(data && data.environment){
        const componentName = _.last(queryString.split("."));
        const index = _.findIndex(data['environment']['components'] ,(component) => component.name=componentName);
        _.update(data,`environment.components[${index}]`, (obj)=> {
          obj.is_visible = toBool(value);
          switch(componentName){
            case UIComponent.Legend:
              setIsLegendVisible(toBool(value));
              break;
            case UIComponent.TimeSlider:
              setIsTimeSliderVisible(toBool(value));
              break;
            case UIComponent.CountriesSearcher:
              setIsCountrySearchVisible(toBool(value));
              break;
            case UIComponent.StatsBar:
              setIsStatsBarVisible(toBool(value));
              break;
            case UIComponent.TabMenu:
              setIsTabMenuVisible(toBool(value));
              break;
            case UIComponent.Zoom:
              setIsZoomVisible(toBool(value));
              break;
            default:
              break
          }
          return obj
       });
       const envt = data.environment;
       setEnvironment(envt);
      }
  }
  const updateMapCord = (value) =>{
    const cord = value.split("/");
    if(cord.length === 3){
      setMapCord((prevCord) => ({
        ...prevCord,
        lng: cord[0],
        lat: cord[1],
        zoom: cord[2]
      }));
    }
  }
  const openOverlay = async (value) => {
      const countryIso  = await fetchCountryISO();
      if(countryIso.length){
        const selectedCountry =await _.find(countryIso, {"Iso": value});
        if(selectedCountry){
          setDialog(prevState => ({
            ...prevState,
            opened: true,
            template: '',
            title: '',
            iso2: value,
            country: selectedCountry.name,
          }
        ));
        }
        const [ minlon, minlat, maxlon, maxlat ] = selectedCountry.cord;
        const avgLng =  (maxlon + minlon)/2;
        const avgLat = (maxlat + minlat) /2;
        setMapCord((prevCord) => ({
          ...prevCord,
          lng: avgLng,
          lat: avgLat,
          zoom: 4  //  need to be  parameterized 
        }));
        
      }
  }
    
    useEffect(() =>{
      const {search=""} = props.location;
      const params = new URLSearchParams(search);
      for (const [key, value] of params) {
        if(key === "map"){
          updateMapCord(value);
        }
        else if(key==="PLD"){
          openOverlay(value);
        }
        updateEnv(key,value);
      }
      
    },[props.location])

    const onSetSelectedDate =(date) => {
      setSelectedDate(toJsonString(new Date(date)));      
    };

  useEffect(() => {
    function handleResize() {
      setWindowDimensions(getWindowDimensions());
    }

    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  }, []);

    return (
      <div
        onKeyUp={(e) => {
          if (e.key === ' ') {
            const newState = playerState === PAUSED ? PLAYING : PAUSED;
            toggleState(newState);
          }
        }}
      >
        <AppContext.Provider value={{environment, setEnvironment}} >
        <ThemeContext.Provider value={{ isDark }}>
          <LoadingAnimation isLoading={loading} />
          <Map
            selectedDate={selectedDate}
            startDate={startDate}
            endDate={endDate}
            onOpen={openDialog}
            setIsLoading={setIsLoading}
            daysRange={daysRange}
            isCountrySearchVisible={isCountrySearchVisible}
            isZoomVisible={isZoomVisible}
            mapCord={mapCord}
            width={windowDimensions.width}
            mobileWidth={fullTimeSliderWidth}
          />
          {isTabMenuVisible && <TabMenu isDark={isDark}
                                        setDarkMode={updateIsDark}
                                        width={windowDimensions.width}
                                        mobilewidth={fullTimeSliderWidth} />}
          {isStatsBarVisible && <StatsBar width={windowDimensions.width} />}
          {isLegendVisible && <Legend width={windowDimensions.width}
                                      mobilewidth={fullTimeSliderWidth} />}
          <Watermark fontsize={watermarkSize} />
          {startDate && endDate && selectedDate && isTimeSliderVisible && (
            <TimeSlider
              playerState={playerState}
              onPlayerStateToggle={toggleState}
              dark={isDark}
              days={days}
              i18n={{ locale: 'en, en-US' }}
              onChange={(CurrentSelectedDate) => {
                setSelectedDate(CurrentSelectedDate);
              }}
              currentSelectedDay={selectedDate}
              selectedDate={selectedDate}
              sliderValue={getDaysDiff(startDate, endDate)}
              setCurrentSelectedDay={onSetSelectedDate}
              firstDay={format(new Date(startDate), 'yyyy-MM-dd')}
              setFirstDay={setStartDate}
              lastDay={format(new Date(endDate), 'yyyy-MM-dd')}
              setLastDay={setEndDate}
            />
          )}
          
          {dialog.opened ? (
                <CountryInfo
                  country={dialog.country}
                  iso2={dialog.iso2}
                  wikidata=""
                  date={selectedDate || new Date()}
                  startDate={startDate}
                  endDate={endDate}
                  daysRange={daysRange}
                  onClose={closeDialog}
                  onOpen={openDialog}
                />
              ) : (
                ''
              )}
        </ThemeContext.Provider>
        </AppContext.Provider>
      </div>
    );
}
Example #25
Source File: fake-diary-data.js    From monsuivipsy with Apache License 2.0 4 votes vote down vote up
fakeDiaryData = {
  [formatDay(startDate)]: null,
  [formatDay(addDays(startDate, 1))]: null,
  [formatDay(addDays(startDate, 2))]: null,
  [formatDay(addDays(startDate, 3))]: {
    MOOD: categoryStates.BAD,
    ANXIETY_FREQUENCE: frequence.SEVERAL_TIMES,
    ANXIETY_INTENSITY: categoryStates.MIDDLE,
    BADTHOUGHTS_FREQUENCE: frequence.MANY_TIMES,
    BADTHOUGHTS_INTENSITY: categoryStates.VERY_GOOD,
    SENSATIONS_FREQUENCE: frequence.NEVER,
    SENSATIONS_INTENSITY: categoryStates.VERY_BAD,
    SLEEP: categoryStates.VERY_GOOD,
    NOTES: "Test note",
    POSOLOGY: [
      {
        id: "Imovane (Zopiclone)",
        name1: "Imovane",
        name2: "Zopiclone",
        values: ["3.75 mg", "7.5 mg"],
        value: "3.75 mg",
      },
      {
        id: "Lamictal (Lamotrigine)",
        name1: "Lamictal",
        name2: "Lamotrigine",
        value: "25 mg",
        values: [
          "12.5 mg",
          "25 mg",
          "37.5 mg",
          "50 mg",
          "62.5mg",
          "75mg",
          "87.5mg",
          "100mg",
          "112.5 mg",
          "125 mg",
          "137.5 mg",
          "150 mg",
          "162.5 mg",
          "175 mg",
          "200 mg",
          "212.5 mg",
          "225 mg",
          "237.5 mg",
          "250 mg",
          "262.5 mg",
          "275 mg",
          "300 mg",
          "312.5 mg",
          "325 mg",
          "350 mg",
          "362.5 mg",
          "375 mg",
          "400 mg",
        ],
      },
      {
        id: "Mélatonine",
        name1: "Mélatonine",
        value: "10 mg",
        values: ["10 mg", "25 mg", "50 mg"],
      },
    ],
  },
  [formatDay(addDays(startDate, 4))]: {
    MOOD: categoryStates.GOOD,
    ANXIETY_FREQUENCE: frequence.NEVER,
    ANXIETY_INTENSITY: categoryStates.GOOD,
    BADTHOUGHTS_FREQUENCE: frequence.SEVERAL_TIMES,
    BADTHOUGHTS_INTENSITY: categoryStates.MIDDLE,
    SENSATIONS_FREQUENCE: frequence.MANY_TIMES,
    SENSATIONS_INTENSITY: categoryStates.BAD,
    SLEEP: categoryStates.VERY_BAD,
    NOTES: null,
  },
  [formatDay(addDays(startDate, 5))]: {
    MOOD: categoryStates.MIDDLE,
    ANXIETY_FREQUENCE: frequence.MANY_TIMES,
    ANXIETY_INTENSITY: categoryStates.VERY_BAD,
    BADTHOUGHTS_FREQUENCE: frequence.MANY_TIMES,
    BADTHOUGHTS_INTENSITY: categoryStates.VERY_GOOD,
    SENSATIONS_FREQUENCE: frequence.MANY_TIMES,
    SENSATIONS_INTENSITY: categoryStates.GOOD,
    SLEEP: categoryStates.MIDDLE,
    NOTES: "",
  },
  [formatDay(addDays(startDate, 6))]: {
    MOOD: categoryStates.VERY_GOOD,
    ANXIETY_FREQUENCE: frequence.MANY_TIMES,
    ANXIETY_INTENSITY: categoryStates.VERY_BAD,
    BADTHOUGHTS_FREQUENCE: frequence.MANY_TIMES,
    BADTHOUGHTS_INTENSITY: categoryStates.VERY_GOOD,
    SENSATIONS_FREQUENCE: frequence.MANY_TIMES,
    SENSATIONS_INTENSITY: categoryStates.GOOD,
    SLEEP: categoryStates.MIDDLE,
    POSOLOGY: [
      {
        id: "Imovane (Zopiclone)",
        name1: "Imovane",
        name2: "Zopiclone",
        values: ["3.75 mg", "7.5 mg"],
        value: "7.5 mg",
      },
      {
        id: "Lamictal (Lamotrigine)",
        name1: "Lamictal",
        name2: "Lamotrigine",
        value: "50 mg",
        values: [
          "12.5 mg",
          "25 mg",
          "37.5 mg",
          "50 mg",
          "62.5mg",
          "75mg",
          "87.5mg",
          "100mg",
          "112.5 mg",
          "125 mg",
          "137.5 mg",
          "150 mg",
          "162.5 mg",
          "175 mg",
          "200 mg",
          "212.5 mg",
          "225 mg",
          "237.5 mg",
          "250 mg",
          "262.5 mg",
          "275 mg",
          "300 mg",
          "312.5 mg",
          "325 mg",
          "350 mg",
          "362.5 mg",
          "375 mg",
          "400 mg",
        ],
      },
      {
        id: "Mélatonine",
        name1: "Mélatonine",
        value: "10 mg",
        values: ["10 mg", "25 mg", "50 mg"],
      },
    ],
    NOTES:
      "This is a very long note. This is a very long note. This is a very long note. This is a very long note. This is a very long note. This is a very long note. This is a very long note. ",
  },
  [formatDay(addDays(startDate, 7))]: {
    MOOD: categoryStates.BAD,
    ANXIETY_FREQUENCE: frequence.MANY_TIMES,
    ANXIETY_INTENSITY: categoryStates.VERY_BAD,
    BADTHOUGHTS_FREQUENCE: frequence.MANY_TIMES,
    BADTHOUGHTS_INTENSITY: categoryStates.VERY_GOOD,
    SENSATIONS_FREQUENCE: frequence.MANY_TIMES,
    SENSATIONS_INTENSITY: categoryStates.GOOD,
    SLEEP: categoryStates.MIDDLE,
    NOTES: "",
  },
  [formatDay(addDays(startDate, 8))]: {
    MOOD: categoryStates.GOOD,
    ANXIETY_FREQUENCE: frequence.MANY_TIMES,
    ANXIETY_INTENSITY: categoryStates.VERY_BAD,
    BADTHOUGHTS_FREQUENCE: frequence.MANY_TIMES,
    BADTHOUGHTS_INTENSITY: categoryStates.VERY_GOOD,
    SENSATIONS_FREQUENCE: frequence.MANY_TIMES,
    SENSATIONS_INTENSITY: categoryStates.GOOD,
    SLEEP: categoryStates.MIDDLE,
    NOTES: {},
  },
  [formatDay(addDays(startDate, 9))]: {
    MOOD: categoryStates.GOOD,
    ANXIETY_FREQUENCE: frequence.MANY_TIMES,
    ANXIETY_INTENSITY: categoryStates.VERY_BAD,
    BADTHOUGHTS_FREQUENCE: frequence.MANY_TIMES,
    BADTHOUGHTS_INTENSITY: categoryStates.VERY_GOOD,
    SENSATIONS_FREQUENCE: frequence.MANY_TIMES,
    SENSATIONS_INTENSITY: categoryStates.GOOD,
    SLEEP: categoryStates.MIDDLE,
    POSOLOGY: [
      {
        id: "Lamictal (Lamotrigine)",
        name1: "Lamictal",
        name2: "Lamotrigine",
        value: "300 mg",
        values: [
          "12.5 mg",
          "25 mg",
          "37.5 mg",
          "50 mg",
          "62.5mg",
          "75mg",
          "87.5mg",
          "100mg",
          "112.5 mg",
          "125 mg",
          "137.5 mg",
          "150 mg",
          "162.5 mg",
          "175 mg",
          "200 mg",
          "212.5 mg",
          "225 mg",
          "237.5 mg",
          "250 mg",
          "262.5 mg",
          "275 mg",
          "300 mg",
          "312.5 mg",
          "325 mg",
          "350 mg",
          "362.5 mg",
          "375 mg",
          "400 mg",
        ],
      },
    ],
  },
  [formatDay(addDays(startDate, 10))]: {
    MOOD: categoryStates.VERY_GOOD,
    ANXIETY_FREQUENCE: frequence.SEVERAL_TIMES,
    ANXIETY_INTENSITY: categoryStates.GOOD,
    BADTHOUGHTS_FREQUENCE: frequence.MANY_TIMES,
    BADTHOUGHTS_INTENSITY: categoryStates.VERY_GOOD,
    SENSATIONS_FREQUENCE: frequence.MANY_TIMES,
    SENSATIONS_INTENSITY: categoryStates.GOOD,
    SLEEP: categoryStates.MIDDLE,
    NOTES: { notesEvents: "ceci est une note d'event" },
  },
}