react-spring#config JavaScript Examples

The following examples show how to use react-spring#config. 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: ValuePill.js    From dashboard with MIT License 6 votes vote down vote up
export function ValuePill({ title, value = 0 }) {
  const { v } = useSpring({
    from: {
      v: 0,
    },
    to: {
      v: value,
    },
    delay: 0,
    config: config.slow,
  });

  return (
    <div className="flex items-center justify-between h-6 dark:text-gray-200 dark:bg-gray-800 rounded-lg shadow-xs">
      <span className="mx-2 text-xxs font-medium leading-none xl:text-sm">
        {title}
      </span>
      <div className="flex items-center h-full text-xs font-medium bg-primary-500 rounded-lg xl:text-base">
        <animated.span className="inline-flex items-center justify-center align-bottom px-3 py-1 text-white leading-5 rounded-md shadow-xs">
          {v.interpolate((x) => Math.round(x))}
        </animated.span>
      </div>
    </div>
  );
}
Example #2
Source File: CheckInList.js    From 1km.co.il with MIT License 6 votes vote down vote up
function CheckInList({ checkIns }) {
  const transitions = useTransition(checkIns, (item) => item?.id, {
    config: config.gentle,
    from: { opacity: 0, transform: 'translate3d(25%, 0%, 0px)' },
    enter: { opacity: 1, transform: 'translate3d(0%, 0px, 0px)' },
    leave: { opacity: 0, height: 0, transform: 'translate3d(-25%, 0px, 0px)' },
  });

  return (
    <CheckInListWrapper>
      {checkIns?.length > 0 ? (
        transitions.map(({ item, props, key }, i) => (
          <CheckIn key={key} style={i === 0 ? props : {}}>
            <UserAvatar src={item.pictureUrl === '' ? '/anonymousPofile.png' : item.pictureUrl} />
            <CheckIn.Info>
              <CheckIn.Name>
                {item.firstName} {item.lastName}
              </CheckIn.Name>
              <CheckIn.Location>ב{item.protestCityName || item.protestStreetAddress}</CheckIn.Location>
            </CheckIn.Info>
            {item.userMessage && <CheckIn.Comment>{item.userMessage}</CheckIn.Comment>}
            <CheckIn.TimeAgo>
              <TimeAgo datetime={item.createdAt} locale="he" />
            </CheckIn.TimeAgo>
          </CheckIn>
        ))
      ) : (
        <div style={{ textAlign: 'center', display: 'flex', flexDirection: 'column' }}>
          <span>טוען...</span>
          <LoadingSpinner style={{ marginTop: 15 }} />
        </div>
      )}
    </CheckInListWrapper>
  );
}
Example #3
Source File: PicutreCardList.js    From 1km.co.il with MIT License 6 votes vote down vote up
function PictureCardList({ pictures }) {
  const transitions = useTransition(pictures, (picture) => picture?.id, {
    config: config.gentle,
    from: { opacity: 0, transform: 'translate3d(25%, 0%, 0px)' },
    enter: { opacity: 1, transform: 'translate3d(0%, 0px, 0px)' },
    leave: { opacity: 0, height: 0, transform: 'translate3d(-25%, 0px, 0px)' },
  });

  return (
    <>
      {transitions.map(({ item: picture, props, key }) => (
        <Card key={key} style={props}>
          <Card.Info>
            <Link to={`/protest/${picture.protestId}`}>
              <Card.Info.Title>
                {picture.protestName}
                {picture.cityName && `, ${picture.cityName}`}
              </Card.Info.Title>
            </Link>
            {picture.uploaderName && (
              <Card.Info.Subtitle>
                <Avatar size={21} src={picture.userAvatar || 'https://1km.co.il/anonymousPofile.png'} style={{ marginLeft: 6 }} />
                {picture.uploaderName}
              </Card.Info.Subtitle>
            )}
            {picture.description && <Card.Description>{picture.description}</Card.Description>}
            <Card.Info.Timestamp>
              <TimeAgo datetime={picture.createdAt} locale="he" />
            </Card.Info.Timestamp>
          </Card.Info>
          <Card.Image src={picture.imageUrl} alt="" />
        </Card>
      ))}
    </>
  );
}
Example #4
Source File: DataTable.js    From umami with MIT License 6 votes vote down vote up
AnimatedRow = ({ label, value = 0, percent, animate, format, onClick }) => {
  const props = useSpring({
    width: percent,
    y: value,
    from: { width: 0, y: 0 },
    config: animate ? config.default : { duration: 0 },
  });

  return (
    <div className={styles.row}>
      <div className={styles.label}>{label}</div>
      <div className={styles.value} onClick={onClick}>
        <animated.div className={styles.value}>{props.y?.interpolate(format)}</animated.div>
      </div>
      <div className={styles.percent}>
        <animated.div
          className={styles.bar}
          style={{ width: props.width.interpolate(n => `${n}%`) }}
        />
        <animated.span className={styles.percentValue}>
          {props.width.interpolate(n => `${n.toFixed(0)}%`)}
        </animated.span>
      </div>
    </div>
  );
}
Example #5
Source File: InfoCard.js    From dashboard with MIT License 5 votes vote down vote up
export function InfoCard({ title, value, delta = null, small = false }) {
  const { _value, _delta } = useSpring({
    from: { _value: 0, _delta: 0 },
    to: {
      _value: value,
      _delta: delta || 0,
    },
    delay: 0,
    config: config.slow,
  });
  return (
    <Card>
      <CardBody className="flex flex-col">
        <div>
          <p
            className={clsx(
              small ? "mb-1 text-xs" : "mb-2 text-sm",
              "dark:text-gray-400 text-gray-600 font-medium"
            )}
          >
            {title}
          </p>
          <div className="flex">
            <animated.p
              className={clsx(
                small ? "text-base" : "text-lg",
                "dark:text-gray-200 text-gray-700 font-semibold"
              )}
            >
              {_value.interpolate((x) => Math.round(x))}
            </animated.p>
            {delta !== null && (
              <animated.span
                className={clsx(
                  small ? "text-xs" : "text-sm",
                  "ml-2 dark:text-gray-400 text-gray-600"
                )}
              >
                {_delta.interpolate((y) => {
                  const x = Math.round(y);
                  return x === 0 ? "-" : x > 0 ? `+${x}` : x;
                })}
              </animated.span>
            )}
          </div>
        </div>
      </CardBody>
    </Card>
  );
}
Example #6
Source File: MapSwitcher.js    From covid19india-react with MIT License 5 votes vote down vote up
MapSwitcher = ({mapStatistic, setMapStatistic}) => {
  const [mapSwitcher, {width}] = useMeasure();
  const [clicked, setClicked] = useState(false);
  const [count, setCount] = useState(0);

  const isPresent = LEVEL_STATISTICS.indexOf(mapStatistic) >= 0;

  const [spring, springApi] = useSpring(() => ({
    opacity: 0,
    background: `${STATISTIC_CONFIGS[mapStatistic].color}20`,
    transform: isPresent
      ? `translate3d(${
          (width * LEVEL_STATISTICS.indexOf(mapStatistic)) /
          LEVEL_STATISTICS.length
        }px, 0, 0)`
      : null,
    width: `calc(${100 / LEVEL_STATISTICS.length}%)`,
    config: config.gentle,
  }));

  useEffect(() => {
    if (width > 0) {
      const isPresent = LEVEL_STATISTICS.indexOf(mapStatistic) >= 0;
      ReactDOM.unstable_batchedUpdates(() => {
        springApi.start({
          transform: isPresent
            ? `translate3d(${
                (width * LEVEL_STATISTICS.indexOf(mapStatistic)) /
                LEVEL_STATISTICS.length
              }px, 0, 0)`
            : null,
          opacity: isPresent ? 1 : 0,
          background: isPresent
            ? `${STATISTIC_CONFIGS[mapStatistic]?.color}20`
            : null,
          delay: count === 0 ? 1500 : 0,
          onStart: setClicked.bind(this, true),
          onRest: setClicked.bind(this, false),
        });
      });
    }
  }, [count, mapStatistic, springApi, width]);

  const handleClick = useCallback(
    (statistic) => {
      setCount((prevCount) => prevCount + 1);
      setMapStatistic(statistic);
    },
    [setMapStatistic]
  );

  return (
    <div className="MapSwitcher" ref={mapSwitcher}>
      <animated.div className="highlight" style={spring}></animated.div>

      {LEVEL_STATISTICS.map((statistic, index) => (
        <div
          key={index}
          className={classnames('clickable', {[`is-${statistic}`]: !clicked})}
          onClick={handleClick.bind(this, statistic)}
          style={{width: `calc(${100 / LEVEL_STATISTICS.length}%)`}}
        ></div>
      ))}
    </div>
  );
}
Example #7
Source File: chat.js    From horondi_client_fe with MIT License 5 votes vote down vote up
Chat = () => {
  const [iconsVisible, setIconsVisible] = useState(false);
  const [mailFormVisible, setMailFormVisible] = useState(false);
  const [сhutButtonDisabled, setChutButtonDisabled] = useState(true);
  const style = useStyles({ iconsVisible, mailFormVisible });
  const cancelIconHandler = () => setMailFormVisible(!mailFormVisible);

  const { loading, error, data } = useQuery(getContactsForChat);
  if (loading || error) return errorOrLoadingHandler(error, loading);
  const contacts = data.getContacts.items;

  const chatButtonHendler = () => {
    setMailFormVisible(false);
    setIconsVisible(!iconsVisible);
    iconsVisible ? hideMessenger() : showMessenger(false);
  };

  return (
    <>
      <div className={style.fbChatWrapper}>
        <MessengerChat
          pageId={CHAT_FACEBOOK_DATA.pageId}
          appId={CHAT_FACEBOOK_DATA.appId}
          onClick={() => setMailFormVisible(false)}
          height={190}
          onMessengerLoad={() => {
            setChutButtonDisabled(false);
            hideMessenger();
          }}
        />
      </div>
      {iconsVisible && (
        <div className={style.iconsMessengers}>
          <div
            className={mailFormVisible ? style.msgIconActive : style.msgIcon}
            onClick={() => setMailFormVisible(!mailFormVisible)}
          >
            <MailOutlineIcon className={style.icon} />
          </div>
          <Transition
            initial={null}
            items={mailFormVisible}
            from={{ opacity: 0, height: 0 }}
            enter={{ opacity: 1, height: 0 }}
            leave={{ opacity: 0, height: 0 }}
            config={config.gentle}
          >
            {(item) =>
              item &&
              ((styles) => (
                <div style={styles}>
                  <MailForm
                    contacts={contacts}
                    cancelIconHandler={cancelIconHandler}
                    iconsVisible={iconsVisible}
                    mailFormVisible={mailFormVisible}
                  />
                </div>
              ))
            }
          </Transition>
        </div>
      )}
      <button onClick={chatButtonHendler} disabled={сhutButtonDisabled} className={style.chatIcon}>
        <ForumIcon className={style.icon} style={{ fontSize: 40 }} />
      </button>
    </>
  );
}
Example #8
Source File: RadialCard.js    From dashboard with MIT License 4 votes vote down vote up
function RadialCard({ label, count, current, previous, col = "" }) {
  const current_used = Math.round((current.used / current.total) * 100);
  const previous_used = Math.round((previous.used / previous.total) * 100);
  const diff = current_used - previous_used;

  const _p = Math.round((current.used / current.total) * 100);

  const { used, total, progress, innerProgress } = useSpring({
    from: { used: 0, total: 0, progress: "0, 100", innerProgress: 0 },
    to: {
      used: current.used,
      total: current.total,
      progress: `${Number.isNaN(_p) ? 0 : _p}, 100`,
      innerProgress: Number.isNaN(_p) ? 0 : _p,
    },
    delay: 0,
    config: config.slow,
  });

  const circlePath = `M18 2.0845 a 15.9155 15.9155 0 0 1 0 31.831 a 15.9155 15.9155 0 0 1 0 -31.831`;

  return (
    <Card className={`flex items-center justify-between ${col}`}>
      <div className="relative flex content-center justify-center m-2 w-4/5">
        <svg viewBox="0 0 36 36" className="w-4/5">
          <path
            className="text-gray-100 dark:text-gray-400 stroke-current stroke-2"
            fill="none"
            d={circlePath}
          />
          <animated.path
            className="text-primary-500 stroke-current stroke-2"
            fill="none"
            strokeDasharray={progress}
            d={circlePath}
          />
        </svg>
        <div className="absolute inline-flex flex-col items-center self-center w-3/5 text-center text-sm xl:text-lg">
          <p className="text-center dark:text-gray-400 text-gray-600 text-xxs font-medium xl:text-xs">
            {label}
          </p>
          <div className="space-x-1">
            <animated.span className="text-center dark:text-gray-200 text-gray-700 font-semibold">
              {innerProgress.interpolate((x) => `${Math.round(x)}%`)}
            </animated.span>
            {count > 0 &&
              !Number.isNaN(diff) &&
              diff !== 0 &&
              (diff > 0 ? (
                <span className="text-red-400">
                  <ChevronsUp className="inline h-full" />
                  {Math.abs(diff)}%
                </span>
              ) : (
                <span className="text-primary-400">
                  <ChevronsDown className="inline h-full" />
                  {Math.abs(diff)}%
                </span>
              ))}
          </div>
        </div>
      </div>
      <div
        style={{ direction: "rtl" }}
        className="grid grid-cols-1 mr-4 w-1/4 text-right space-y-1 xl:space-y-2"
      >
        <div className="flex-col">
          <p className="dark:text-gray-400 text-gray-600 text-xs font-medium xl:text-sm">
            Used
          </p>
          <animated.p className="dark:text-gray-200 text-gray-700 text-xs font-semibold xl:text-lg">
            {used.interpolate((x) => Math.round(x))}
          </animated.p>
        </div>
        <div className="flex-col">
          <p className="dark:text-gray-400 text-gray-600 text-xs font-medium xl:text-sm">
            Total
          </p>
          <animated.p className="dark:text-gray-200 text-gray-700 text-xs font-semibold xl:text-lg">
            {total.interpolate((x) => Math.round(x))}
          </animated.p>
        </div>
      </div>
    </Card>
  );
}
Example #9
Source File: CapacityForecast.js    From dashboard with MIT License 4 votes vote down vote up
function SingleCapacityForecast({ title, past, forecasted }) {
  const { mode } = useContext(WindmillContext);
  const { a, mx, mn, fa, fmx, fmn } = useSpring({
    from: { a: 0, mx: 0, mn: 0 },
    to: {
      a: past.avg,
      mx: past.max,
      mn: past.min,
      fa: forecasted.avg,
      fmx: forecasted.max,
      fmn: forecasted.min,
    },
    delay: 0,
    config: config.slow,
  });
  const { date } = past.data[past.data.length - 1];
  const chartData = [
    ...past.data,
    ...forecasted.data.map((d, i) => ({
      date: dateString(getNDateAfter(new Date(date), i + 1)),
      forecasted: d,
    })),
  ];

  return (
    <div className="flex flex-col">
      <p className="mb-2 dark:text-gray-400 text-gray-600 text-lg font-semibold">
        {title}
      </p>
      <div className="flex space-x-3">
        <Card className="flex w-1/4">
          <CardBody className="flex flex-col justify-between w-full">
            <p className="mb-2 dark:text-gray-400 text-gray-600 text-base font-medium">
              Trends for past {past.data.length} days
            </p>
            <div className="flex justify-between text-lg font-bold">
              <div className="flex flex-col justify-between">
                <p className="dark:text-gray-400 text-gray-600">AVG</p>
                <animated.p className="dark:text-gray-200 text-gray-700 text-2xl">
                  {a.interpolate((x) => x.toFixed(2))}
                </animated.p>
              </div>
              <div className="flex flex-col justify-between">
                <p className="dark:text-gray-400 text-gray-600">MIN</p>
                <animated.p className="dark:text-gray-200 text-gray-700 text-2xl">
                  {mn.interpolate((x) => x.toFixed(2))}
                </animated.p>
              </div>
              <div className="flex flex-col justify-between">
                <p className="dark:text-gray-400 text-gray-600">MAX</p>
                <animated.p className="dark:text-gray-200 text-gray-700 text-2xl">
                  {mx.interpolate((x) => x.toFixed(2))}
                </animated.p>
              </div>
            </div>
            <ResponsiveContainer height={50}>
              <LineChart data={past.data}>
                <Line
                  type="monotone"
                  dataKey="usage"
                  stroke="var(--color-primary-400)"
                  strokeWidth={2}
                />
              </LineChart>
            </ResponsiveContainer>
          </CardBody>
        </Card>
        <Card className="flex flex-col w-3/4">
          <CardBody>
            <p className="mb-2 dark:text-gray-400 text-gray-600 text-base font-medium">
              Forecasts for next {forecasted.data.length} days
            </p>
            <div className="flex space-x-2">
              <div className="flex w-11/12">
                <ResponsiveContainer height={175}>
                  <LineChart
                    data={chartData}
                    margin={{
                      top: 20,
                      right: 20,
                      left: -20,
                      bottom: 20,
                    }}
                  >
                    <CartesianGrid strokeDasharray="3 3" />
                    <XAxis dataKey="date" />
                    <YAxis />
                    <Tooltip
                      contentStyle={{
                        backgroundColor:
                          mode === "dark"
                            ? "var(--color-gray-800)"
                            : "var(--color-gray-100)",
                        color:
                          mode === "dark"
                            ? "var(--color-gray-100)"
                            : "var(--color-gray-800)",
                        borderRadius: "0.5rem",
                        borderStyle: "none",
                      }}
                    />
                    <Line
                      type="monotone"
                      dataKey="usage"
                      stroke="var(--color-primary-400)"
                      strokeWidth={2}
                    />
                    <Line
                      type="monotone"
                      dataKey="forecasted"
                      stroke="var(--color-primary-400)"
                      strokeWidth={2}
                      strokeDasharray="3 3"
                    />
                  </LineChart>
                </ResponsiveContainer>
              </div>
              <div className="flex flex-col self-center w-1/12 text-right">
                <div className="flex flex-col justify-between">
                  <p className="dark:text-gray-400 text-gray-600 text-base font-semibold">
                    AVG
                  </p>
                  <animated.p className="dark:text-gray-200 text-gray-700 text-lg font-semibold">
                    {fa.interpolate((x) => x.toFixed(2))}
                  </animated.p>
                </div>
                <div className="flex flex-col justify-between">
                  <p className="dark:text-gray-400 text-gray-600 text-base font-semibold">
                    MIN
                  </p>
                  <animated.p className="dark:text-gray-200 text-gray-700 text-lg font-semibold">
                    {fmn.interpolate((x) => x.toFixed(2))}
                  </animated.p>
                </div>
                <div className="flex flex-col justify-between">
                  <p className="dark:text-gray-400 text-gray-600 text-base font-semibold">
                    MAX
                  </p>
                  <animated.p className="dark:text-gray-200 text-gray-700 text-lg font-semibold">
                    {fmx.interpolate((x) => x.toFixed(2))}
                  </animated.p>
                </div>
              </div>
            </div>
          </CardBody>
        </Card>
      </div>
    </div>
  );
}
Example #10
Source File: Table.js    From covid19india-react with MIT License 4 votes vote down vote up
function Table({
  data: states,
  date: timelineDate,
  regionHighlighted,
  setRegionHighlighted,
  expandTable,
  setExpandTable,
  hideDistrictData,
  hideDistrictTestData,
  hideVaccinated,
  lastDataDate,
  noDistrictDataStates,
}) {
  const {t} = useTranslation();
  const [sortData, setSortData] = useSessionStorage('sortData', {
    sortColumn: 'confirmed',
    isAscending: false,
    delta: false,
  });
  const [page, setPage] = useState(0);
  const [delta7Mode, setDelta7Mode] = useState(false);

  const [tableContainerRef, {width: tableWidth}] = useMeasure();

  const handleSortClick = useCallback(
    (statistic) => {
      if (sortData.sortColumn !== statistic) {
        setSortData(
          produce(sortData, (draftSortData) => {
            if (
              sortData.sortColumn === 'regionName' ||
              statistic === 'regionName'
            ) {
              draftSortData.isAscending = !sortData.isAscending;
            }
            draftSortData.sortColumn = statistic;
          })
        );
      } else {
        setSortData(
          produce(sortData, (draftSortData) => {
            draftSortData.isAscending = !sortData.isAscending;
          })
        );
      }
    },
    [sortData, setSortData]
  );

  const trail = useTrail(5, {
    from: {transform: 'translate3d(0, 10px, 0)', opacity: 0},
    to: {transform: 'translate3d(0, 0px, 0)', opacity: 1},
    config: config.wobbly,
  });

  const [allDistricts, setAllDistricts] = useState();

  const [tableOption, setTableOption] = useState('States');
  const [isPerLakh, setIsPerLakh] = useState(false);
  const [isInfoVisible, setIsInfoVisible] = useState(false);

  const getTableStatistic = useCallback(
    (data, statistic, type) => {
      const statisticConfig = STATISTIC_CONFIGS[statistic];
      if (type == 'total' && statisticConfig?.onlyDelta7) {
        type = 'delta7';
      }

      if (statisticConfig?.showDelta && type === 'total' && delta7Mode) {
        type = 'delta7';
      }

      return getStatistic(data, type, statistic, {
        expiredDate: lastDataDate,
        normalizedByPopulationPer: isPerLakh ? 'lakh' : null,
      });
    },
    [isPerLakh, lastDataDate, delta7Mode]
  );

  const districts = useMemo(() => {
    if (!isPerLakh) {
      return allDistricts;
    } else {
      return Object.keys(allDistricts || {})
        .filter(
          (districtKey) =>
            getStatistic(allDistricts[districtKey], 'total', 'population') > 0
        )
        .reduce((res, districtKey) => {
          res[districtKey] = allDistricts[districtKey];
          return res;
        }, {});
    }
  }, [isPerLakh, allDistricts]);

  const numPages = Math.ceil(
    Object.keys(districts || {}).length / DISTRICT_TABLE_COUNT
  );

  const sortingFunction = useCallback(
    (regionKeyA, regionKeyB) => {
      if (sortData.sortColumn !== 'regionName') {
        const statisticConfig = STATISTIC_CONFIGS[sortData.sortColumn];
        const dataType =
          sortData.delta && statisticConfig?.showDelta ? 'delta' : 'total';

        const statisticA = getTableStatistic(
          districts?.[regionKeyA] || states[regionKeyA],
          sortData.sortColumn,
          dataType
        );
        const statisticB = getTableStatistic(
          districts?.[regionKeyB] || states[regionKeyB],
          sortData.sortColumn,
          dataType
        );
        return sortData.isAscending
          ? statisticA - statisticB
          : statisticB - statisticA;
      } else {
        const regionNameA =
          districts?.[regionKeyA]?.districtName || STATE_NAMES[regionKeyA];
        const regionNameB =
          districts?.[regionKeyB]?.districtName || STATE_NAMES[regionKeyB];
        return sortData.isAscending
          ? regionNameA.localeCompare(regionNameB)
          : regionNameB.localeCompare(regionNameA);
      }
    },
    [
      districts,
      getTableStatistic,
      sortData.delta,
      sortData.isAscending,
      sortData.sortColumn,
      states,
    ]
  );

  const _setTableOption = useCallback(() => {
    setTableOption((prevTableOption) =>
      prevTableOption === 'States' ? 'Districts' : 'States'
    );
  }, []);

  useEffect(() => {
    const workerInstance = worker();
    workerInstance.getDistricts(states);
    workerInstance.addEventListener('message', (message) => {
      if (message.data.type !== 'RPC') {
        setAllDistricts(message.data);
        workerInstance.terminate();
      }
    });
  }, [tableOption, states]);

  useEffect(() => {
    setPage((p) => Math.max(0, Math.min(p, numPages - 1)));
  }, [numPages]);

  const handlePageClick = (direction) => {
    if (Math.abs(direction) === 1) {
      setPage(Math.min(Math.max(0, page + direction), numPages - 1));
    } else if (direction < 0) {
      setPage(0);
    } else if (direction > 0) {
      setPage(numPages - 1);
    }
  };

  const transition = useTransition(isInfoVisible, {
    from: TABLE_FADE_OUT,
    enter: TABLE_FADE_IN,
    leave: TABLE_FADE_OUT,
  });

  const tableStatistics = (
    expandTable ? TABLE_STATISTICS_EXPANDED : TABLE_STATISTICS
  ).filter(
    (statistic) =>
      (tableOption === 'States' ||
        STATISTIC_CONFIGS[statistic]?.category !== 'tested' ||
        !hideDistrictTestData) &&
      (STATISTIC_CONFIGS[statistic]?.category !== 'vaccinated' ||
        !hideVaccinated)
  );

  const showDistricts = tableOption === 'Districts' && !hideDistrictData;

  useEffect(() => {
    if (!showDistricts) {
      setPage(0);
    }
  }, [showDistricts]);

  useKeyPressEvent('?', () => {
    setIsInfoVisible(!isInfoVisible);
  });

  return (
    <div className="Table">
      <div className="table-top">
        <div className="table-top-left">
          <Tooltip message={'Toggle between states/districts'} hold>
            <animated.div
              className={classnames('toggle', 'option-toggle', {
                'is-highlighted': showDistricts,
                disabled: hideDistrictData,
              })}
              onClick={_setTableOption}
              style={trail[0]}
            >
              <DistrictIcon />
            </animated.div>
          </Tooltip>

          <Tooltip message={'Per lakh people'} hold>
            <animated.div
              className={classnames('toggle', 'lakh-toggle', {
                'is-highlighted': isPerLakh,
              })}
              onClick={setIsPerLakh.bind(this, !isPerLakh)}
              style={trail[1]}
            >
              <PerLakhIcon />
            </animated.div>
          </Tooltip>

          <Tooltip message={'Last 7 day values'} hold>
            <animated.div
              className={classnames('toggle', 'delta-toggle', {
                'is-highlighted': delta7Mode,
              })}
              style={trail[2]}
              onClick={setDelta7Mode.bind(this, !delta7Mode)}
            >
              <Delta7Icon />
            </animated.div>
          </Tooltip>

          <animated.div
            className={classnames('toggle', 'info-toggle', {
              'is-highlighted': isInfoVisible,
            })}
            onClick={setIsInfoVisible.bind(this, !isInfoVisible)}
            style={trail[3]}
          >
            <QuestionIcon size={14} />
          </animated.div>
        </div>

        <Tooltip message={`${expandTable ? 'Collapse' : 'Expand'} table`} hold>
          <animated.div
            className={classnames('toggle', 'expand-table-toggle', {
              'is-highlighted': expandTable,
            })}
            style={trail[4]}
            onClick={setExpandTable.bind(this, !expandTable)}
          >
            <FoldDownIcon size={16} />
          </animated.div>
        </Tooltip>
      </div>

      {transition(
        (style, item) =>
          item && (
            <animated.div className="table-helper" {...{style}}>
              <div className="helper-top">
                <div className="helper-left">
                  <div className="info-item">
                    <div>
                      <OrganizationIcon size={14} />
                    </div>
                    <p>{t('Toggle between States/Districts')}</p>
                  </div>

                  <div className="info-item">
                    <div>
                      <PeopleIcon size={16} />
                    </div>
                    <p>{t('Per Lakh People')}</p>
                  </div>

                  <div className="info-item">
                    <div>
                      <PulseIcon size={16} />
                    </div>
                    <p>{t('Last 7 day values')}</p>
                  </div>

                  <div className="info-item sort">
                    <div>
                      <SortDescIcon size={14} />
                    </div>
                    <p>{t('Sorted by Descending')}</p>
                  </div>

                  <div className="info-item sort">
                    <div>
                      <SortAscIcon size={14} />
                    </div>
                    <p>{t('Sorted by Ascending')}</p>
                  </div>

                  <div className="info-item sort">
                    <TableDeltaHelper />
                  </div>

                  <div className="info-item notes">
                    <div>
                      <InfoIcon size={15} />
                    </div>
                    <p>{t('Notes')}</p>
                  </div>
                </div>

                <div className="helper-right">
                  <div className="info-item">
                    <p>{t('Units')}</p>
                  </div>
                  {Object.entries({'1K': 3, '1L': 5, '1Cr': 7}).map(
                    ([abbr, exp]) => (
                      <div className="info-item abbr" key={abbr}>
                        <h5>{abbr}</h5>
                        <p>
                          10
                          <sup>{exp}</sup>
                        </p>
                      </div>
                    )
                  )}
                </div>
              </div>

              <h5 className="text">
                {t('Compiled from State Govt. numbers')},{' '}
                <Link to="/about">{t('know more')}!</Link>
              </h5>
            </animated.div>
          )
      )}

      <div className="table-container" ref={tableContainerRef}>
        <div
          className="table fadeInUp"
          style={{
            gridTemplateColumns: `repeat(${tableStatistics.length + 1}, auto)`,
          }}
        >
          <div className="row heading">
            <div
              className="cell heading"
              onClick={handleSortClick.bind(this, 'regionName')}
            >
              <div>{t(!showDistricts ? 'State/UT' : 'District')}</div>
              {sortData.sortColumn === 'regionName' && (
                <div className={'sort-icon'}>
                  {sortData.isAscending ? (
                    <SortAscIcon size={12} />
                  ) : (
                    <SortDescIcon size={12} />
                  )}
                </div>
              )}
            </div>

            {tableStatistics.map((statistic) => (
              <HeaderCell
                key={statistic}
                {...{
                  statistic,
                  sortData,
                  setSortData,
                }}
                handleSort={handleSortClick.bind(this, statistic)}
              />
            ))}
          </div>

          {!showDistricts &&
            Object.keys(states)
              .filter(
                (stateCode) =>
                  stateCode !== 'TT' &&
                  !(stateCode === UNASSIGNED_STATE_CODE && isPerLakh)
              )
              .sort((a, b) => sortingFunction(a, b))
              .map((stateCode) => {
                return (
                  <Row
                    key={stateCode}
                    data={states[stateCode]}
                    noDistrictData={noDistrictDataStates[stateCode]}
                    {...{
                      stateCode,
                      regionHighlighted,
                      setRegionHighlighted,
                      expandTable,
                      tableStatistics,
                      getTableStatistic,
                      tableWidth,
                    }}
                  />
                );
              })}

          {showDistricts && !districts && <TableLoader />}

          {showDistricts &&
            districts &&
            Object.keys(districts)
              .sort((a, b) => sortingFunction(a, b))
              .slice(
                page * DISTRICT_TABLE_COUNT,
                (page + 1) * DISTRICT_TABLE_COUNT
              )
              .map((districtKey) => {
                const noDistrictData =
                  noDistrictDataStates[districts[districtKey].stateCode];
                return (
                  <Row
                    key={districtKey}
                    data={districts[districtKey]}
                    districtName={districts[districtKey].districtName}
                    {...{
                      regionHighlighted,
                      setRegionHighlighted,
                      expandTable,
                      tableStatistics,
                      getTableStatistic,
                      noDistrictData,
                    }}
                  />
                );
              })}

          <Row
            key={'TT'}
            data={states['TT']}
            stateCode={'TT'}
            {...{
              regionHighlighted,
              setRegionHighlighted,
              expandTable,
              tableStatistics,
              getTableStatistic,
            }}
          />
        </div>
      </div>
      {showDistricts && (
        <div className="paginate">
          <div
            className={classnames('left', {disabled: page === 0})}
            onClick={handlePageClick.bind(this, -2)}
          >
            <ChevronsLeft size={16} />
          </div>
          <div
            className={classnames('left', {disabled: page === 0})}
            onClick={handlePageClick.bind(this, -1)}
          >
            <ChevronLeft size={16} />
          </div>
          <h5>{`${page + 1} / ${numPages}`}</h5>
          <div
            className={classnames('right', {disabled: page === numPages - 1})}
            onClick={handlePageClick.bind(this, 1)}
          >
            <ChevronRight size={16} />
          </div>
          <div
            className={classnames('right', {disabled: page === numPages - 1})}
            onClick={handlePageClick.bind(this, 2)}
          >
            <ChevronsRight size={16} />
          </div>
        </div>
      )}
    </div>
  );
}