Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/navbar links configurable #34

Merged
merged 2 commits into from
Oct 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions web/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,8 @@ REACT_APP_VERSION=$npm_package_version
REACT_APP_IBC_CHAINS=
# can set custom evm chains via json string
REACT_APP_EVM_CHAINS=

REACT_APP_BRAND_URL=https://astria.org
REACT_APP_BRIDGE_URL=https://bridge.astria.org
REACT_APP_SWAP_URL=https://flame.astria.org/swap
REACT_APP_POOL_URL=https://flame.astria.org/pool
5 changes: 5 additions & 0 deletions web/.env.test
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,8 @@ REACT_APP_ENV=test

REACT_APP_IBC_CHAINS='{"Celestia Mocha-4":{"chainId":"mocha-4","chainName":"Celestia Mocha-4","rpc":"wss://rpc-mocha.pops.one","rest":"https://api-mocha.pops.one","stakeCurrency":{"coinDenom":"TIA","coinMinimalDenom":"utia","coinDecimals":6},"bip44":{"coinType":118},"bech32Config":{"bech32PrefixAccAddr":"celestia","bech32PrefixAccPub":"celestiapub","bech32PrefixConsAddr":"celestiavalcons","bech32PrefixConsPub":"celestiavalconspub","bech32PrefixValAddr":"celestiavaloper","bech32PrefixValPub":"celestiavaloperpub"},"currencies":[{"coinDenom":"TIA","coinMinimalDenom":"utia","coinDecimals":6,"ibcChannel":"channel-128","sequencerBridgeAccount":"astria1d7zjjljc0dsmxa545xkpwxym86g8uvvwhtezcr","iconClass":"i-celestia"},{"coinDenom":"STEEZE","coinMinimalDenom":"usteeze","coinDecimals":6}],"feeCurrencies":[{"coinDenom":"TIA","coinMinimalDenom":"utia","coinDecimals":6,"gasPriceStep":{"low":0.01,"average":0.02,"high":0.1}}],"iconClass":"i-celestia"}}'
REACT_APP_EVM_CHAINS=''

REACT_APP_BRAND_URL=https://astria.org
REACT_APP_BRIDGE_URL=https://bridge.astria.org
REACT_APP_SWAP_URL=https://flame.astria.org/swap
REACT_APP_POOL_URL=https://flame.astria.org/pool
6 changes: 3 additions & 3 deletions web/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type React from "react";
import { Route, Routes } from "react-router-dom";
import { EthWalletContextProvider } from "features/EthWallet/contexts/EthWalletContext";
import BridgePage from "pages/BridgePage/BridgePage";
import Layout from "pages/Layout";
import { NotificationsContextProvider } from "features/Notifications/contexts/NotificationsContext";
import { ConfigContextProvider } from "config/contexts/ConfigContext";
import { ConfigContextProvider } from "config";
import { EthWalletContextProvider } from "features/EthWallet";
import { NotificationsContextProvider } from "features/Notifications";

/**
* App component with routes.
Expand Down
14 changes: 6 additions & 8 deletions web/src/components/DepositCard/DepositCard.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
import type React from "react";
import { useContext, useEffect, useMemo, useState } from "react";
import { useEffect, useMemo, useState } from "react";

import { Dec, DecUtils } from "@keplr-wallet/unit";
import AnimatedArrowSpacer from "components/AnimatedDownArrowSpacer/AnimatedDownArrowSpacer";
import Dropdown, { type DropdownOption } from "components/Dropdown/Dropdown";
import type { EvmChainInfo, IbcChainInfo } from "config/chainConfigs";
import { useConfig } from "config/hooks/useConfig";
import { NotificationType } from "features/Notifications/components/Notification/types";
import { NotificationsContext } from "features/Notifications/contexts/NotificationsContext";
import { useEvmChainSelection } from "features/EthWallet/hooks/useEvmChainSelection";
import { useIbcChainSelection } from "features/IbcChainSelector/hooks/useIbcChainSelection";
import { useConfig, type EvmChainInfo, type IbcChainInfo } from "config";
import { useEvmChainSelection } from "features/EthWallet";
import { useIbcChainSelection } from "features/IbcChainSelector";
import { useNotifications, NotificationType } from "features/Notifications";
import { sendIbcTransfer } from "services/ibc";

export default function DepositCard(): React.ReactElement {
const { addNotification } = useContext(NotificationsContext);
const { evmChains, ibcChains } = useConfig();
const { addNotification } = useNotifications();

const {
evmAccountAddress: recipientAddress,
Expand Down
10 changes: 10 additions & 0 deletions web/src/components/Navbar/Navbar.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,14 @@ describe("Navbar Component", () => {
const logoElem = screen.getByAltText(/logo/i);
expect(logoElem).toBeInTheDocument();
});

test("renders navbar links", () => {
renderWithRouter(<Navbar />);
const bridgeLink = screen.getByText(/bridge/i);
expect(bridgeLink).toBeInTheDocument();
const swapLink = screen.getByText(/swap/i);
expect(swapLink).toBeInTheDocument();
const poolLink = screen.getByText(/pool/i);
expect(poolLink).toBeInTheDocument();
});
});
24 changes: 15 additions & 9 deletions web/src/components/Navbar/Navbar.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import type React from "react";
import { useState } from "react";
import { Link } from "react-router-dom";
import logo from "../../logo-flame-w-text.svg";

import { useConfig } from "config";
import logo from "logo-flame-w-text.svg";

function Navbar() {
const [isMobileMenuActive, setIsMobileMenuActive] = useState(false);
Expand All @@ -10,19 +12,22 @@ function Navbar() {
setIsMobileMenuActive((prev) => !prev);
};

const brandLink = "https://www.astria.org/";
const swapLink = "https://flame.astria.org/";
const poolLink = "https://flame.astria.org/";
const { brandURL, bridgeURL, swapURL, poolURL } = useConfig();

return (
<nav
className="navbar is-spaced is-transparent"
aria-label="main navigation"
>
<div className="navbar-brand">
<Link className="navbar-item" to={brandLink}>
<a
target="_blank"
href={brandURL}
className="navbar-item"
rel="noreferrer"
>
<img src={logo} width="161" height="32" alt="logo" />
</Link>
</a>
<button
type="button"
className={`navbar-burger ${isMobileMenuActive && "is-active"}`}
Expand All @@ -44,20 +49,21 @@ function Navbar() {
}`}
>
<div className="navbar-middle has-text-weight-medium is-family-monospace">
<Link to="/" className="navbar-item">
{/* this link is always active right now since the bridge is a separate app */}
<Link to="/" className="navbar-item is-active">
BRIDGE
</Link>
<a
target="_blank"
href={swapLink}
href={swapURL}
className="navbar-item"
rel="noreferrer"
>
SWAP
</a>
<a
target="_blank"
href={poolLink}
href={poolURL}
className="navbar-item"
rel="noreferrer"
>
Expand Down
20 changes: 10 additions & 10 deletions web/src/components/WithdrawCard/WithdrawCard.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import type React from "react";
import { useContext, useEffect, useMemo, useState } from "react";
import { useEffect, useMemo, useState } from "react";

import { useConfig, type EvmChainInfo, type IbcChainInfo } from "config";
import AnimatedArrowSpacer from "components/AnimatedDownArrowSpacer/AnimatedDownArrowSpacer";
import Dropdown, { type DropdownOption } from "components/Dropdown/Dropdown";
import type { EvmChainInfo, IbcChainInfo } from "config/chainConfigs";
import { useConfig } from "config/hooks/useConfig";
import {
getAstriaWithdrawerService,
useEthWallet,
useEvmChainSelection,
} from "features/EthWallet";
import { useIbcChainSelection } from "features/IbcChainSelector";
import { getAstriaWithdrawerService } from "features/EthWallet";
import { useEthWallet } from "features/EthWallet/hooks/useEthWallet";
import { useEvmChainSelection } from "features/EthWallet/hooks/useEvmChainSelection";
import { NotificationType } from "features/Notifications/components/Notification/types";
import { NotificationsContext } from "features/Notifications/contexts/NotificationsContext";
import { NotificationType, useNotifications } from "features/Notifications";

export default function WithdrawCard(): React.ReactElement {
const { addNotification } = useContext(NotificationsContext);
const { selectedWallet } = useEthWallet();
const { evmChains, ibcChains } = useConfig();
const { addNotification } = useNotifications();
const { selectedWallet } = useEthWallet();

const {
evmAccountAddress: fromAddress,
Expand Down
5 changes: 3 additions & 2 deletions web/src/config/chainConfigs/ChainConfigsLocal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,9 @@ const NobleChainInfo: IbcChainInfo = {
chainId: "noble-local-0",
chainName: "noble-local-0",
// RPC endpoint of the chain
rpc: "http://rpc.app.celestia.localdev.me",
rpc: "http://rpc.app.noble.localdev.me",
// REST endpoint of the chain.
rest: "http://rest.app.celestia.localdev.me",
rest: "http://rest.app.noble.localdev.me",
// Staking coin information
stakeCurrency: {
// Coin denomination to be displayed to the user.
Expand Down Expand Up @@ -213,6 +213,7 @@ const FakeChainInfo: EvmChainInfo = {
coinDenom: "FAKE",
coinMinimalDenom: "ufake",
coinDecimals: 6,
// fake address here so it shows up in the currency dropdown
nativeTokenWithdrawerContractAddress:
"0x0000000000000000000000000000000000000000",
iconClass: "i-flame",
Expand Down
18 changes: 1 addition & 17 deletions web/src/config/chainConfigs/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { ChainInfo } from "@keplr-wallet/types";
import { getEnvVariable } from "config/env";
import { getEnvVariable } from "config";

import {
evmChains as localEvmChains,
Expand Down Expand Up @@ -155,22 +155,6 @@ export type EvmChains = {
[label: string]: EvmChainInfo;
};

/**
* Retrieves the EVM chain with the given chain ID.
*
* @param chainIdHex - The chain ID as a hexadecimal string.
*/
export function getEvmChainById(chainIdHex: string): EvmChainInfo {
const chainId = Number.parseInt(chainIdHex as string, 16);
const chains = getEvmChains();
for (const chain of Object.values(chains)) {
if (chain.chainId === chainId) {
return chain;
}
}
throw new Error(`Chain with ID ${chainId} (hex: ${chainIdHex}) not found`);
}

/**
* Retrieves the EVM chains from the environment variable override or the default chain configurations,
* depending on the environment.
Expand Down
5 changes: 3 additions & 2 deletions web/src/config/contexts/ConfigContext.test.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type React from "react";
import { render, screen } from "@testing-library/react";
import { ConfigContextProvider } from "./ConfigContext";
import { useConfig } from "../hooks/useConfig";

import { ConfigContextProvider } from "config/contexts/ConfigContext";
import { useConfig } from "config/hooks/useConfig";

const TestComponent: React.FC = () => {
const config = useConfig();
Expand Down
46 changes: 39 additions & 7 deletions web/src/config/contexts/ConfigContext.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import React from "react";
import React, { useMemo } from "react";

import type { AppConfig } from "..";
import type { AppConfig } from "config";
import {
type EvmChainInfo,
type EvmChains,
getEvmChains,
getIbcChains,
type IbcChains,
} from "../chainConfigs";
} from "config/chainConfigs";
import { getEnvVariable } from "config/env";

export const ConfigContext = React.createContext<AppConfig | undefined>(
undefined,
Expand All @@ -17,17 +19,47 @@ type ConfigContextProps = {
};

/**
* ConfigContextProvider component to provide notifications context to children.
* ConfigContextProvider component to provide config context to children.
* @param children
*/
export const ConfigContextProvider: React.FC<ConfigContextProps> = ({
children,
}) => {
const ibcChains: IbcChains = getIbcChains();
const evmChains: EvmChains = getEvmChains();
const evmChains: EvmChains = useMemo(() => {
return getEvmChains();
}, []);
const ibcChains: IbcChains = useMemo(() => {
return getIbcChains();
}, []);

const brandURL = getEnvVariable("REACT_APP_BRAND_URL");
const bridgeURL = getEnvVariable("REACT_APP_BRIDGE_URL");
const swapURL = getEnvVariable("REACT_APP_SWAP_URL");
const poolURL = getEnvVariable("REACT_APP_POOL_URL");

// retrieves the EVM chain with the given chain ID.
const getEvmChainById = (chainIdHex: string): EvmChainInfo => {
const chainIdNum = Number.parseInt(chainIdHex, 16);
for (const chain of Object.values(evmChains)) {
if (chain.chainId === chainIdNum) {
return chain;
}
}
throw new Error(`Chain with ID ${chainIdHex} (${chainIdNum}) not found`);
};

return (
<ConfigContext.Provider value={{ ibcChains, evmChains }}>
<ConfigContext.Provider
value={{
ibcChains,
evmChains,
brandURL,
bridgeURL,
swapURL,
poolURL,
getEvmChainById,
}}
>
{children}
</ConfigContext.Provider>
);
Expand Down
4 changes: 4 additions & 0 deletions web/src/config/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ export const ENV = {
REACT_APP_VERSION: process.env.REACT_APP_VERSION,
REACT_APP_IBC_CHAINS: process.env.REACT_APP_IBC_CHAINS,
REACT_APP_EVM_CHAINS: process.env.REACT_APP_EVM_CHAINS,
REACT_APP_BRAND_URL: process.env.REACT_APP_BRAND_URL,
REACT_APP_BRIDGE_URL: process.env.REACT_APP_BRIDGE_URL,
REACT_APP_SWAP_URL: process.env.REACT_APP_SWAP_URL,
REACT_APP_POOL_URL: process.env.REACT_APP_POOL_URL,
};

/**
Expand Down
2 changes: 1 addition & 1 deletion web/src/config/hooks/useConfig.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useContext } from "react";

import { ConfigContext } from "../contexts/ConfigContext";
import { ConfigContext } from "config/contexts/ConfigContext";

/**
* Hook to use the config context.
Expand Down
40 changes: 39 additions & 1 deletion web/src/config/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,51 @@
import type { EvmChains, IbcChains } from "./chainConfigs";
import {
type EvmChainInfo,
type EvmChains,
type EvmCurrency,
evmCurrencyBelongsToChain,
type IbcChainInfo,
type IbcChains,
type IbcCurrency,
ibcCurrencyBelongsToChain,
toChainInfo,
} from "./chainConfigs";
import { ConfigContextProvider } from "./contexts/ConfigContext";
import { getEnvVariable } from "./env";
import { useConfig } from "./hooks/useConfig";

/**
* Represents the configuration object for the application.
*
* @typedef {Object} AppConfig
* @property {IbcChains} ibcChains - The configurations for IBC chains.
* @property {EvmChains} evmChains - The configurations for EVM chains.
* @property {string} brandURL - The URL for the brand link in the navbar.
* @property {string} bridgeURL - The URL for the bridge link in the navbar.
* @property {string} swapURL - The URL for the swap link in the navbar.
* @property {string} poolURL - The URL for the pool link in the navbar.
* @property {function} getEvmChainById - Retrieves the EVM chain with the given chain ID from the config context.
*/
export type AppConfig = {
ibcChains: IbcChains;
evmChains: EvmChains;
brandURL: string;
bridgeURL: string;
swapURL: string;
poolURL: string;
getEvmChainById(chainIdHex: string): EvmChainInfo;
};

export {
ConfigContextProvider,
type EvmChainInfo,
type EvmChains,
type EvmCurrency,
evmCurrencyBelongsToChain,
getEnvVariable,
type IbcChainInfo,
type IbcChains,
type IbcCurrency,
ibcCurrencyBelongsToChain,
toChainInfo,
useConfig,
};
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React from "react";

import { useEthWallet } from "../../hooks/useEthWallet";
import { getEvmChains } from "config/chainConfigs";
import { useConfig } from "config";

import { useEthWallet } from "features/EthWallet/hooks/useEthWallet";

/**
* A card component for connecting to an ethereum wallet
Expand All @@ -10,7 +11,7 @@ export default function EthWalletConnector() {
const { providers, selectedWallet, userAccount, handleConnect } =
useEthWallet();

const evmChains = getEvmChains();
const { evmChains } = useConfig();
const firstKey = Object.keys(evmChains)[0];
const defaultChain = evmChains[firstKey];

Expand Down
Loading