react-icons/fa#FaExternalLinkAlt TypeScript Examples

The following examples show how to use react-icons/fa#FaExternalLinkAlt. 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
ExternalLink = ({ className, children, ...rest }: InterlayLinkProps): JSX.Element => {
  return (
    <InterlayLink
      className={clsx(
        { 'text-interlayDenim': process.env.REACT_APP_RELAY_CHAIN_NAME === POLKADOT },
        { 'dark:text-kintsugiSupernova': process.env.REACT_APP_RELAY_CHAIN_NAME === KUSAMA },
        'space-x-1.5',
        'inline-flex',
        'items-center',
        className
      )}
      target='_blank'
      rel='noopener noreferrer'
      {...rest}
    >
      <span className='inline-flex'>{children}</span>
      <FaExternalLinkAlt />
    </InterlayLink>
  );
}
Example #2
Source File: index.tsx    From polkabtc-ui with Apache License 2.0 6 votes vote down vote up
FEEDBACK_ITEMS = [
  {
    title: 'User Feedback Form',
    link: USER_FEEDBACK_FORM,
    icon: <FaExternalLinkAlt />
  },
  {
    title: 'Vault Feedback Form',
    link: VAULT_FEEDBACK_FORM,
    icon: <FaExternalLinkAlt />
  },
  {
    title: 'Relayer Feedback Form',
    link: RELAYER_FEEDBACK_FORM,
    icon: <FaExternalLinkAlt />
  },
  {
    title: 'Open an Issue on Github',
    link: POLKA_BTC_UI_GITHUB_ISSUES,
    icon: <FaGithub />
  },
  {
    title: 'Discuss on Discord',
    link: INTERLAY_DISCORD,
    icon: <FaDiscord />
  }
]
Example #3
Source File: columns.tsx    From crossfeed with Creative Commons Zero v1.0 Universal 5 votes vote down vote up
extLink = <FaExternalLinkAlt style={{ width: 12 }}></FaExternalLinkAlt>
Example #4
Source File: index.tsx    From polkabtc-ui with Apache License 2.0 4 votes vote down vote up
IssueRequestsTable = ({
  totalIssueRequests
}: Props): JSX.Element | null => {
  const query = useQuery();
  const selectedPage: number = query.get(QUERY_PARAMETERS.page) || 1;
  const updateQueryParameters = useUpdateQueryParameters();
  const statsApi = usePolkabtcStats();
  const [data, setData] = React.useState<DashboardRequestInfo[]>([]);
  const [status, setStatus] = React.useState(STATUSES.IDLE);
  const [error, setError] = React.useState<Error | null>(null);
  const { t } = useTranslation();

  React.useEffect(() => {
    if (!statsApi) return;
    if (!selectedPage) return;

    const selectedPageIndex = selectedPage - 1;

    try {
      (async () => {
        setStatus(STATUSES.PENDING);
        const response = await statsApi.getIssues(
          selectedPageIndex,
          PAGE_SIZE,
          undefined,
          undefined,
          constants.BITCOIN_NETWORK as BtcNetworkName // Not sure why cast is necessary here, but TS complains
        );
        setStatus(STATUSES.RESOLVED);
        setData(response.data);
      })();
    } catch (error) {
      setStatus(STATUSES.REJECTED);
      setError(error);
    }
  }, [
    statsApi,
    selectedPage
  ]);

  const columns = React.useMemo(
    () => [
      {
        Header: t('date'),
        accessor: 'timestamp',
        classNames: [
          'text-left'
        ],
        Cell: function FormattedCell({ value }) {
          return (
            <>
              {formatDateTimePrecise(new Date(Number(value)))}
            </>
          );
        }
      },
      {
        Header: t('issue_page.amount'),
        accessor: 'amountBTC',
        classNames: [
          'text-right'
        ]
      },
      {
        Header: t('issue_page.parachain_block'),
        accessor: 'creation',
        classNames: [
          'text-right'
        ]
      },
      {
        Header: t('issue_page.vault_dot_address'),
        accessor: 'vaultDOTAddress',
        classNames: [
          'text-left'
        ],
        Cell: function FormattedCell({ value }) {
          return (
            <>
              {shortAddress(value)}
            </>
          );
        }
      },
      {
        Header: t('issue_page.vault_btc_address'),
        accessor: 'vaultBTCAddress',
        classNames: [
          'text-left'
        ],
        Cell: function FormattedCell({ value }) {
          return (
            <InterlayLink
              className={clsx(
                'text-interlayDodgerBlue',
                'space-x-1.5',
                'flex',
                'items-center'
              )}
              href={`${BTC_ADDRESS_API}${value}`}
              target='_blank'
              rel='noopener noreferrer'>
              <span>{shortAddress(value)}</span>
              <FaExternalLinkAlt />
            </InterlayLink>
          );
        }
      },
      {
        Header: t('status'),
        classNames: [
          'text-left'
        ],
        Cell: function FormattedCell(props) {
          return (
            <StatusCell
              status={{
                completed: props.row.original.completed,
                cancelled: props.row.original.cancelled,
                isExpired: props.row.original.isExpired,
                reimbursed: props.row.original.reimbursed
              }} />
          );
        }
      }
    ],
    [t]
  );

  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    rows,
    prepareRow
  } = useTable(
    {
      columns,
      data
    }
  );

  if (status === STATUSES.REJECTED && error) {
    return (
      <ErrorHandler error={error} />
    );
  }

  const handlePageChange = (newPage: number) => {
    updateQueryParameters({
      [QUERY_PARAMETERS.page]: newPage
    });
  };

  return (
    <InterlayTableContainer className='space-y-6'>
      <h2
        className={clsx(
          'text-2xl',
          'font-bold'
        )}>
        {t('issue_page.recent_requests')}
      </h2>
      {(status === STATUSES.IDLE || status === STATUSES.PENDING) && (
        <div
          className={clsx(
            'flex',
            'justify-center'
          )}>
          <EllipsisLoader dotClassName='bg-interlayTreePoppy-400' />
        </div>
      )}
      {status === STATUSES.RESOLVED && (
        <InterlayTable {...getTableProps()}>
          <InterlayThead>
            {headerGroups.map(headerGroup => (
              // eslint-disable-next-line react/jsx-key
              <InterlayTr {...headerGroup.getHeaderGroupProps()}>
                {headerGroup.headers.map(column => (
                  // eslint-disable-next-line react/jsx-key
                  <InterlayTh
                    {...column.getHeaderProps([
                      {
                        className: clsx(column.classNames),
                        style: column.style
                      }
                    ])}>
                    {column.render('Header')}
                  </InterlayTh>
                ))}
              </InterlayTr>
            ))}
          </InterlayThead>
          <InterlayTbody {...getTableBodyProps()}>
            {rows.map(row => {
              prepareRow(row);

              return (
                // eslint-disable-next-line react/jsx-key
                <InterlayTr {...row.getRowProps()}>
                  {row.cells.map(cell => {
                    return (
                      // eslint-disable-next-line react/jsx-key
                      <InterlayTd
                        {...cell.getCellProps([
                          {
                            className: clsx(cell.column.classNames),
                            style: cell.column.style
                          }
                        ])}>
                        {cell.render('Cell')}
                      </InterlayTd>
                    );
                  })}
                </InterlayTr>
              );
            })}
          </InterlayTbody>
        </InterlayTable>
      )}
      {totalIssueRequests > 0 && (
        // TODO: error-prone in UI/UX
        <Pagination
          pageSize={PAGE_SIZE}
          total={totalIssueRequests}
          current={selectedPage}
          onChange={handlePageChange} />
      )}
    </InterlayTableContainer>
  );
}
Example #5
Source File: index.tsx    From polkabtc-ui with Apache License 2.0 4 votes vote down vote up
RedeemRequestsTable = ({
  totalRedeemRequests
}: Props): JSX.Element | null => {
  const query = useQuery();
  const selectedPage: number = query.get(QUERY_PARAMETERS.page) || 1;
  const updateQueryParameters = useUpdateQueryParameters();
  const statsApi = usePolkabtcStats();
  const [data, setData] = React.useState<DashboardRequestInfo[]>([]);
  const [status, setStatus] = React.useState(STATUSES.IDLE);
  const [error, setError] = React.useState<Error | null>(null);
  const { t } = useTranslation();

  React.useEffect(() => {
    if (!statsApi) return;
    if (!selectedPage) return;

    const selectedPageIndex = selectedPage - 1;

    try {
      (async () => {
        setStatus(STATUSES.PENDING);
        const response = await statsApi.getRedeems(
          selectedPageIndex,
          PAGE_SIZE,
          undefined,
          undefined,
          // TODO: should double-check
          constants.BITCOIN_NETWORK as BtcNetworkName
        );
        setStatus(STATUSES.RESOLVED);
        setData(response.data);
      })();
    } catch (error) {
      setStatus(STATUSES.REJECTED);
      setError(error);
    }
  }, [
    statsApi,
    selectedPage
  ]);

  const columns = React.useMemo(
    () => [
      {
        Header: t('date'),
        accessor: 'timestamp',
        classNames: [
          'text-left'
        ],
        Cell: function FormattedCell({ value }) {
          return (
            <>
              {formatDateTimePrecise(new Date(Number(value)))}
            </>
          );
        }
      },
      {
        Header: t('redeem_page.amount'),
        accessor: 'amountPolkaBTC',
        classNames: [
          'text-right'
        ]
      },
      {
        Header: t('parachain_block'),
        accessor: 'creation',
        classNames: [
          'text-right'
        ]
      },
      {
        Header: t('issue_page.vault_dot_address'),
        accessor: 'vaultDotAddress',
        classNames: [
          'text-left'
        ],
        Cell: function FormattedCell({ value }) {
          return (
            <>
              {shortAddress(value)}
            </>
          );
        }
      },
      {
        Header: t('redeem_page.output_BTC_address'),
        accessor: 'btcAddress',
        classNames: [
          'text-left'
        ],
        Cell: function FormattedCell({ value }) {
          return (
            <InterlayLink
              className={clsx(
                'text-interlayDodgerBlue',
                'space-x-1.5',
                'flex',
                'items-center'
              )}
              href={`${BTC_ADDRESS_API}${value}`}
              target='_blank'
              rel='noopener noreferrer'>
              <span>{shortAddress(value)}</span>
              <FaExternalLinkAlt />
            </InterlayLink>
          );
        }
      },
      {
        Header: t('status'),
        classNames: [
          'text-left'
        ],
        Cell: function FormattedCell(props) {
          return (
            <StatusCell
              status={{
                completed: props.row.original.completed,
                cancelled: props.row.original.cancelled,
                isExpired: props.row.original.isExpired,
                reimbursed: props.row.original.reimbursed
              }} />
          );
        }
      }
    ],
    [t]
  );

  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    rows,
    prepareRow
  } = useTable(
    {
      columns,
      data
    }
  );

  if (status === STATUSES.REJECTED && error) {
    return (
      <ErrorHandler error={error} />
    );
  }

  const handlePageChange = (newPage: number) => {
    updateQueryParameters({
      [QUERY_PARAMETERS.page]: newPage
    });
  };

  return (
    <InterlayTableContainer className='space-y-6'>
      <h2
        className={clsx(
          'text-2xl',
          'font-bold'
        )}>
        {t('issue_page.recent_requests')}
      </h2>
      {(status === STATUSES.IDLE || status === STATUSES.PENDING) && (
        <div
          className={clsx(
            'flex',
            'justify-center'
          )}>
          <EllipsisLoader dotClassName='bg-interlayTreePoppy-400' />
        </div>
      )}
      {status === STATUSES.RESOLVED && (
        <InterlayTable {...getTableProps()}>
          <InterlayThead>
            {headerGroups.map(headerGroup => (
              // eslint-disable-next-line react/jsx-key
              <InterlayTr {...headerGroup.getHeaderGroupProps()}>
                {headerGroup.headers.map(column => (
                  // eslint-disable-next-line react/jsx-key
                  <InterlayTh
                    {...column.getHeaderProps([
                      {
                        className: clsx(column.classNames),
                        style: column.style
                      }
                    ])}>
                    {column.render('Header')}
                  </InterlayTh>
                ))}
              </InterlayTr>
            ))}
          </InterlayThead>
          <InterlayTbody {...getTableBodyProps()}>
            {rows.map(row => {
              prepareRow(row);

              return (
                // eslint-disable-next-line react/jsx-key
                <InterlayTr {...row.getRowProps()}>
                  {row.cells.map(cell => {
                    return (
                      // eslint-disable-next-line react/jsx-key
                      <InterlayTd
                        {...cell.getCellProps([
                          {
                            className: clsx(cell.column.classNames),
                            style: cell.column.style
                          }
                        ])}>
                        {cell.render('Cell')}
                      </InterlayTd>
                    );
                  })}
                </InterlayTr>
              );
            })}
          </InterlayTbody>
        </InterlayTable>
      )}
      {totalRedeemRequests > 0 && (
        // TODO: error-prone in UI/UX
        <Pagination
          pageSize={PAGE_SIZE}
          total={totalRedeemRequests}
          current={selectedPage}
          onChange={handlePageChange} />
      )}
    </InterlayTableContainer>
  );
}
Example #6
Source File: index.tsx    From polkabtc-ui with Apache License 2.0 4 votes vote down vote up
VaultIssueRequestsTable = ({
  totalIssueRequests,
  vaultAddress
}: Props): JSX.Element | null => {
  const query = useQuery();
  const selectedPage: number = query.get(QUERY_PARAMETERS.page) || 1;
  const updateQueryParameters = useUpdateQueryParameters();
  const statsApi = usePolkabtcStats();
  const [data, setData] = React.useState<DashboardRequestInfo[]>([]);
  const [status, setStatus] = React.useState(STATUSES.IDLE);
  const [error, setError] = React.useState<Error | null>(null);
  const { t } = useTranslation();

  const issueRequestFilter = React.useMemo(
    () => [{ column: IssueColumns.VaultId, value: vaultAddress }], // filter requests by vault address
    [vaultAddress]
  );

  React.useEffect(() => {
    if (!statsApi) return;
    if (!selectedPage) return;

    const selectedPageIndex = selectedPage - 1;

    try {
      (async () => {
        setStatus(STATUSES.PENDING);
        const response = await statsApi.getFilteredIssues(
          selectedPageIndex,
          PAGE_SIZE,
          undefined,
          undefined,
          constants.BITCOIN_NETWORK as BtcNetworkName, // Not sure why cast is necessary here, but TS complains
          issueRequestFilter
        );
        setStatus(STATUSES.RESOLVED);
        setData(response.data);
      })();
    } catch (error) {
      setStatus(STATUSES.REJECTED);
      setError(error);
    }
  }, [
    statsApi,
    selectedPage,
    issueRequestFilter
  ]);

  const columns = React.useMemo(
    () => [
      {
        Header: t('id'),
        accessor: 'id',
        classNames: [
          'text-center'
        ]
      },
      {
        Header: t('date'),
        accessor: 'timestamp',
        classNames: [
          'text-left'
        ],
        Cell: function FormattedCell({ value }) {
          return (
            <>
              {formatDateTimePrecise(new Date(Number(value)))}
            </>
          );
        }
      },
      {
        Header: t('vault.creation_block'),
        accessor: 'creation',
        classNames: [
          'text-right'
        ]
      },
      {
        Header: t('user'),
        accessor: 'requester',
        classNames: [
          'text-center'
        ],
        Cell: function FormattedCell({ value }) {
          return (
            <>
              {shortAddress(value)}
            </>
          );
        }
      },
      {
        Header: t('issue_page.amount'),
        accessor: 'amountBTC',
        classNames: [
          'text-right'
        ]
      },
      {
        Header: t('griefing_collateral'),
        accessor: 'griefingCollateral',
        classNames: [
          'text-right'
        ]
      },
      {
        Header: t('issue_page.vault_btc_address'),
        accessor: 'vaultBTCAddress',
        classNames: [
          'text-left'
        ],
        Cell: function FormattedCell({ value }) {
          return (
            <InterlayLink
              className={clsx(
                'text-interlayDodgerBlue',
                'space-x-1.5',
                'flex',
                'items-center'
              )}
              href={`${BTC_ADDRESS_API}${value}`}
              target='_blank'
              rel='noopener noreferrer'>
              <span>{shortAddress(value)}</span>
              <FaExternalLinkAlt />
            </InterlayLink>
          );
        }
      },
      {
        Header: t('status'),
        classNames: [
          'text-left'
        ],
        Cell: function FormattedCell(props) {
          return (
            <StatusCell
              status={{
                completed: props.row.original.completed,
                cancelled: props.row.original.cancelled,
                isExpired: props.row.original.isExpired,
                reimbursed: props.row.original.reimbursed
              }} />
          );
        }
      }
    ],
    [t]
  );

  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    rows,
    prepareRow
  } = useTable(
    {
      columns,
      data
    }
  );

  if (status === STATUSES.REJECTED && error) {
    return (
      <ErrorHandler error={error} />
    );
  }

  const handlePageChange = (newPage: number) => {
    updateQueryParameters({
      [QUERY_PARAMETERS.page]: newPage
    });
  };

  return (
    <InterlayTableContainer className='space-y-6'>
      <h2
        className={clsx(
          'text-2xl',
          'font-bold'
        )}>
        {t('issue_requests')}
      </h2>
      {(status === STATUSES.IDLE || status === STATUSES.PENDING) && (
        <div
          className={clsx(
            'flex',
            'justify-center'
          )}>
          <EllipsisLoader dotClassName='bg-interlayTreePoppy-400' />
        </div>
      )}
      {status === STATUSES.RESOLVED && (
        <InterlayTable {...getTableProps()}>
          <InterlayThead>
            {headerGroups.map(headerGroup => (
              // eslint-disable-next-line react/jsx-key
              <InterlayTr {...headerGroup.getHeaderGroupProps()}>
                {headerGroup.headers.map(column => (
                  // eslint-disable-next-line react/jsx-key
                  <InterlayTh
                    {...column.getHeaderProps([
                      {
                        className: clsx(column.classNames),
                        style: column.style
                      }
                    ])}>
                    {column.render('Header')}
                  </InterlayTh>
                ))}
              </InterlayTr>
            ))}
          </InterlayThead>
          <InterlayTbody {...getTableBodyProps()}>
            {rows.map(row => {
              prepareRow(row);

              return (
                // eslint-disable-next-line react/jsx-key
                <InterlayTr {...row.getRowProps()}>
                  {row.cells.map(cell => {
                    return (
                      // eslint-disable-next-line react/jsx-key
                      <InterlayTd
                        {...cell.getCellProps([
                          {
                            className: clsx(cell.column.classNames),
                            style: cell.column.style
                          }
                        ])}>
                        {cell.render('Cell')}
                      </InterlayTd>
                    );
                  })}
                </InterlayTr>
              );
            })}
          </InterlayTbody>
        </InterlayTable>
      )}
      {totalIssueRequests > 0 && (
        // TODO: error-prone in UI/UX
        <Pagination
          pageSize={PAGE_SIZE}
          total={totalIssueRequests}
          current={selectedPage}
          onChange={handlePageChange} />
      )}
    </InterlayTableContainer>
  );
}
Example #7
Source File: index.tsx    From polkabtc-ui with Apache License 2.0 4 votes vote down vote up
VaultRedeemRequestsTable = ({
  totalRedeemRequests,
  vaultAddress
}: Props): JSX.Element | null => {
  const query = useQuery();
  const selectedPage: number = query.get(QUERY_PARAMETERS.page) || 1;
  const updateQueryParameters = useUpdateQueryParameters();
  const statsApi = usePolkabtcStats();
  const [data, setData] = React.useState<DashboardRequestInfo[]>([]);
  const [status, setStatus] = React.useState(STATUSES.IDLE);
  const [error, setError] = React.useState<Error | null>(null);
  const { t } = useTranslation();

  const redeemRequestFilter = React.useMemo(
    () => [{ column: RedeemColumns.VaultId, value: vaultAddress }], // filter requests by vault address
    [vaultAddress]
  );

  React.useEffect(() => {
    if (!statsApi) return;
    if (!selectedPage) return;

    const selectedPageIndex = selectedPage - 1;

    try {
      (async () => {
        setStatus(STATUSES.PENDING);
        const response = await statsApi.getFilteredRedeems(
          selectedPageIndex,
          PAGE_SIZE,
          undefined,
          undefined,
          constants.BITCOIN_NETWORK as BtcNetworkName, // Not sure why cast is necessary here, but TS complains
          redeemRequestFilter
        );
        setStatus(STATUSES.RESOLVED);
        setData(response.data);
      })();
    } catch (error) {
      setStatus(STATUSES.REJECTED);
      setError(error);
    }
  }, [
    statsApi,
    selectedPage,
    redeemRequestFilter
  ]);

  const columns = React.useMemo(
    () => [
      {
        Header: t('id'),
        accessor: 'id',
        classNames: [
          'text-center'
        ]
      },
      {
        Header: t('date'),
        accessor: 'timestamp',
        classNames: [
          'text-left'
        ],
        Cell: function FormattedCell({ value }) {
          return (
            <>
              {formatDateTimePrecise(new Date(Number(value)))}
            </>
          );
        }
      },
      {
        Header: t('vault.creation_block'),
        accessor: 'creation',
        classNames: [
          'text-right'
        ]
      },
      {
        Header: t('user'),
        accessor: 'requester',
        classNames: [
          'text-center'
        ],
        Cell: function FormattedCell({ value }) {
          return (
            <>
              {shortAddress(value)}
            </>
          );
        }
      },
      {
        Header: t('issue_page.amount'),
        accessor: 'amountPolkaBTC',
        classNames: [
          'text-right'
        ]
      },
      {
        Header: t('redeem_page.btc_destination_address'),
        accessor: 'btcAddress',
        classNames: [
          'text-left'
        ],
        Cell: function FormattedCell({ value }) {
          return (
            <InterlayLink
              className={clsx(
                'text-interlayDodgerBlue',
                'space-x-1.5',
                'flex',
                'items-center'
              )}
              href={`${BTC_ADDRESS_API}${value}`}
              target='_blank'
              rel='noopener noreferrer'>
              <span>{shortAddress(value)}</span>
              <FaExternalLinkAlt />
            </InterlayLink>
          );
        }
      },
      {
        Header: t('status'),
        classNames: [
          'text-left'
        ],
        Cell: function FormattedCell(props) {
          return (
            <StatusCell
              status={{
                completed: props.row.original.completed,
                cancelled: props.row.original.cancelled,
                isExpired: props.row.original.isExpired,
                reimbursed: props.row.original.reimbursed
              }} />
          );
        }
      }
    ],
    [t]
  );

  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    rows,
    prepareRow
  } = useTable(
    {
      columns,
      data
    }
  );

  if (status === STATUSES.REJECTED && error) {
    return (
      <ErrorHandler error={error} />
    );
  }

  const handlePageChange = (newPage: number) => {
    updateQueryParameters({
      [QUERY_PARAMETERS.page]: newPage
    });
  };

  return (
    <InterlayTableContainer className='space-y-6'>
      <h2
        className={clsx(
          'text-2xl',
          'font-bold'
        )}>
        {t('redeem_requests')}
      </h2>
      {(status === STATUSES.IDLE || status === STATUSES.PENDING) && (
        <div
          className={clsx(
            'flex',
            'justify-center'
          )}>
          <EllipsisLoader dotClassName='bg-interlayTreePoppy-400' />
        </div>
      )}
      {status === STATUSES.RESOLVED && (
        <InterlayTable {...getTableProps()}>
          <InterlayThead>
            {headerGroups.map(headerGroup => (
              // eslint-disable-next-line react/jsx-key
              <InterlayTr {...headerGroup.getHeaderGroupProps()}>
                {headerGroup.headers.map(column => (
                  // eslint-disable-next-line react/jsx-key
                  <InterlayTh
                    {...column.getHeaderProps([
                      {
                        className: clsx(column.classNames),
                        style: column.style
                      }
                    ])}>
                    {column.render('Header')}
                  </InterlayTh>
                ))}
              </InterlayTr>
            ))}
          </InterlayThead>
          <InterlayTbody {...getTableBodyProps()}>
            {rows.map(row => {
              prepareRow(row);

              return (
                // eslint-disable-next-line react/jsx-key
                <InterlayTr {...row.getRowProps()}>
                  {row.cells.map(cell => {
                    return (
                      // eslint-disable-next-line react/jsx-key
                      <InterlayTd
                        {...cell.getCellProps([
                          {
                            className: clsx(cell.column.classNames),
                            style: cell.column.style
                          }
                        ])}>
                        {cell.render('Cell')}
                      </InterlayTd>
                    );
                  })}
                </InterlayTr>
              );
            })}
          </InterlayTbody>
        </InterlayTable>
      )}
      {totalRedeemRequests > 0 && (
        // TODO: error-prone in UI/UX
        <Pagination
          pageSize={PAGE_SIZE}
          total={totalRedeemRequests}
          current={selectedPage}
          onChange={handlePageChange} />
      )}
    </InterlayTableContainer>
  );
}
Example #8
Source File: index.tsx    From polkabtc-ui with Apache License 2.0 4 votes vote down vote up
function Challenges(): JSX.Element {
  // TODO: should be persisted using query parameters
  const [challengeId, setChallengeId] = useState(challengeCutOffs[0].id ?? null);
  // TODO: should be persisted using query parameters
  const [tabKey, setTabKey] = useState<string | null>('vaults');
  const { t } = useTranslation();

  const handleChallengeIdChange = (newChallengeId: number) => {
    setChallengeId(newChallengeId);
  };

  const handleTabSelect = (newTabKey: string | null) => {
    setTabKey(newTabKey);
  };

  const challengeTime = challengeCutOffs.find(item => item.id === challengeId)?.time;
  if (challengeTime === undefined) {
    // TODO: should translate
    throw new Error('Something went wrong!');
  }

  return (
    <MainContainer
      className={clsx(
        'flex',
        'justify-center',
        'fade-in-animation'
      )}>
      <div className='w-3/4'>
        <PageTitle mainTitle={t('leaderboard.challenges_title')} />
        <CardList>
          {CHALLENGE_ITEMS.map(challengeItem => (
            <Card key={challengeItem.title}>
              <CardHeader className='flex'>
                {t(challengeItem.title)}
                {challengeItem.titleIcon}
              </CardHeader>
              <CardContent>
                {t(challengeItem.content)}
                {challengeItem.contentLink && (
                  <InterlayLink
                    className={clsx(
                      'inline-flex',
                      'items-center',
                      'space-x-1',
                      'ml-1'
                    )}
                    href={challengeItem.contentLink}
                    target='_blank'
                    rel='noopener noreferrer'>
                    <span>{t('leaderboard.more_info')}</span>
                    <FaExternalLinkAlt />
                  </InterlayLink>
                )}
              </CardContent>
            </Card>
          ))}
        </CardList>
        <PageTitle
          mainTitle={t('leaderboard.title')}
          subTitle={<TimerIncrement />} />
        <div
          className={clsx(
            'text-right',
            'px-4',
            // TODO: hack for now
            'mt-8'
          )}>
          <ChallengeSelector
            name='challenge'
            value={challengeId}
            onChange={handleChallengeIdChange} />
        </div>
        <InterlayTabs onSelect={handleTabSelect}>
          <InterlayTab
            {...tabStyles}
            eventKey={TAB_KEYS.VAULTS}
            title={t('leaderboard.vault_scores')}>
            {tabKey === TAB_KEYS.VAULTS && <VaultScoresTable challengeTime={challengeTime} />}
          </InterlayTab>
          <InterlayTab
            {...tabStyles}
            eventKey={TAB_KEYS.STAKED_RELAYER}
            title={t('leaderboard.relayer_scores')}>
            {tabKey === TAB_KEYS.STAKED_RELAYER && <StakedRelayerScoresTable challengeTime={challengeTime} />}
          </InterlayTab>
        </InterlayTabs>
      </div>
    </MainContainer>
  );
}