diff --git a/src/components/Elements/Balance/index.module.scss b/src/components/Elements/Balance/index.module.scss
new file mode 100644
index 00000000..492ca772
--- /dev/null
+++ b/src/components/Elements/Balance/index.module.scss
@@ -0,0 +1,22 @@
+.container {
+ display: flex;
+ gap: 1rem;
+}
+
+.balanceItem {
+ display: flex;
+ gap: 0.5rem;
+ align-items: center;
+}
+
+.balanceWrapper {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ line-height: 1.5;
+ height: fit-content;
+ padding: 0.5rem 1.25rem;
+ border-radius: 2rem;
+ min-width: 8rem;
+ font-weight: 500;
+}
diff --git a/src/components/Elements/Balance/index.tsx b/src/components/Elements/Balance/index.tsx
index 49b80f03..076173e3 100644
--- a/src/components/Elements/Balance/index.tsx
+++ b/src/components/Elements/Balance/index.tsx
@@ -1,7 +1,11 @@
-import { Typography, useTheme } from '@mui/material';
+import { Box, Typography, useTheme } from '@mui/material';
import { formatBalance } from '@/utils/functions';
+import { useAccounts } from '@/contexts/account';
+
+import styles from './index.module.scss';
+
interface BalanceProps {
coretimeBalance: number;
relayBalance: number;
@@ -10,16 +14,42 @@ interface BalanceProps {
const Balance = ({ relayBalance, coretimeBalance, symbol }: BalanceProps) => {
const theme = useTheme();
+ const {
+ state: { activeAccount },
+ } = useAccounts();
+
+ const items = [
+ {
+ label: 'Relay Chain',
+ value: relayBalance,
+ },
+ {
+ label: 'Coretime Chain',
+ value: coretimeBalance,
+ },
+ ];
- return (
-
-
- {`Relay chain: ${formatBalance(relayBalance.toString(), false)} ${symbol}`}
-
-
- {`Coretime chain: ${formatBalance(coretimeBalance.toString(), false)} ${symbol}`}
-
-
+ return activeAccount ? (
+
+ {items.map(({ label, value }, index) => (
+
+
+ {label}
+
+
+ {`${formatBalance(value.toString(), false)} ${symbol}`}
+
+
+ ))}
+
+ ) : (
+ <>>
);
};
diff --git a/src/components/Elements/Selectors/AssetSelector/index.module.scss b/src/components/Elements/Selectors/AssetSelector/index.module.scss
index 521136b4..c994ef44 100644
--- a/src/components/Elements/Selectors/AssetSelector/index.module.scss
+++ b/src/components/Elements/Selectors/AssetSelector/index.module.scss
@@ -3,7 +3,24 @@
justify-content: center;
}
+.option,
+.activeOption {
+ min-width: 15rem;
+ margin: 1rem 5rem;
+ border-radius: 0.5rem !important;
+ text-transform: capitalize;
+}
+
+.activeOption {
+ border: 1px solid #e84d68;
+ background: linear-gradient(180deg, #e84d68 0%, #ad2b49 100%);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+}
+
.option {
- min-width: 250px;
- margin: 1em 5em;
+ border: 1px solid #cccccc !important;
+ background-color: white;
+ color: black;
}
diff --git a/src/components/Elements/Selectors/AssetSelector/index.tsx b/src/components/Elements/Selectors/AssetSelector/index.tsx
index aeabfadd..640583c9 100644
--- a/src/components/Elements/Selectors/AssetSelector/index.tsx
+++ b/src/components/Elements/Selectors/AssetSelector/index.tsx
@@ -1,4 +1,4 @@
-import { ToggleButton, ToggleButtonGroup, useTheme } from '@mui/material';
+import { ToggleButton, ToggleButtonGroup } from '@mui/material';
import FormControl from '@mui/material/FormControl';
import { AssetType } from '@/models';
@@ -16,7 +16,6 @@ export default function AssetSelector({
setAsset,
symbol,
}: AssetSelectorProps) {
- const theme = useTheme();
const items = [
{
value: AssetType.TOKEN,
@@ -38,11 +37,7 @@ export default function AssetSelector({
>
{items.map(({ label, value }, index) => (
diff --git a/src/components/Elements/Selectors/ChainSelector/index.module.scss b/src/components/Elements/Selectors/ChainSelector/index.module.scss
new file mode 100644
index 00000000..ca1a9ba4
--- /dev/null
+++ b/src/components/Elements/Selectors/ChainSelector/index.module.scss
@@ -0,0 +1,16 @@
+.chainItem {
+ display: flex;
+ gap: 0.5rem;
+ align-items: center;
+}
+
+.icon {
+ width: 1.5rem;
+ height: 1.5rem;
+ border-radius: 100%;
+}
+
+.label {
+ font-size: 1rem;
+ line-height: 1.5;
+}
diff --git a/src/components/Elements/Selectors/ChainSelector/index.tsx b/src/components/Elements/Selectors/ChainSelector/index.tsx
index ced01401..59bcd5d3 100644
--- a/src/components/Elements/Selectors/ChainSelector/index.tsx
+++ b/src/components/Elements/Selectors/ChainSelector/index.tsx
@@ -12,6 +12,8 @@ import Image from 'next/image';
import { useCoretimeApi, useRelayApi } from '@/contexts/apis';
import { ChainType, NetworkType } from '@/models';
+import styles from './index.module.scss';
+
interface ChainSelectorProps {
chain: ChainType;
setChain: (_: ChainType) => void;
@@ -80,18 +82,12 @@ export const ChainSelector = ({ chain, setChain }: ChainSelectorProps) => {
>
{menuItems.map(({ icon, label, value, loading }, index) => (
diff --git a/src/components/Elements/Selectors/index.ts b/src/components/Elements/Selectors/index.ts
index 4b666636..3246a937 100644
--- a/src/components/Elements/Selectors/index.ts
+++ b/src/components/Elements/Selectors/index.ts
@@ -1,3 +1,4 @@
+export * from './AssetSelector';
export * from './ChainSelector';
export * from './RecipientSelector';
export * from './RegionSelector';
diff --git a/src/contexts/balance/index.tsx b/src/contexts/balance/index.tsx
new file mode 100644
index 00000000..2df705d7
--- /dev/null
+++ b/src/contexts/balance/index.tsx
@@ -0,0 +1,123 @@
+import React, { createContext, useContext, useEffect, useState } from 'react';
+
+import { useAccounts } from '../account';
+import { useCoretimeApi, useRelayApi } from '../apis';
+import { ApiState } from '../apis/types';
+import { useToast } from '../toast';
+
+interface Props {
+ children: React.ReactNode;
+}
+
+interface BalanceData {
+ balance: {
+ coretime: number;
+ relay: number;
+ };
+}
+
+const defaultBalanceData: BalanceData = {
+ balance: {
+ coretime: 0,
+ relay: 0,
+ },
+};
+
+const BalanceContext = createContext(defaultBalanceData);
+
+const BalanceProvider = ({ children }: Props) => {
+ const {
+ state: { activeAccount },
+ } = useAccounts();
+ const { toastWarning } = useToast();
+ const {
+ state: {
+ api: coretimeApi,
+ apiState: coretimeApiState,
+ symbol: coretimeSymbol,
+ name: coretimeChain,
+ },
+ } = useCoretimeApi();
+ const {
+ state: {
+ api: relayApi,
+ apiState: relayApiState,
+ symbol: relaySymbol,
+ name: relayChain,
+ },
+ } = useRelayApi();
+
+ const [coretimeBalance, setCoretimeBalance] = useState(0);
+ const [relayBalance, setRelayBalance] = useState(0);
+
+ useEffect(() => {
+ const subscribeBalances = async () => {
+ if (!activeAccount) {
+ setCoretimeBalance(0);
+ setRelayBalance(0);
+ return;
+ }
+ if (
+ coretimeApiState !== ApiState.READY ||
+ relayApiState !== ApiState.READY
+ )
+ return;
+
+ if (!coretimeApi || !relayApi) return;
+
+ const { address } = activeAccount;
+
+ const unsubscribeCoretime = await coretimeApi.queryMulti(
+ [[coretimeApi.query.system.account, address]],
+ ([
+ {
+ data: { free },
+ },
+ ]: [any]) => {
+ setCoretimeBalance(free as number);
+ free === 0 &&
+ toastWarning(
+ `The selected account does not have any ${coretimeSymbol} tokens on ${coretimeChain}.`
+ );
+ }
+ );
+
+ const unsubscribeRelay = await relayApi.queryMulti(
+ [[relayApi.query.system.account, address]],
+ ([
+ {
+ data: { free },
+ },
+ ]: [any]) => {
+ setRelayBalance(free as number);
+ free === 0 &&
+ toastWarning(
+ `The selected account does not have any ${relaySymbol} tokens on ${relayChain}.`
+ );
+ }
+ );
+ return () => {
+ unsubscribeCoretime();
+ unsubscribeRelay();
+ };
+ };
+ subscribeBalances();
+ }, [activeAccount, coretimeApi, coretimeApiState, relayApi, relayApiState]);
+
+ return (
+
+ {children}
+
+ );
+};
+
+const useBalances = () => useContext(BalanceContext);
+
+export { BalanceProvider, useBalances };
diff --git a/src/hooks/balance.tsx b/src/hooks/balance.tsx
deleted file mode 100644
index 166c0daf..00000000
--- a/src/hooks/balance.tsx
+++ /dev/null
@@ -1,79 +0,0 @@
-import { ApiPromise } from '@polkadot/api';
-import { useCallback, useEffect, useState } from 'react';
-
-import { parseHNString } from '@/utils/functions';
-
-import { useAccounts } from '@/contexts/account';
-import { useCoretimeApi, useRelayApi } from '@/contexts/apis';
-import { ApiState } from '@/contexts/apis/types';
-import { useToast } from '@/contexts/toast';
-
-// React hook for fetching balance.
-const useBalance = () => {
- const {
- state: { api: coretimeApi, apiState: coretimeApiState, symbol },
- } = useCoretimeApi();
- const {
- state: { api: relayApi, apiState: relayApiState },
- } = useRelayApi();
-
- const {
- state: { activeAccount },
- } = useAccounts();
-
- const [coretimeBalance, setCoretimeBalance] = useState(0);
- const [relayBalance, setRelayBalance] = useState(0);
-
- const { toastWarning } = useToast();
-
- const fetchBalance = useCallback(
- async (api: ApiPromise): Promise => {
- if (!activeAccount) {
- setCoretimeBalance(0);
- setRelayBalance(0);
- return;
- }
-
- const accountData: any = (
- await api.query.system.account(activeAccount.address)
- ).toHuman();
- const balance = parseHNString(accountData.data.free.toString());
-
- return balance;
- },
- [activeAccount]
- );
-
- const fetchBalances = useCallback(() => {
- if (coretimeApi && coretimeApiState == ApiState.READY) {
- fetchBalance(coretimeApi).then((balance) => {
- balance !== undefined && setCoretimeBalance(balance);
- balance === 0 &&
- toastWarning(
- `The selected account does not have any ${symbol} tokens on the Coretime chain.`
- );
- });
- }
- if (relayApi && relayApiState == ApiState.READY) {
- fetchBalance(relayApi).then((balance) => {
- balance !== undefined && setRelayBalance(balance);
- });
- }
- }, [
- fetchBalance,
- toastWarning,
- symbol,
- coretimeApi,
- coretimeApiState,
- relayApi,
- relayApiState,
- ]);
-
- useEffect(() => {
- fetchBalances();
- }, [fetchBalances]);
-
- return { coretimeBalance, relayBalance, fetchBalances };
-};
-
-export default useBalance;
diff --git a/src/hooks/salePhase.tsx b/src/hooks/salePhase.tsx
index 75eaf9e7..59eac2e0 100644
--- a/src/hooks/salePhase.tsx
+++ b/src/hooks/salePhase.tsx
@@ -29,6 +29,7 @@ const useSalePhase = () => {
const { saleInfo, config } = useSaleInfo();
const [currentPhase, setCurrentPhase] = useState(null);
+ const [loading, setLoading] = useState(false);
const [saleEndTimestamp, setSaleEndTimestamp] = useState(0);
const [saleStartTimestamp, setSaleStartTimestamp] = useState(0);
@@ -96,7 +97,12 @@ const useSalePhase = () => {
useEffect(() => {
if (!api || apiState !== ApiState.READY) return;
- fetchCurrentPhase(api);
+ const asyncFetchCurrentPhase = async () => {
+ setLoading(true);
+ await fetchCurrentPhase(api);
+ setLoading(false);
+ };
+ asyncFetchCurrentPhase();
}, [fetchCurrentPhase, api, apiState]);
return {
@@ -105,6 +111,7 @@ const useSalePhase = () => {
saleEndTimestamp,
progress,
saleSections,
+ loading,
};
};
diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx
index e038f765..97a42b01 100644
--- a/src/pages/_app.tsx
+++ b/src/pages/_app.tsx
@@ -17,6 +17,7 @@ import {
CoretimeApiContextProvider,
RelayApiContextProvider,
} from '@/contexts/apis';
+import { BalanceProvider } from '@/contexts/balance';
import { ContextDataProvider } from '@/contexts/common';
import { MarketProvider } from '@/contexts/market';
import { NetworkProvider } from '@/contexts/network';
@@ -52,17 +53,19 @@ export default function MyApp(props: MyAppProps) {
-
-
-
-
-
- {getLayout()}
-
-
-
-
-
+
+
+
+
+
+
+ {getLayout()}
+
+
+
+
+
+
diff --git a/src/pages/purchase.tsx b/src/pages/purchase.tsx
index 76ac42ed..5e22656d 100644
--- a/src/pages/purchase.tsx
+++ b/src/pages/purchase.tsx
@@ -1,10 +1,16 @@
-import { Box, Button, Typography, useTheme } from '@mui/material';
+import {
+ Backdrop,
+ Box,
+ Button,
+ CircularProgress,
+ Typography,
+ useTheme,
+} from '@mui/material';
import TimeAgo from 'javascript-time-ago';
import en from 'javascript-time-ago/locale/en.json';
import Link from 'next/link';
import { useState } from 'react';
-import useBalance from '@/hooks/balance';
import useSalePhase from '@/hooks/salePhase';
import useSalePrice from '@/hooks/salePrice';
import { sendTx } from '@/utils/functions';
@@ -15,6 +21,7 @@ import Balance from '@/components/Elements/Balance';
import { useAccounts } from '@/contexts/account';
import { useCoretimeApi } from '@/contexts/apis';
import { ApiState } from '@/contexts/apis/types';
+import { useBalances } from '@/contexts/balance';
import { useRegions } from '@/contexts/regions';
import { useSaleInfo } from '@/contexts/sales';
import { useToast } from '@/contexts/toast';
@@ -38,10 +45,15 @@ const Purchase = () => {
const { fetchRegions } = useRegions();
- const { coretimeBalance, relayBalance } = useBalance();
+ const { balance } = useBalances();
const currentPrice = useSalePrice();
- const { currentPhase, progress, saleStartTimestamp, saleEndTimestamp } =
- useSalePhase();
+ const {
+ currentPhase,
+ progress,
+ saleStartTimestamp,
+ saleEndTimestamp,
+ loading: loadingSalePhase,
+ } = useSalePhase();
const purchase = async () => {
if (!api || apiState !== ApiState.READY || !activeAccount || !activeSigner)
@@ -87,17 +99,20 @@ const Purchase = () => {
- {loading ||
- !currentPhase ||
- !progress ||
- !saleStartTimestamp ||
- !saleEndTimestamp ? (
+ {loading || loadingSalePhase ? (
+
+
+
+ ) : !currentPhase ||
+ !progress ||
+ !saleStartTimestamp ||
+ !saleEndTimestamp ? (
<>
Check your network conection and connect your wallet
@@ -119,7 +134,8 @@ const Purchase = () => {
diff --git a/src/pages/regions.tsx b/src/pages/regions.tsx
index 5446d679..f93bf446 100644
--- a/src/pages/regions.tsx
+++ b/src/pages/regions.tsx
@@ -22,6 +22,7 @@ import {
import { SellModal } from '@/components/Modals/Sell';
import { UnlistModal } from '@/components/Modals/Unlist';
+import { useAccounts } from '@/contexts/account';
import { useRegions } from '@/contexts/regions';
import { useToast } from '@/contexts/toast';
import {
@@ -34,6 +35,9 @@ import { RegionLocation } from '@/models';
const Dashboard = () => {
const theme = useTheme();
+ const {
+ state: { activeAccount },
+ } = useAccounts();
const { regions, loading, updateRegionName } = useRegions();
const [currentRegionIndex, setCurrentRegionIndex] = useState();
@@ -155,13 +159,13 @@ const Dashboard = () => {
)}
- {regions.length === 0 ? (
- <>
-
- No regions owned. Go to bulk sales{' '}
- to make a purchase
-
- >
+ {!activeAccount ? (
+ Please connect your wallet.
+ ) : regions.length === 0 ? (
+
+ No regions owned. Go to bulk sales{' '}
+ to make a purchase
+
) : (
<>
{regions.map((region, index) => (
diff --git a/src/pages/transfer.tsx b/src/pages/transfer.tsx
index 6493f294..130e0c83 100644
--- a/src/pages/transfer.tsx
+++ b/src/pages/transfer.tsx
@@ -1,5 +1,4 @@
import ArrowDownward from '@mui/icons-material/ArrowDownwardOutlined';
-import { LoadingButton } from '@mui/lab';
import {
Box,
Button,
@@ -12,7 +11,6 @@ import { Keyring } from '@polkadot/api';
import { Region } from 'coretime-utils';
import { useEffect, useState } from 'react';
-import useBalance from '@/hooks/balance';
import {
transferTokensFromCoretimeToRelay,
transferTokensFromRelayToCoretime,
@@ -26,6 +24,7 @@ import {
import {
AmountInput,
ChainSelector,
+ ProgressButton,
RecipientSelector,
RegionCard,
RegionSelector,
@@ -36,6 +35,7 @@ import AssetSelector from '@/components/Elements/Selectors/AssetSelector';
import { useAccounts } from '@/contexts/account';
import { useCoretimeApi, useRelayApi } from '@/contexts/apis';
import { ApiState } from '@/contexts/apis/types';
+import { useBalances } from '@/contexts/balance';
import { useRegions } from '@/contexts/regions';
import { useToast } from '@/contexts/toast';
import {
@@ -77,14 +77,13 @@ const TransferPage = () => {
const [asset, setAsset] = useState(AssetType.TOKEN);
const [transferAmount, setTransferAmount] = useState('');
- const { coretimeBalance, relayBalance, fetchBalances } = useBalance();
+ const { balance } = useBalances();
const defaultHandler = {
ready: () => toastInfo('Transaction was initiated.'),
inBlock: () => toastInfo(`In Block`),
finalized: () => setWorking(false),
success: () => {
- fetchBalances();
toastSuccess('Successfully transferred.');
},
error: () => {
@@ -229,8 +228,8 @@ const TransferPage = () => {
{
}}
>
- Origin chain:
+
+ Origin chain:
+
- Destination chain:
+
+ Destination chain:
+
{
- Transfer to:
+
+ Transfer to:
+
{asset === AssetType.TOKEN &&
@@ -310,15 +321,22 @@ const TransferPage = () => {
-
+
-
- Transfer
-
+ />