kleros/kleros-v2

View on GitHub
web/src/pages/Courts/StakeMaintenanceButton/PassPhaseButton.tsx

Summary

Maintainability
A
3 hrs
Test Coverage
import React, { useMemo, useState } from "react";
import styled from "styled-components";

import { usePublicClient } from "wagmi";

import { Button } from "@kleros/ui-components-library";

import {
  useReadSortitionModuleDisputesWithoutJurors,
  useReadSortitionModuleLastPhaseChange,
  useReadSortitionModuleMaxDrawingTime,
  useReadSortitionModuleMinStakingTime,
  useSimulateSortitionModulePassPhase,
  useWriteSortitionModulePassPhase,
} from "hooks/contracts/generated";
import { useSortitionModulePhase } from "hooks/useSortitionModulePhase";
import { wrapWithToast } from "utils/wrapWithToast";

import { isUndefined } from "src/utils";

import { Phases } from "components/Phase";

import { IBaseStakeMaintenanceButton } from ".";

const StyledButton = styled(Button)`
  width: 100%;
`;

type IPassPhaseButton = IBaseStakeMaintenanceButton;

const PassPhaseButton: React.FC<IPassPhaseButton> = ({ setIsOpen }) => {
  const [isSending, setIsSending] = useState(false);
  const publicClient = usePublicClient();
  const { data: phase } = useSortitionModulePhase();
  const { data: lastPhaseChange } = useReadSortitionModuleLastPhaseChange();
  const { data: minStakingTime } = useReadSortitionModuleMinStakingTime();
  const { data: maxDrawingTime } = useReadSortitionModuleMaxDrawingTime();
  const { data: disputeWithoutJurors } = useReadSortitionModuleDisputesWithoutJurors();

  const canChangePhase = useMemo(() => {
    if (
      isUndefined(phase) ||
      isUndefined(lastPhaseChange) ||
      isUndefined(minStakingTime) ||
      isUndefined(maxDrawingTime) ||
      isUndefined(disputeWithoutJurors)
    )
      return false;

    const now = Math.floor(Date.now() / 1000);
    switch (phase) {
      case Phases.staking:
        return BigInt(now) - lastPhaseChange >= minStakingTime;
      case Phases.drawing:
        return disputeWithoutJurors === 0n || BigInt(now) - lastPhaseChange >= maxDrawingTime;
      default:
        return true;
    }
  }, [phase, lastPhaseChange, minStakingTime, maxDrawingTime, disputeWithoutJurors]);

  const {
    data: passPhaseConfig,
    isLoading: isLoadingConfig,
    isError,
  } = useSimulateSortitionModulePassPhase({
    query: {
      enabled: canChangePhase,
    },
  });

  const { writeContractAsync: passPhase } = useWriteSortitionModulePassPhase();

  const isLoading = useMemo(() => isLoadingConfig || isSending, [isLoadingConfig, isSending]);
  const isDisabled = useMemo(() => isError || isLoading || !canChangePhase, [isError, isLoading, canChangePhase]);
  const handleClick = () => {
    if (!passPhaseConfig || !publicClient || !passPhase) return;

    setIsSending(true);

    wrapWithToast(async () => await passPhase(passPhaseConfig.request), publicClient).finally(() => {
      setIsSending(false);
      setIsOpen(false);
    });
  };
  return <StyledButton text="Pass Phase" small isLoading={isLoading} disabled={isDisabled} onClick={handleClick} />;
};

export default PassPhaseButton;