@headlessui/react#Tab TypeScript Examples

The following examples show how to use @headlessui/react#Tab. 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: index.tsx    From interbtc-ui with Apache License 2.0 6 votes vote down vote up
InterlayTabList = ({ className, ...rest }: InterlayTabListProps): JSX.Element => (
  <Tab.List
    className={clsx(
      'flex',
      'p-1',
      'space-x-1',
      { 'bg-interlayDenim-900': process.env.REACT_APP_RELAY_CHAIN_NAME === POLKADOT },
      'bg-opacity-20',
      { 'dark:bg-kintsugiMidnight-100': process.env.REACT_APP_RELAY_CHAIN_NAME === KUSAMA },
      { 'dark:bg-opacity-20': process.env.REACT_APP_RELAY_CHAIN_NAME === KUSAMA },
      'rounded-xl',
      className
    )}
    {...rest}
  />
)
Example #2
Source File: index.tsx    From interbtc-ui with Apache License 2.0 6 votes vote down vote up
InterlayTab = ({ className, ...rest }: InterlayTabProps): JSX.Element => (
  <Tab
    className={({ selected }) =>
      clsx(
        'w-full',
        'py-2.5',
        'text-sm',
        'leading-5',
        'font-medium',
        { 'text-interlayDenim-700': process.env.REACT_APP_RELAY_CHAIN_NAME === POLKADOT },
        { 'dark:text-kintsugiMidnight-700': process.env.REACT_APP_RELAY_CHAIN_NAME === KUSAMA },
        'rounded-lg',

        'focus:outline-none',
        'focus:ring-2',
        'ring-offset-2',
        { 'ring-offset-interlayDenim-400': process.env.REACT_APP_RELAY_CHAIN_NAME === POLKADOT },
        { 'dark:ring-offset-kintsugiMidnight': process.env.REACT_APP_RELAY_CHAIN_NAME === KUSAMA },
        'ring-white',
        'ring-opacity-60',
        selected
          ? clsx('bg-white', 'shadow')
          : clsx(
              { 'text-interlayDenim-100': process.env.REACT_APP_RELAY_CHAIN_NAME === POLKADOT },
              { 'dark:text-kintsugiTextSecondaryInDarkMode': process.env.REACT_APP_RELAY_CHAIN_NAME === KUSAMA },
              'hover:bg-white',
              'hover:bg-opacity-10',
              'hover:text-white'
            ),
        className
      )
    }
    {...rest}
  />
)
Example #3
Source File: index.tsx    From interbtc-ui with Apache License 2.0 6 votes vote down vote up
InterlayTabPanel = ({ className, ...rest }: InterlayTabPanelProps): JSX.Element => (
  <Tab.Panel
    className={clsx(
      'rounded-xl',
      'p-1.5',
      'focus:outline-none',
      'focus:ring-2',
      'ring-offset-2',
      { 'ring-offset-interlayDenim-400': process.env.REACT_APP_RELAY_CHAIN_NAME === POLKADOT },
      { 'dark:ring-offset-kintsugiMidnight': process.env.REACT_APP_RELAY_CHAIN_NAME === KUSAMA },
      'ring-white',
      'ring-opacity-60',
      className
    )}
    {...rest}
  />
)
Example #4
Source File: CardTab.tsx    From Meshtastic with GNU General Public License v3.0 6 votes vote down vote up
CardTab = ({ title }: CardTabProps): JSX.Element => {
  return (
    <Tab
      className={({ selected }) =>
        `w-1/3 truncate rounded-md px-3 py-2 text-sm font-medium hover:bg-tertiary ${
          selected ? 'bg-secondary shadow-md' : ''
        }`
      }
    >
      {title}
    </Tab>
  );
}
Example #5
Source File: InfoTab.tsx    From Meshtastic with GNU General Public License v3.0 6 votes vote down vote up
InfoTab = ({ device }: InfoTabProps): JSX.Element => {
  return (
    <Tab.Panel>
      <div className="px-4 py-5 sm:p-0">
        <dl className="sm:divide-y sm:divide-gray-200">
          <div className="py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:py-5 sm:px-6">
            <dt className="text-sm font-medium text-secondaryInv">
              BLE/WiFi Version
            </dt>
            <dd className="mt-1 flex gap-1 text-sm text-tertiaryInv sm:col-span-2 sm:mt-0">
              <span className="rounded-md bg-secondary px-0.5">
                {device.specifications.BLEVersion}
              </span>
              /
              <span className="rounded-md bg-secondary px-0.5">
                {device.specifications.WiFiVersion}
              </span>
            </dd>
          </div>
          <div className="py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:py-5 sm:px-6">
            <dt className="text-sm font-medium text-secondaryInv">
              BLE/WiFi Antenna
            </dt>
            <dd className="mt-1 flex gap-1 text-sm text-tertiaryInv sm:col-span-2 sm:mt-0">
              <span className="rounded-md bg-secondary px-0.5">
                {device.specifications.BLEAntenna}
              </span>
              /
              <span className="rounded-md bg-secondary px-0.5">
                {device.specifications.WiFiAntenna}
              </span>
            </dd>
          </div>
        </dl>
      </div>
    </Tab.Panel>
  );
}
Example #6
Source File: PinoutTab.tsx    From Meshtastic with GNU General Public License v3.0 6 votes vote down vote up
PinoutTab = ({ device }: PinoutTabProps): JSX.Element => {
  return (
    <Tab.Panel className="flex">
      <div className="m-auto flex gap-4 rounded-lg bg-slate-700 px-2 py-1 shadow-md">
        {[
          device.pinout.slice(0, device.misc.pinoutSplit),
          device.pinout.slice(device.misc.pinoutSplit, device.pinout.length),
        ].map((group, index) => (
          <div key={index}>
            {group.map((pin, pinIndex) => (
              <div
                className={`flex gap-1 ${
                  index === 0 ? 'flex-row' : 'flex-row-reverse'
                }`}
                key={pinIndex}
              >
                <div className="m-auto h-3 w-3 rounded-full border bg-yellow-500" />
                <span className="m-auto font-mono text-white">{pin.label}</span>
              </div>
            ))}
          </div>
        ))}
      </div>
    </Tab.Panel>
  );
}
Example #7
Source File: index.tsx    From interbtc-ui with Apache License 2.0 5 votes vote down vote up
InterlayTabGroup = Tab.Group
Example #8
Source File: index.tsx    From interbtc-ui with Apache License 2.0 5 votes vote down vote up
InterlayTabPanels = Tab.Panels
Example #9
Source File: PowerTab.tsx    From Meshtastic with GNU General Public License v3.0 5 votes vote down vote up
PowerTab = ({ device }: PowerTabProps): JSX.Element => {
  return <Tab.Panel className="h-32">Content 1</Tab.Panel>;
}
Example #10
Source File: liquidations.tsx    From arkadiko with GNU General Public License v3.0 4 votes vote down vote up
Liquidations: React.FC = () => {
  const { doContractCall } = useConnect();
  const stxAddress = useSTXAddress();
  const contractAddress = process.env.REACT_APP_CONTRACT_ADDRESS || '';

  const [state, setState] = useContext(AppContext);
  const [isLoading, setIsLoading] = useState(true);
  const [startLoadingRewards, setStartLoadingRewards] = useState(false);
  const [isLoadingRewards, setIsLoadingRewards] = useState(true);
  const [rewardData, setRewardData] = useState([]);
  const [stakeAmount, setStakeAmount] = useState(0);
  const [unstakeAmount, setUnstakeAmount] = useState(0);
  const [userPooled, setUserPooled] = useState(0);
  const [totalPooled, setTotalPooled] = useState(0);
  const [currentBlockHeight, setCurrentBlockHeight] = useState(0);
  const [dikoEndBlock, setDikoEndBlock] = useState(0);
  const [dikoRewardsToAdd, setDikoRewardsToAdd] = useState(0);
  const [dikoApr, setDikoApr] = useState(0);
  const [buttonUnstakeDisabled, setButtonUnstakeDisabled] = useState(true);
  const [buttonStakeDisabled, setButtonStakeDisabled] = useState(true);
  const [redeemableStx, setRedeemableStx] = useState(0);
  const [lockupBlocks, setLockupBlocks] = useState(0);
  const [stakerLockupBlocks, setStakerLockupBlocks] = useState(0);
  const [rewardLoadingPercentage, setRewardLoadingPercentage] = useState(0);

  const onInputStakeChange = (event: any) => {
    const value = event.target.value;
    setStakeAmount(value);
  };

  const onInputUnstakeChange = (event: any) => {
    const value = event.target.value;
    setUnstakeAmount(value);
  };

  const stakeMaxAmount = () => {
    setStakeAmount((state.balance['usda'] / 1000000).toString());
  };

  const unstakeMaxAmount = () => {
    setUnstakeAmount((userPooled / 1000000).toString());
  };

  const redeemStx = async () => {
    await doContractCall({
      network,
      contractAddress,
      stxAddress,
      contractName: 'arkadiko-freddie-v1-1',
      functionName: 'redeem-stx',
      functionArgs: [uintCV(state.balance['xstx'])],
      postConditionMode: 0x01,
      onFinish: data => {
        setState(prevState => ({
          ...prevState,
          currentTxId: data.txId,
          currentTxStatus: 'pending',
        }));
      },
      anchorMode: AnchorMode.Any,
    });
  };

  const stake = async () => {

    const postConditions = [
      makeStandardFungiblePostCondition(
        stxAddress || '',
        FungibleConditionCode.Equal,
        uintCV(Number((parseFloat(stakeAmount) * 1000000).toFixed(0))).value,
        createAssetInfo(contractAddress, 'usda-token', 'usda')
      ),
    ];

    await doContractCall({
      network,
      contractAddress,
      stxAddress,
      contractName: 'arkadiko-liquidation-pool-v1-1',
      functionName: 'stake',
      functionArgs: [
        uintCV(Number((parseFloat(stakeAmount) * 1000000).toFixed(0)))
      ],
      postConditions,
      onFinish: data => {
        setState(prevState => ({
          ...prevState,
          currentTxId: data.txId,
          currentTxStatus: 'pending',
        }));
      },
      anchorMode: AnchorMode.Any,
    });
  };

  const unstake = async () => {

    const postConditions = [
      makeContractFungiblePostCondition(
        contractAddress,
        'arkadiko-liquidation-pool-v1-1',
        FungibleConditionCode.Equal,
        uintCV(Number((parseFloat(unstakeAmount) * 1000000).toFixed(0))).value,
        createAssetInfo(contractAddress, 'usda-token', 'usda')
      ),
    ];

    await doContractCall({
      network,
      contractAddress,
      stxAddress,
      contractName: 'arkadiko-liquidation-pool-v1-1',
      functionName: 'unstake',
      functionArgs: [
        uintCV(Number((parseFloat(unstakeAmount) * 1000000).toFixed(0)))
      ],
      postConditions,
      onFinish: data => {
        setState(prevState => ({
          ...prevState,
          currentTxId: data.txId,
          currentTxStatus: 'pending',
        }));
      },
      anchorMode: AnchorMode.Any,
    });
  };

  const getRewardCount = async () => {

    const call = await callReadOnlyFunction({
      contractAddress,
      contractName: 'arkadiko-liquidation-rewards-v1-1',
      functionName: 'get-total-reward-ids',
      functionArgs: [],
      senderAddress: stxAddress || '',
      network: network,
    });
    const maxRewardId = cvToJSON(call).value;
    console.log("Reward IDs: ", maxRewardId);
    return parseInt(maxRewardId);
  };

  const getRewardsData = async (startId: Number, endId: Number, totalIds: number, loadedIds: number) => {
    var rewardIds = [];
    for (let rewardId = startId; rewardId <= endId; rewardId++) {
      rewardIds.push(rewardId);
    }

    const rewardsData: LiquidationRewardProps[] = [];
    await asyncForEach(rewardIds, async (rewardId: number) => {
      try {
        const callUserPending = await callReadOnlyFunction({
          contractAddress,
          contractName: 'arkadiko-liquidation-ui-v1-2',
          functionName: 'get-user-reward-info',
          functionArgs: [
            uintCV(rewardId),
          ],
          senderAddress: stxAddress || '',
          network: network,
        });
        const result = cvToJSON(callUserPending).value.value;

        if (result['pending-rewards'].value > 0){
          rewardsData.push({
            rewardIds: [rewardId],
            token: result['token'].value,
            claimable: result['pending-rewards'].value,
            tokenIsStx: result['token-is-stx'].value,
          });
        }
      } catch (e) {
        console.error(e);
      }

      loadedIds = loadedIds + 1;
      const percentage = parseInt(Math.floor((loadedIds / (totalIds * 1.01)) * 100.0));
      setRewardLoadingPercentage(percentage);
    });

    return rewardsData;
  };

  const createGroups = (rewardsData: LiquidationRewardProps[]) => {
    // Merge in groups to bulk claim
    const rewardsDataMerged: LiquidationRewardProps[] = [];
    for (const rewardData of rewardsData) {
      const result = rewardsDataMerged.filter(data => {
        return data.rewardIds.length < 50 && data.token == rewardData.token && data.tokenIsStx == rewardData.tokenIsStx;
      });
      if (result.length == 0) {
        rewardsDataMerged.push(rewardData);
      } else {
        let existingData = result[0];
        if (!existingData.rewardIds.includes(rewardData.rewardIds[0])) {
          existingData.rewardIds.push(rewardData.rewardIds[0]);
          existingData.claimable = parseInt(existingData.claimable) + parseInt(rewardData.claimable);
        }
      }
    }
    return rewardsDataMerged;
  };

  const sleep = (milliseconds) => {
    return new Promise(resolve => setTimeout(resolve, milliseconds))
  };

  async function asyncForEach(array, callback) {
    for (let index = 0; index < array.length; index++) {
      await callback(array[index], index, array);
    }
  }

  const loadRewards = async () => {
    setStartLoadingRewards(true);

    // Fetch all reward info
    const rewardCount = await getRewardCount();
    var rewards: LiquidationRewardProps[] = [];
    const batchAmount = 15;
    const batches = Math.ceil(rewardCount / batchAmount);
    for (let batch = batches-1; batch >= 0; batch--) {

      // Sleep 10 sec
      await sleep(10000);

      const startRewardId = batch * batchAmount;
      const endRewardId = Math.min((batch+1) * batchAmount - 1, rewardCount-1);
      const rewardsLoaded = (batches-1-batch) * (endRewardId - startRewardId);
      const newRewards = await getRewardsData(startRewardId, endRewardId, rewardCount, rewardsLoaded);
      rewards = rewards.concat(newRewards);

      // Group rewards
      const rewardGroups = createGroups(rewards);
      const rewardItems = rewardGroups.map((reward: object) => (
        <LiquidationReward
          key={reward.rewardIds}
          rewardIds={reward.rewardIds}
          token={reward.token}
          claimable={reward.claimable}
          tokenIsStx={reward.tokenIsStx}
        />
      ));
      setRewardData(rewardItems);
    }

    setIsLoadingRewards(false);
  };

  useEffect(() => {

    // TODO: Replace by API price
    const getDikoPrice = async () => {
      const call = await callReadOnlyFunction({
        contractAddress,
        contractName: 'arkadiko-swap-v2-1',
        functionName: 'get-pair-details',
        functionArgs: [
          contractPrincipalCV(contractAddress, 'arkadiko-token'),
          contractPrincipalCV(contractAddress, 'usda-token'),
        ],
        senderAddress: stxAddress || '',
        network: network,
      });
      const resultPairDetails = cvToJSON(call).value.value.value;
      const balanceX = resultPairDetails["balance-x"].value;
      const balanceY = resultPairDetails["balance-y"].value;
      return balanceY / balanceX;
    };

    const getTotalPooled = async () => {
      const call = await callReadOnlyFunction({
        contractAddress,
        contractName: 'usda-token',
        functionName: 'get-balance',
        functionArgs: [
          contractPrincipalCV(contractAddress, 'arkadiko-liquidation-pool-v1-1'),
        ],
        senderAddress: stxAddress || '',
        network: network,
      });
      const result = cvToJSON(call).value.value;
      return result;
    };

    const getUserPooled = async () => {
      const call = await callReadOnlyFunction({
        contractAddress,
        contractName: 'arkadiko-liquidation-pool-v1-1',
        functionName: 'get-tokens-of',
        functionArgs: [
          standardPrincipalCV(stxAddress || ''),
        ],
        senderAddress: stxAddress || '',
        network: network,
      });
      const result = cvToJSON(call).value.value;
      return result;
    };

    const getCurrentBlockHeight = async () => {
      const client = getRPCClient();
      const response = await fetch(`${client.url}/v2/info`, { credentials: 'omit' });
      const data = await response.json();
      return data['stacks_tip_height'];
    };

    const getEpochInfo = async () => {
      const call = await callReadOnlyFunction({
        contractAddress,
        contractName: 'arkadiko-liquidation-rewards-diko-v1-1',
        functionName: 'get-epoch-info',
        functionArgs: [],
        senderAddress: stxAddress || '',
        network: network,
      });
      const result = cvToJSON(call).value.value;
      return result;
    };

    const getDikoEpochRewardsToAdd = async () => {
      const call = await callReadOnlyFunction({
        contractAddress,
        contractName: 'arkadiko-liquidation-rewards-diko-v1-1',
        functionName: 'get-rewards-to-add',
        functionArgs: [],
        senderAddress: stxAddress || '',
        network: network,
      });
      const result = cvToJSON(call).value;
      return result;
    };

    const getStxRedeemable = async () => {
      const stxRedeemable = await callReadOnlyFunction({
        contractAddress,
        contractName: 'arkadiko-freddie-v1-1',
        functionName: 'get-stx-redeemable',
        functionArgs: [],
        senderAddress: stxAddress || '',
        network: network,
      });
      const result = cvToJSON(stxRedeemable).value.value;
      return result;
    };

    const getLockup = async () => {
      const stxRedeemable = await callReadOnlyFunction({
        contractAddress,
        contractName: 'arkadiko-liquidation-pool-v1-1',
        functionName: 'get-lockup-blocks',
        functionArgs: [],
        senderAddress: stxAddress || '',
        network: network,
      });
      const result = cvToJSON(stxRedeemable).value.value;
      return result;
    };

    const getStakerLockup = async () => {
      const call = await callReadOnlyFunction({
        contractAddress,
        contractName: 'arkadiko-liquidation-pool-v1-1',
        functionName: 'get-staker-lockup',
        functionArgs: [
          standardPrincipalCV(stxAddress || ''),
        ],
        senderAddress: stxAddress || '',
        network: network,
      });
      const result = cvToJSON(call).value;
      return result["start-block"].value;
    };

    const fetchInfo = async () => {
      // Fetch info
      const [
        totalPooled,
        userPooled,
        epochInfo,
        dikoEpochRewardsToAdd,
        currentBlockHeight,
        stxRedeemable,
        stakerLockup,
        lockupBlocks,
        dikoPrice,
      ] = await Promise.all([
        getTotalPooled(),
        getUserPooled(),
        getEpochInfo(),
        getDikoEpochRewardsToAdd(),
        getCurrentBlockHeight(),
        getStxRedeemable(),
        getStakerLockup(),
        getLockup(),
        getDikoPrice(),
      ]);

      setTotalPooled(totalPooled);
      setUserPooled(userPooled);
      setDikoEndBlock(epochInfo["end-block"].value);
      setDikoRewardsToAdd(dikoEpochRewardsToAdd);
      setCurrentBlockHeight(currentBlockHeight);

      setButtonStakeDisabled(false);
      setButtonUnstakeDisabled(userPooled == 0)

      if (userPooled == 0) {
        setStakerLockupBlocks(0);
      } else {
        setStakerLockupBlocks(parseInt(stakerLockup) + parseInt(lockupBlocks));
      }
      setLockupBlocks(lockupBlocks);
      setRedeemableStx(stxRedeemable);

      const dikoPerYear = (52560 / epochInfo["blocks"].value) * dikoEpochRewardsToAdd;
      setDikoApr((dikoPerYear * dikoPrice) / totalPooled * 100.0);
      setIsLoading(false);
    };

    fetchInfo();
  }, []);

  const tabs = [
    { name: 'Add', icon: <PlusCircleIcon className="w-4 h-4 mr-2" aria-hidden="true" /> },
    { name: 'Remove', icon: <MinusCircleIcon className="w-4 h-4 mr-2" aria-hidden="true"/> },
  ]

  return (
    <>
      <Helmet>
        <title>Liquidations</title>
      </Helmet>

      {state.userData ? (
        <Container>
          <main className="relative flex-1 py-12">

            {state.balance['xstx'] > 0 ? (
              <section>
                <header className="pb-5 border-b border-gray-200 dark:border-zinc-600 sm:flex sm:justify-between sm:items-end">
                  <div>
                    <h3 className="text-lg leading-6 text-gray-900 font-headings dark:text-zinc-50">Trade xSTX for STX</h3>
                  </div>
                </header>
                <div className="mt-4">
                  {isLoading ? (
                    <>
                      <Placeholder className="py-2" width={Placeholder.width.FULL} />
                      <Placeholder className="py-2" width={Placeholder.width.FULL} />
                    </>
                  ) : (
                    <div className="mt-4 shadow sm:rounded-md sm:overflow-hidden">
                      <div className="px-4 py-5 bg-white dark:bg-zinc-800 sm:p-6">
                        {(redeemableStx / 1000000) === 0 ? (
                          <>
                            <p>There are <span className="font-semibold">no redeemable STX</span> in the Arkadiko pool.</p>
                            <p className="mt-1">Be sure to check again later to redeem your xSTX for STX.</p>
                          </>
                        ) : (
                          <p>There are <span className="text-lg font-semibold">{redeemableStx / 1000000}</span> STX redeemable in the Arkadiko pool.</p>
                        )}
                        <div className="flex items-center justify-between mt-4">
                          <p>You have <span className="text-lg font-semibold">{state.balance['xstx'] / 1000000}</span> xSTX.</p>

                          <button
                            type="button"
                            onClick={() => redeemStx()}
                            disabled={(redeemableStx / 1000000) === 0}
                            className="inline-flex justify-center px-4 py-2 text-base font-medium text-white bg-indigo-600 border border-transparent rounded-md shadow-sm hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:col-start-2 sm:text-sm disabled:bg-gray-100 disabled:text-gray-500 disabled:cursor-not-allowed"
                          >
                            Redeem
                          </button>
                        </div>
                      </div>
                    </div>
                  )}
                </div>
              </section>
            ): null}

            <section>
              <header className="pt-10 pb-5 border-b border-gray-200 dark:border-zinc-600 sm:flex sm:justify-between sm:items-end">
                <div>
                  <h3 className="text-lg leading-6 text-gray-900 font-headings dark:text-zinc-50">Your rewards</h3>
                </div>
              </header>
              <div className="mt-4">
                {!startLoadingRewards ? (
                  <div className="mt-4 shadow sm:rounded-md sm:overflow-hidden">
                    <div className="px-4 py-5 bg-white dark:bg-zinc-800 sm:p-6">
                      <div className="flex items-center justify-between">
                        <p>
                          It can take a couple of minutes to check all liquidated vaults. Thanks for your patience!
                        </p>
                        <button
                          type="button"
                          onClick={() => loadRewards()}
                          className="inline-flex justify-center px-4 py-2 text-base font-medium text-white bg-indigo-600 border border-transparent rounded-md shadow-sm hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:col-start-2 sm:text-sm disabled:bg-gray-100 disabled:text-gray-500 disabled:cursor-not-allowed"
                        >
                          Load rewards
                        </button>
                      </div>
                    </div>
                  </div>
                ) : isLoadingRewards ? (
                  <div className="mt-4 shadow sm:rounded-md sm:overflow-hidden">
                    <div className="px-4 py-5 bg-white dark:bg-zinc-800 sm:p-6">
                      <div className="flex justify-between mb-3">
                        <span className="text-base font-medium dark:text-white">Checking liquidated vaults…</span>
                        <span className="text-sm font-medium text-indigo-700 dark:text-white">{rewardLoadingPercentage}%</span>
                      </div>
                        <div className="w-full bg-gray-200 rounded-full h-2.5 dark:bg-gray-700">
                          <div className="bg-indigo-600 h-2.5 rounded-full font-semibold" style={{ width: rewardLoadingPercentage + "%" }}></div>
                        </div>
                    </div>
                  </div>
                ): null}
              </div>

              <div className="mt-4">
                {rewardData.length == 0 && startLoadingRewards && !isLoadingRewards ? (
                  <EmptyState
                    Icon={CashIcon}
                    title="You have no rewards to claim."
                    description="DIKO and liquidation rewards will appear here."
                  />
                ) : rewardData.length != 0 && startLoadingRewards ? (
                  <>
                    <table className="min-w-full divide-y divide-gray-200 dark:divide-zinc-600 shadow sm:rounded-md sm:overflow-hidden">
                      <thead className="bg-gray-50 dark:bg-zinc-900 dark:bg-opacity-80">
                        <tr>
                          <th className="px-6 py-3 text-xs font-medium tracking-wider text-left text-gray-500 dark:text-zinc-400">
                            Token
                          </th>
                          <th className="px-6 py-3 text-xs font-medium tracking-wider text-center text-gray-500 dark:text-zinc-400">
                            Amount
                          </th>
                          <th className="px-6 py-3 text-xs font-medium tracking-wider text-left text-gray-500 dark:text-zinc-400"></th>
                        </tr>
                      </thead>
                      <tbody className="bg-white divide-y divide-gray-200 dark:bg-zinc-900 dark:divide-zinc-600">{rewardData}</tbody>
                    </table>
                  </>
                ): null}
              </div>
            </section>

            <section>
              <header className="pt-10 pb-5 border-b border-gray-200 dark:border-zinc-600 sm:flex sm:justify-between sm:items-end">
                <div>
                  <h3 className="text-lg leading-6 text-gray-900 font-headings dark:text-zinc-50">DIKO emissions</h3>
                </div>
              </header>
              <div className="mt-4">
                <div className="grid grid-cols-1 gap-5 mt-4 sm:grid-cols-4">
                  <div className="p-4 overflow-hidden border border-gray-300 rounded-lg shadow-sm bg-zinc-200/30 dark:bg-gray-500 dark:border-gray-700">
                    <p className="text-xs font-semibold text-gray-500 uppercase dark:text-gray-300">Current Block Height</p>
                    {isLoading ? (
                      <Placeholder className="py-2" width={Placeholder.width.FULL} color={Placeholder.color.GRAY} />
                    ) : (
                      <p className="mt-1 text-xl font-semibold text-gray-600 dark:text-gray-50">
                        #{currentBlockHeight}
                      </p>
                    )}
                  </div>

                  <div className="p-4 overflow-hidden border border-gray-300 rounded-lg shadow-sm bg-zinc-200/30 dark:bg-gray-500 dark:border-gray-700">
                    <p className="text-xs font-semibold text-gray-500 uppercase dark:text-gray-300">Next DIKO rewards at block</p>
                    {isLoading ? (
                      <Placeholder className="py-2" width={Placeholder.width.FULL} color={Placeholder.color.GRAY} />
                    ) : (
                      <p className="mt-1 text-xl font-semibold text-gray-600 dark:text-gray-50">#{dikoEndBlock}</p>
                    )}
                  </div>

                  <div className="p-4 overflow-hidden border border-indigo-200 rounded-lg shadow-sm bg-indigo-50 dark:bg-indigo-200">
                    <p className="text-xs font-semibold text-indigo-600 uppercase">Rewards to distribute</p>
                    {isLoading ? (
                      <>
                        <Placeholder className="py-2" width={Placeholder.width.THIRD} />
                        <Placeholder className="py-2" width={Placeholder.width.FULL} />
                      </>
                    ) : (
                      <>
                        <p className="mt-1 text-xl font-semibold text-indigo-800">
                          {microToReadable(dikoRewardsToAdd).toLocaleString(undefined, {
                            minimumFractionDigits: 2,
                            maximumFractionDigits: 6,
                          })} DIKO
                        </p>
                      </>
                    )}
                  </div>

                  <div className="p-4 overflow-hidden border border-indigo-200 rounded-lg shadow-sm bg-indigo-50 dark:bg-indigo-200">
                    <p className="text-xs font-semibold text-indigo-600 uppercase">APR</p>
                    {isLoading ? (
                      <>
                        <Placeholder className="py-2" width={Placeholder.width.THIRD} />
                        <Placeholder className="py-2" width={Placeholder.width.FULL} />
                      </>
                    ) : (
                      <>
                        <p className="mt-1 text-xl font-semibold text-indigo-800">
                          {dikoApr.toLocaleString(undefined, {
                            minimumFractionDigits: 2,
                            maximumFractionDigits: 2,
                          })}%
                        </p>
                      </>
                    )}
                  </div>
                </div>
              </div>
            </section>

            <section>
              <header className="pt-10 pb-5 border-b border-gray-200 dark:border-zinc-600 sm:flex sm:justify-between sm:items-end">
                <div>
                  <h3 className="text-lg leading-6 text-gray-900 font-headings dark:text-zinc-50">USDA pool</h3>
                </div>
              </header>
              <div className="mt-4">
                <div className="grid grid-cols-1 gap-4 sm:grid-cols-3">
                  <div className="w-full p-4 border border-indigo-200 rounded-lg shadow-sm bg-indigo-50 dark:bg-indigo-200">
                    <h4 className="text-xs text-indigo-700 uppercase font-headings">Pool info</h4>
                    <dl className="mt-2 space-y-1">
                      <div className="sm:grid sm:grid-cols-2 sm:gap-4">
                        <dt className="inline-flex items-center text-sm font-medium text-indigo-500 dark:text-indigo-700">
                          Total tokens in pool
                          <div className="ml-2">
                            <Tooltip
                              className="z-10"
                              shouldWrapChildren={true}
                              label={`Amount of USDA that is currently in the pool, ready to be used for liquidations.`}
                            >
                              <InformationCircleIcon
                                className="block w-4 h-4 text-indigo-400 dark:text-indigo-500"
                                aria-hidden="true"
                              />
                            </Tooltip>
                          </div>
                        </dt>
                        <dt className="mt-1 text-sm font-semibold text-indigo-900 sm:mt-0 sm:text-right">
                          {isLoading ? (
                            <Placeholder className="py-2" width={Placeholder.width.FULL} />
                          ) : (
                            <>
                              {microToReadable(totalPooled).toLocaleString(undefined, {
                                minimumFractionDigits: 2,
                                maximumFractionDigits: 6,
                              })} USDA
                            </>
                          )}
                        </dt>
                      </div>

                      <div className="sm:grid sm:grid-cols-2 sm:gap-4">
                        <dt className="inline-flex items-center text-sm font-medium text-indigo-500 dark:text-indigo-700">
                          Lockup duration
                          <div className="ml-2">
                            <Tooltip
                              className="z-10"
                              shouldWrapChildren={true}
                              label={`Deposited USDA will be locked.`}
                            >
                              <InformationCircleIcon
                                className="block w-4 h-4 text-indigo-400 dark:text-indigo-500"
                                aria-hidden="true"
                              />
                            </Tooltip>
                          </div>
                        </dt>
                        <dt className="mt-1 text-sm font-semibold text-indigo-900 sm:mt-0 sm:text-right">
                          {isLoading ? (
                            <Placeholder className="py-2" width={Placeholder.width.FULL} />
                          ) : (
                            <>
                              {lockupBlocks} blocks
                            </>
                          )}
                        </dt>
                      </div>

                      <div className="sm:grid sm:grid-cols-2 sm:gap-4">
                        <dt className="inline-flex items-center text-sm font-medium text-indigo-500 dark:text-indigo-700">
                          Your tokens in pool
                          <div className="ml-2">
                            <Tooltip
                              className="z-10"
                              shouldWrapChildren={true}
                              label={`The amount of USDA you still have in the pool. Will decrease if USDA is used in liquidations`}
                            >
                              <InformationCircleIcon
                                className="block w-4 h-4 text-indigo-400 dark:text-indigo-500"
                                aria-hidden="true"
                              />
                            </Tooltip>
                          </div>
                        </dt>
                        <dt className="mt-1 text-sm font-semibold text-indigo-900 sm:mt-0 sm:text-right">
                          {isLoading ? (
                            <Placeholder className="py-2" width={Placeholder.width.FULL} />
                          ) : (
                            <>
                              {microToReadable(userPooled).toLocaleString(undefined, {
                                minimumFractionDigits: 2,
                                maximumFractionDigits: 6,
                              })} USDA
                            </>
                          )}
                        </dt>
                      </div>

                      <div className="sm:grid sm:grid-cols-2 sm:gap-4">
                        <dt className="inline-flex items-center text-sm font-medium text-indigo-500 dark:text-indigo-700">
                          Unlocking at
                          <div className="ml-2">
                            <Tooltip
                              className="z-10"
                              shouldWrapChildren={true}
                              label={`Your deposited USDA will unlock at this block.`}
                            >
                              <InformationCircleIcon
                                className="block w-4 h-4 text-indigo-400 dark:text-indigo-500"
                                aria-hidden="true"
                              />
                            </Tooltip>
                          </div>
                        </dt>
                        <dt className="mt-1 text-sm font-semibold text-indigo-900 sm:mt-0 sm:text-right">
                          {isLoading ? (
                            <Placeholder className="py-2" width={Placeholder.width.FULL} />
                          ) : (
                            <>
                              Block {stakerLockupBlocks}
                            </>
                          )}
                        </dt>
                      </div>
                    </dl>
                  </div>

                  <div className="sm:col-span-2">
                    <div className="relative bg-white rounded-lg shadow dark:bg-zinc-900">
                      <div className="flex flex-col p-4">
                        <Tab.Group>
                          <Tab.List className="group p-0.5 rounded-lg flex w-full bg-gray-50 hover:bg-gray-100 dark:bg-zinc-300 dark:hover:bg-zinc-200">
                            {tabs.map((tab, tabIdx) => (
                              <Tab as={Fragment} key={tabIdx}>
                                {({ selected }) => (
                                  <button className={
                                    classNames(
                                      `p-1.5 lg:pl-2.5 lg:pr-3.5 rounded-md flex items-center justify-center flex-1 focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2 focus:outline-none focus-visible:ring-offset-gray-100 ${tabIdx === 1 ? 'ml-0.5': ''}`,
                                      selected
                                      ? 'text-sm text-gray-600 font-medium bg-white ring-1 ring-black ring-opacity-5'
                                      : ''
                                    )}
                                  >
                                    <span className="inline-flex items-center text-sm font-medium rounded-md">
                                      <span className={
                                          selected
                                            ? 'text-indigo-500'
                                            : 'text-gray-500 group-hover:text-gray-900 dark:group-hover:text-zinc-900'
                                        }
                                      >
                                        {tab.icon}
                                      </span>
                                      <span className="text-gray-900">{tab.name}</span>
                                    </span>
                                  </button>
                                )}
                              </Tab>
                            ))}
                          </Tab.List>
                          <Tab.Panels className="mt-4">
                            <Tab.Panel>
                              {isLoading ? (
                                <Placeholder className="py-2" width={Placeholder.width.FULL} />
                              ) : (
                                <>
                                  <InputAmount
                                    balance={microToReadable(state.balance['usda']).toLocaleString(undefined, {
                                      minimumFractionDigits: 2,
                                      maximumFractionDigits: 6,
                                    })}
                                    token='USDA'
                                    inputValue={stakeAmount}
                                    onInputChange={onInputStakeChange}
                                    onClickMax={stakeMaxAmount}
                                  />
                                  <button
                                    type="button"
                                    className="inline-flex justify-center px-4 py-2 mb-4 text-base font-medium text-white bg-indigo-600 border border-transparent rounded-md shadow-sm hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:col-start-2 sm:text-sm disabled:bg-gray-100 disabled:text-gray-500 disabled:cursor-not-allowed"
                                    disabled={buttonStakeDisabled}
                                    onClick={stake}
                                  >
                                    Add USDA to pool
                                  </button>
                                </>
                              )}
                            </Tab.Panel>

                            <Tab.Panel>
                              {isLoading ? (
                                <Placeholder className="py-2" width={Placeholder.width.FULL} />
                              ) : currentBlockHeight < stakerLockupBlocks ? (
                                <div className="">
                                  <Alert type={Alert.type.WARNING} title="Locked">
                                    <p>
                                      Your USDA is locked until block #{stakerLockupBlocks}
                                    </p>
                                  </Alert>
                                </div>
                              ) : (
                                <>
                                  <InputAmount
                                    balance={microToReadable(userPooled).toLocaleString(undefined, {
                                      minimumFractionDigits: 2,
                                      maximumFractionDigits: 6,
                                    })}
                                    token='USDA'
                                    inputValue={unstakeAmount}
                                    onInputChange={onInputUnstakeChange}
                                    onClickMax={unstakeMaxAmount}
                                  />
                                  <button
                                    type="button"
                                    className="inline-flex justify-center px-4 py-2 mb-4 text-base font-medium text-white bg-indigo-600 border border-transparent rounded-md shadow-sm hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:col-start-2 sm:text-sm disabled:bg-gray-100 disabled:text-gray-500 disabled:cursor-not-allowed"
                                    disabled={buttonUnstakeDisabled}
                                    onClick={unstake}
                                  >
                                    Remove USDA from pool
                                  </button>
                                </>
                              )}
                            </Tab.Panel>
                          </Tab.Panels>
                        </Tab.Group>
                      </div>
                    </div>
                  </div>
                </div>
              </div>
            </section>
          </main>
        </Container>
      ) : (
        <Redirect to={{ pathname: '/' }} />
      )}
    </>
  );
}
Example #11
Source File: Festival.tsx    From platform with MIT License 4 votes vote down vote up
export default function Festival() {
  const { id } = useParams();
  const event = rounds.find(({ type }) => type === "festival");
  const [isLoading, setIsLoading] = useState(false);
  const [eventEntries, setEventEntries] = useState({});
  const [entriesCount, setEntriesCount] = useState(0);

  useEffect(() => {
    document.title = "The Chess Centre | Festival";

    const fetchEvent = async () => {
      setIsLoading(true);
      const response = await API.graphql({
        query: getEvent,
        variables: { id },
        authMode: "AWS_IAM",
      }).catch((error) => {
        console.log("Error fetching event.", id);
        console.log(error.response);
      });
      if (response && response.data) {
        const {
          data: { getEvent: entries },
        } = response;
        setEventEntries(entries);
        if (entries?.entries?.items) {
          setEntriesCount(entries?.entries?.items.length);
        }
      }
      setIsLoading(false);
    };
    fetchEvent();
  }, [id]);

  return (
    <div className="relative bg-white">
      <div className=" bg-gray-50 pt-6 pb-6 sm:pb-6 md:pb-6 lg:pb-6 xl:pb-6">
        <LandingNav />
      </div>
      <div className="mx-auto py-10 px-4 sm:px-6 lg:max-w-7xl lg:px-8">
        <div className="lg:grid lg:grid-rows-1 lg:grid-cols-7 lg:gap-x-8 lg:gap-y-10 xl:gap-x-16">
          <div className="lg:row-end-1 lg:col-span-4">
            <div className="aspect-w-4 aspect-h-3 rounded-lg bg-gray-100 overflow-hidden">
              <img
                src={FestivalHero}
                alt="hero"
                className="object-center object-cover"
              />
            </div>
          </div>

          <div className="max-w-2xl text-center sm:text-left mx-auto mt-4 sm:mt-16 lg:max-w-none lg:mt-0 lg:row-end-2 lg:row-span-2 lg:col-span-3">
            {/* TITLE */}
            <div className="flex flex-col-reverse">
              <div className="mt-4">
                <h1 className="text-3xl font-extrabold tracking-tight  text-teal-brand sm:text-5xl">
                  <span className="text-orange-brand">Ilkley</span> Chess
                  Festival
                </h1>
                <p className="text-md text-blue-brand mt-2">
                  <time dateTime={festival.datetime}>{festival.date}</time>
                </p>
              </div>
            </div>

            {/* PRIZES */}
            <div className="border-t border-gray-200 mt-6 pt-6 mb-4">
              <h3 className="text-lg font-medium text-gray-900">
                Prizes{" "}
                <span className="text-sm text-gray-500">for all sections</span>
              </h3>
              <div className="mt-4 sm:mx-0">
                <Prizes />
              </div>
            </div>

            {/* ENTRY FORM */}
            <div className="hidden sm:block">
              <EntryForm id={id} />
            </div>

            {/* LOCATION */}
            <div className="border-t border-gray-200 mt-10 pt-10">
              <div className="grid grid-cols-1 sm:grid-cols-2">
                <div className="order-2 sm:order-1">
                  <h3 className="text-lg font-medium text-gray-900">
                    Location
                  </h3>
                  <p className="mt-4 text-sm text-gray-500">
                    King&#39;s Hall &#38; Winter Garden
                  </p>
                  <p className="mt-2 text-sm text-gray-500">Station Road</p>
                  <p className="mt-2 mb-10 text-sm text-gray-500">
                    Ilkley, LS29 8HB
                  </p>
                </div>
                <div className="order-1 sm:order-2">
                  <img
                    className="w-6/7 -mt-6"
                    alt="festival building"
                    src={FestivalBuilding}
                  />
                </div>
              </div>

              <FestivalMap />
            </div>
          </div>

          {/* MORE DETAILS */}
          <div className="w-full max-w-2xl mx-auto sm:mt-16 mt-6 lg:max-w-none lg:mt-0 lg:col-span-4">
            <Tab.Group as="div">
              <div className="border-b border-gray-200">
                <Tab.List className="-mb-px flex space-x-8">
                  <Tab
                    className={({ selected }) =>
                      classNames(
                        selected
                          ? "border-teal-600 text-teal-600"
                          : "border-transparent text-gray-700 hover:text-gray-800 hover:border-gray-300",
                        "whitespace-nowrap py-6 border-b-2 font-medium text-sm focus:ring-transparent"
                      )
                    }
                  >
                    Details
                  </Tab>
                  <Tab
                    className={({ selected }) =>
                      classNames(
                        selected
                          ? "border-teal-600 text-teal-600"
                          : "border-transparent text-gray-700 hover:text-gray-800 hover:border-gray-300",
                        "whitespace-nowrap py-6 border-b-2 font-medium text-sm focus:ring-transparent"
                      )
                    }
                  >
                    Schedule
                  </Tab>
                  <Tab
                    className={({ selected }) =>
                      classNames(
                        selected
                          ? "border-teal-600 text-teal-600"
                          : "border-transparent text-gray-700 hover:text-gray-800 hover:border-gray-300",
                        "whitespace-nowrap py-6 border-b-2 font-medium text-sm focus:ring-transparent"
                      )
                    }
                  >
                    Entries
                  </Tab>
                  <Tab
                    className={({ selected }) =>
                      classNames(
                        selected
                          ? "border-teal-600 text-teal-600"
                          : "border-transparent text-gray-700 hover:text-gray-800 hover:border-gray-300",
                        "whitespace-nowrap py-6 border-b-2 font-medium text-sm focus:ring-transparent"
                      )
                    }
                  >
                    FAQs
                  </Tab>
                </Tab.List>
              </div>
              <Tab.Panels as={Fragment}>
                <Tab.Panel className="-mb-10 py-5 focus:ring-transparent">
                  <div className="relative">
                    <div className="prose prose-blue text-gray-500 mx-auto lg:max-w-none text-justify">
                      <h2>Sections</h2>
                      <ul className="font-medium text-teal-brand">
                        <li>Open</li>
                        <li>
                          Major{" "}
                          <span className="text-xs text-gray-500">
                            (2000 ECF and below)
                          </span>
                        </li>
                        <li>
                          Intermediate{" "}
                          <span className="text-xs text-gray-500">
                            (1750 ECF and below)
                          </span>
                        </li>
                        <li>
                          Minor{" "}
                          <span className="text-xs text-gray-500">
                            (1500 ECF and below)
                          </span>
                        </li>
                      </ul>
                      <p className="text-sm">
                        Unrated players will not be eligible for section
                        specific grading prizes.
                      </p>
                    </div>
                    <div className="rounded-md bg-yellow-50 p-4 my-4 hidden sm:block">
                      <div className="flex">
                        <div className="flex-shrink-0">
                          <ExclamationIcon
                            className="h-5 w-5 text-yellow-400"
                            aria-hidden="true"
                          />
                        </div>
                        <div className="ml-3">
                          <h3 className="text-sm font-medium text-yellow-800">
                            ECF Membership Required
                          </h3>
                          <div className="mt-2 text-sm text-yellow-700">
                            <p>
                              All entries <span className="italic">should</span>{" "}
                              have an ECF membership, create yours here:{" "}
                              <a
                                target="_blank"
                                rel="noreferrer"
                                href={`https://www.englishchess.org.uk/ecf-membership-rates-and-joining-details/`}
                                className="font-medium underline text-yellow-700 hover:text-yellow-600"
                              >
                                ECF Membership
                              </a>
                            </p>
                          </div>
                        </div>
                      </div>
                    </div>
                    <div className="prose prose-blue text-gray-500 mx-auto lg:max-w-none text-justify mt-4">
                      <h2>Event Structure</h2>
                      <ul className="font-medium text-teal-brand">
                        <li>
                          Rounds: <span className="text-blue-brand">5</span>{" "}
                          <span className="text-gray-600 text-sm font-normal">
                            see schedule
                          </span>
                        </li>
                        <li>
                          Time Control:{" "}
                          <span className="text-blue-brand text-md">
                            90{" "}
                            <span className="text-sm text-gray-600 font-normal">
                              mins per player
                            </span>{" "}
                            + 10{" "}
                            <span className="text-sm text-gray-600 font-normal">
                              second increment
                            </span>
                          </span>
                        </li>
                        <li>
                          Entry fee:{" "}
                          <span className="text-blue-brand">£30</span>
                        </li>
                      </ul>
                      <p className="text-sm">
                        Standard ECF rules apply. All games will be submited to
                        the ECF for offical rating calculation.
                      </p>
                    </div>
                  </div>
                </Tab.Panel>

                <Tab.Panel
                  as="dl"
                  className="text-gray-500 py-5 focus:ring-transparent"
                >
                  <div className="prose prose-blue mb-4">
                    <h2>Schedule</h2>
                  </div>
                  <Schedule event={event} />
                </Tab.Panel>

                <Tab.Panel
                  as="dl"
                  className="text-sm text-gray-500 py-5 focus:ring-transparent"
                >
                  <div className="prose prose-blue text-gray-500 mx-auto lg:max-w-none text-justify">
                    <h2>
                      Entries{" "}
                      <span className="text-gray-500 font-medium text-sm">
                        ( {entriesCount} )
                      </span>
                    </h2>

                    {!isLoading && eventEntries && (
                      <EntriesTable eventDetails={eventEntries} />
                    )}

                    {isLoading && (
                      <div className="text-gray-300 italic text-center">
                        <i className="fas fa-spinner-third fa-spin fa-fw text-teal-500"></i>{" "}
                        fetching entry details ...
                      </div>
                    )}
                  </div>
                </Tab.Panel>
                <Tab.Panel
                  as="dl"
                  className="text-sm text-gray-500 py-5 focus:ring-transparent"
                >
                  <div className="prose prose-teal text-gray-500 mx-auto lg:max-w-none text-justify">
                    <h2>FAQs</h2>
                    <ul>
                      <li>
                        <span className="font-bold text-teal-600">
                          Missing my ECF rating
                        </span>
                        <p>
                          We automatically search and check ECF rating data upon
                          account registration. If we are unable to accurately
                          determine your ECF rating (if you have one) we will
                          contact you. Otherwise, leave it with us, your rating
                          will appear within a few hours of any event entry!
                        </p>
                      </li>
                      <li>
                        <span className="font-bold text-teal-600">
                          Withdraw entry
                        </span>
                        <p>
                          If you are unable to make this event, please{" "}
                          <a
                            className="text-teal-600 hover:underline"
                            href="mailto:[email protected]?subject=Withdraw%20Festival%20Entry"
                          >
                            contact us
                          </a>{" "}
                          as soon as possible so we can process any refund.
                          Unfortunately, those who withdraw on the day or fail
                          to attend will not be eligible for refunds as we offer
                          your place to other players.
                        </p>
                      </li>
                      <li>
                        <span className="font-bold text-teal-600">
                          Rating list
                        </span>
                        <p>
                          We will use the latest ECF ratings published on the{" "}
                          <span className="font-bold">1st September 2022</span>{" "}
                          for this event, this may mean entries have to switch
                          sections if their rating jumps beyond the specified
                          rating cap. We will contact all players where this
                          occurs but will automatically move players up to the
                          next eligible section.
                        </p>
                      </li>
                      <li>
                        <span className="font-bold text-teal-600">
                          Anti-Cheating{" "}
                          <span className="text-red-600 font-medium text-sm">
                            (TBC)
                          </span>
                        </span>
                        <p>
                          We are working with an official FIDE registered
                          tournament arbiter to provide clear guidance for
                          electronic devices.
                        </p>
                        <p>
                          <span className="font-bold">ECF</span>{" "}
                          <a href="https://www.englishchess.org.uk/wp-content/uploads/2019/12/Anti-Cheating-Document.pdf">
                            anti-cheating policy
                          </a>
                        </p>
                        <p>
                          <span className="font-bold">FIDE</span>{" "}
                          <a href="https://www.fide.com/FIDE/handbook/Anti%20Cheating%20Guidelines.pdf">
                            anti-cheating guidelines
                          </a>
                        </p>
                      </li>
                    </ul>
                  </div>
                </Tab.Panel>
              </Tab.Panels>
            </Tab.Group>
            {/* ENTRY FORM */}
            <div className="block sm:hidden mt-12">
              <EntryForm id={id} />
            </div>
          </div>
        </div>
      </div>
      <FooterLanding />
    </div>
  );
}
Example #12
Source File: HardwareModal.tsx    From Meshtastic with GNU General Public License v3.0 4 votes vote down vote up
HardwareModal = ({
  device,
  open,
  close,
}: HardwareModal): JSX.Element => {
  const [hideDetails, setHideDetails] = useState(false);
  const { breakpoint } = useBreakpoint(BREAKPOINTS, 'md');

  return (
    <Modal open={open} onClose={close}>
      <div className="absolute right-0 z-20 m-2 md:flex">
        <Button onClick={close}>
          <FiX />
        </Button>
      </div>
      <div className="absolute inset-0">
        <motion.div
          layout
          animate={
            breakpoint === 'sm'
              ? hideDetails
                ? 'hiddenSm'
                : 'visibleSm'
              : hideDetails
              ? 'hidden'
              : 'visible'
          }
          variants={{
            hidden: { width: '100%', height: '100%' },
            hiddenSm: { height: '100%', width: '100%' },
            visible: { width: '20%', height: '100%' },
            visibleSm: { height: '33%', width: '100%' },
          }}
          transition={{
            type: 'just',
          }}
          className="flex flex-col md:h-full md:flex-row"
        >
          <motion.div
            layout
            className={`relative z-10 flex h-full w-full rounded-t-2xl md:rounded-l-2xl md:rounded-tr-none ${device.misc.Gradient}`}
          >
            <motion.img
              layout
              src={device.images.Front}
              alt=""
              className="pointer-events-none m-auto max-h-full max-w-full object-cover p-2"
            />
            <div className="absolute -bottom-5 z-20 flex w-full md:bottom-auto md:-right-5 md:h-full md:w-auto">
              <Button
                animate={
                  breakpoint === 'sm'
                    ? hideDetails
                      ? 'hiddenSm'
                      : 'visibleSm'
                    : hideDetails
                    ? 'hidden'
                    : 'visible'
                }
                variants={{
                  hidden: { rotate: 180 },
                  hiddenSm: { rotate: -90 },
                  visible: { rotate: 0 },
                  visibleSm: { rotate: 90 },
                }}
                onClick={() => {
                  setHideDetails(!hideDetails);
                }}
              >
                <FiChevronRight />
              </Button>
            </div>
            <AnimatePresence>
              {!hideDetails && (
                <>
                  <motion.div
                    initial={{ opacity: 0 }}
                    animate={{ opacity: 1 }}
                    exit={{ opacity: 0 }}
                    className={`absolute -bottom-5 z-20 flex md:mt-0 md:hidden md:pb-2 ${
                      hideDetails ? 'opacity-0' : 'opacity-100'
                    }`}
                  >
                    <VariantSelectButton options={device.variants} />
                  </motion.div>
                  <motion.div
                    initial={{ opacity: 0 }}
                    animate={{ opacity: 1 }}
                    exit={{ opacity: 0 }}
                    className="absolute -bottom-3 right-0 m-auto mr-2 ml-auto flex md:inset-x-1 md:bottom-4 md:mt-2"
                  >
                    <div className="m-auto flex gap-2">
                      {device.features.BLE && (
                        <Badge
                          name="Bluetooth"
                          color="bg-blue-500"
                          icon={<FiBluetooth />}
                        />
                      )}
                      {device.features.WiFi && (
                        <Badge
                          name="WiFi"
                          color="bg-orange-500"
                          icon={<FiWifi />}
                        />
                      )}
                    </div>
                  </motion.div>
                </>
              )}
            </AnimatePresence>
          </motion.div>
          <div
            className={`h-7 bg-base opacity-0 md:h-auto md:w-7 ${
              hideDetails ? 'flex' : 'hidden'
            }`}
          />
        </motion.div>
      </div>
      <div className="z-[1] mt-[25%] flex h-full flex-col md:ml-[20%] md:mt-0 md:w-4/5">
        <div className="z-0 hidden pb-2 md:flex">
          <VariantSelectButton options={device.variants} />
        </div>
        <div
          className={`mt-1 flex flex-grow rounded-2xl bg-base p-2 shadow-inner transition-opacity duration-100 ease-linear md:mt-0 md:rounded-l-none md:rounded-r-2xl md:p-4 ${
            hideDetails ? 'opacity-0' : 'opacity-100'
          }`}
        >
          <Tab.Group
            as="div"
            className="flex flex-grow flex-col rounded-2xl bg-primary p-2"
          >
            <Tab.List className="flex gap-2">
              <CardTab title="Info" />
              <CardTab title="Power" />
              <CardTab title="Pinout" />
            </Tab.List>
            <Tab.Panels as="div" className="flex-grow overflow-y-auto">
              <InfoTab device={device} />
              <PowerTab device={device} />
              <PinoutTab device={device} />
            </Tab.Panels>
          </Tab.Group>
        </div>
      </div>
    </Modal>
  );
}
Example #13
Source File: index.tsx    From interactsh-web with MIT License 4 votes vote down vote up
NotificationsPopup = ({ handleCloseDialog }: NotificationsPopupP) => {
  const data = getStoredData();
  const [isLoading, setIsLoading] = useState<boolean>(false);
  const [inputData, setInputData] = useState<any>({
    telegram: data.telegram,
    slack: data.slack,
    discord: data.discord,
  });

  const handleTelegramConfirm = () => {
    setIsLoading(true);
    const currentStoredData = getStoredData();
    setTimeout(() => {
      localStorage.clear();
      writeStoredData({ ...currentStoredData, telegram: inputData.telegram });
      setInputData({ ...inputData });
      setIsLoading(false);
    }, 500);
  };

  const handleDiscordConfirm = () => {
    setIsLoading(true);
    const currentStoredData = getStoredData();
    setTimeout(() => {
      localStorage.clear();
      writeStoredData({ ...currentStoredData, discord: inputData.discord });
      setInputData({ ...inputData });
      setIsLoading(false);
    }, 500);
  };

  const handleSlackConfirm = () => {
    setIsLoading(true);
    const currentStoredData = getStoredData();
    setTimeout(() => {
      localStorage.clear();
      writeStoredData({ ...currentStoredData, slack: inputData.slack });
      setInputData({ ...inputData });
      setIsLoading(false);
    }, 500);
  };

  const handleInput = (e: any) => {
    if (e.target.id === "telegram_bot_token") {
      setInputData({ ...inputData, telegram: { ...inputData.telegram, botToken: e.target.value } });
    } else if (e.target.id === "telegram_chat_id") {
      setInputData({ ...inputData, telegram: { ...inputData.telegram, chatId: e.target.value } });
    } else if (e.target.id === "slack_hook_key") {
      setInputData({ ...inputData, slack: { ...inputData.slack, hookKey: e.target.value } });
    } else if (e.target.id === "slack_channel") {
      setInputData({ ...inputData, slack: { ...inputData.slack, channel: e.target.value } });
    } else if (e.target.id === "discord_webhook") {
      setInputData({ ...inputData, discord: { ...inputData.discord, webhook: e.target.value } });
    } else if (e.target.id === "discord_channel") {
      setInputData({ ...inputData, discord: { ...inputData.discord, channel: e.target.value } });
    }
  };

  const handleToggleBtn = (e: any) => {
    if (e.target.name === "telegram") {
      setInputData({ ...inputData, telegram: { ...inputData.telegram, enabled: e.target.checked } });
      writeStoredData({ ...data, telegram: { ...data.telegram, enabled: e.target.checked } });
    } else if (e.target.name === "slack") {
      setInputData({ ...inputData, slack: { ...inputData.slack, enabled: e.target.checked } });
      writeStoredData({ ...data, slack: { ...data.slack, enabled: e.target.checked } });
    } else if (e.target.name === "discord") {
      setInputData({ ...inputData, discord: { ...inputData.discord, enabled: e.target.checked } });
      writeStoredData({ ...data, discord: { ...data.discord, enabled: e.target.checked } });
    }
  };

  return (
    <div className="backdrop_container">
      <div className="dialog_box">
        <div className="header">
          <span>Notifications</span>
          <CloseIcon onClick={handleCloseDialog} />
        </div>
        <div className="body">
          {/* <div className="toggle_btns">
            <div className="toggle_btn">
              <span>Telegram: </span>
              <ToggleBtn
                name="telegram"
                onChangeHandler={handleToggleBtn}
                value={inputData.telegram.enabled}
              />
            </div>
            <div className="toggle_btn">
              <span>Slack: </span>
              <ToggleBtn
                name="slack"
                onChangeHandler={handleToggleBtn}
                value={inputData.slack.enabled}
              />
            </div>
            <div className="toggle_btn">
              <span>Discord: </span>
              <ToggleBtn
                name="discord"
                onChangeHandler={handleToggleBtn}
                value={inputData.discord.enabled}
              />
            </div>
          </div> */}
          <Tab.Group>
            <Tab.List className="tab_list">
              {({ selectedIndex }) => (
                <>
                  <Tab
                    className="tab"
                    style={{
                      borderColor: selectedIndex === 0 ? "#3254c5" : "#444444",
                      opacity: selectedIndex === 0 ? "1" : "0.7",
                    }}
                  >
                    <div
                      id="editor_button"
                      style={{
                        color: inputData.telegram.enabled ? "#36AE7C" : "#bdbdbd",
                      }}
                    >
                      Telegram
                    </div>
                    <ToggleBtn
                      name="telegram"
                      onChangeHandler={handleToggleBtn}
                      value={inputData.telegram.enabled}
                    />
                  </Tab>
                  <Tab
                    className="tab"
                    style={{
                      borderColor: selectedIndex === 1 ? "#3254c5" : "#444444",
                      opacity: selectedIndex === 1 ? "1" : "0.7",
                    }}
                  >
                    <div
                      id="editor_button"
                      style={{
                        color: inputData.slack.enabled ? "#36AE7C" : "#bdbdbd",
                      }}
                    >
                      Slack
                    </div>
                    <ToggleBtn
                      name="slack"
                      onChangeHandler={handleToggleBtn}
                      value={inputData.slack.enabled}
                    />
                  </Tab>
                  <Tab
                    className="tab"
                    style={{
                      borderColor: selectedIndex === 2 ? "#3254c5" : "#444444",
                      opacity: selectedIndex === 2 ? "1" : "0.7",
                    }}
                  >
                    <div
                      id="editor_button"
                      style={{
                        color: inputData.discord.enabled ? "#36AE7C" : "#bdbdbd",
                      }}
                    >
                      Discord
                    </div>
                    <ToggleBtn
                      name="discord"
                      onChangeHandler={handleToggleBtn}
                      value={inputData.discord.enabled}
                    />
                  </Tab>
                </>
              )}
            </Tab.List>
            <Tab.Panels>
              <Tab.Panel className="panel">
                <input
                  id="telegram_bot_token"
                  type="text"
                  placeholder="Enter telegram bot token"
                  onChange={handleInput}
                  value={inputData.telegram.botToken}
                />
                <input
                  id="telegram_chat_id"
                  type="text"
                  placeholder="Enter telegram chat ID"
                  onChange={handleInput}
                  value={inputData.telegram.chatId}
                />
                <div>
                  <button
                    type="button"
                    className="submit_button"
                    disabled={
                      inputData.telegram.botToken === "" ||
                      inputData.telegram.chatId === "" ||
                      (inputData.telegram.botToken === data.telegram.botToken &&
                        inputData.telegram.chatId === data.telegram.chatId)
                    }
                    onClick={handleTelegramConfirm}
                  >
                    Confirm
                    {isLoading ? <LoadingIcon /> : <ArrowRightIcon />}
                  </button>
                </div>
              </Tab.Panel>
              <Tab.Panel className="panel">
                <input
                  id="slack_hook_key"
                  type="text"
                  placeholder="https://hooks.slack.com/services/XXX/XXX/XXXXXXXX"
                  onChange={handleInput}
                  value={inputData.slack.hookKey}
                />
                <input
                  id="slack_channel"
                  type="text"
                  placeholder="Enter slack channel (optional)"
                  onChange={handleInput}
                  value={inputData.slack.channel}
                />
                <div>
                  <button
                    type="button"
                    className="submit_button"
                    disabled={
                      inputData.slack.hookKey === "" ||
                      (inputData.slack.hookKey === data.slack.hookKey && inputData.slack.channel === data.slack.channel)
                    }
                    onClick={handleSlackConfirm}
                  >
                    Confirm
                    {isLoading ? <LoadingIcon /> : <ArrowRightIcon />}
                  </button>
                </div>
              </Tab.Panel>
              <Tab.Panel className="panel">
                <input
                  id="discord_webhook"
                  type="text"
                  placeholder="https://discord.com/api/webhooks/XXXXX/XXXXXXXXXX"
                  onChange={handleInput}
                  value={inputData.discord.webhook}
                />
                <input
                  id="discord_channel"
                  type="text"
                  placeholder="Enter discord channel (optional)"
                  onChange={handleInput}
                  value={inputData.discord.channel}
                />
                <div>
                  <button
                    type="button"
                    className="submit_button"
                    disabled={
                      inputData.discord.webhook === "" ||
                      (inputData.discord.webhook === data.discord.webhook && inputData.discord.channel === data.discord.channel)
                    }
                    onClick={handleDiscordConfirm}
                  >
                    Confirm
                    {isLoading ? <LoadingIcon /> : <ArrowRightIcon />}
                  </button>
                </div>
              </Tab.Panel>
            </Tab.Panels>
          </Tab.Group>
        </div>
        {/* <span>
          Please confirm the action, this action can’t be undone and all the client data will be
          deleted immediately. You can download a copy of your data in JSON format by clicking the
          Export button below or in top right.
        </span>
        <div className="buttons">
          <button type="button" title="Export" className="button" onClick={handleDataExport}>
            Export <DownloadIcon />
          </button>
        </div>
        <div className="buttons">
          <button
            type="button"
            disabled={isLoading}
            className="confirm_button"
            onClick={handleConfirm}
          >
            Confirm {isLoading ? <LoadingIcon /> : <DeleteIcon />}
          </button>
        </div> */}
      </div>
    </div>
  );
}