Skip to content

Commit

Permalink
wip: transfer page UI
Browse files Browse the repository at this point in the history
  • Loading branch information
cuteolaf committed Aug 21, 2023
1 parent cf11225 commit 09c594d
Show file tree
Hide file tree
Showing 10 changed files with 231 additions and 47 deletions.
3 changes: 2 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
CONTRACT_IDENTITY="AddressOfIdentityContract"
CONTRACT_ADDRESS_BOOK="AddressOfAddressBookContract"
CONTRACT_ADDRESS_BOOK="AddressOfAddressBookContract"
RELAY_CHAIN="kusama_or_polkadot"
1 change: 1 addition & 0 deletions next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const nextConfig = {
env: {
CONTRACT_IDENTITY: process.env.CONTRACT_IDENTITY,
CONTRACT_ADDRESS_BOOK: process.env.CONTRACT_ADDRESS_BOOK,
RELAY_CHAIN: process.env.RELAY_CHAIN,
},
async redirects() {
return [
Expand Down
7 changes: 7 additions & 0 deletions src/consts/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
type RELAY_CHAIN_OPTION = 'polkadot' | 'kusama';
const RELAY_CHAIN_ENDPOINTS = {
polkadot: "wss://polkadot.api.onfinality.io/public-ws",
kusama: "wss://kusama.api.onfinality.io/public-ws"
};
export const RELAY_CHAIN = (process.env.RELAY_CHAIN || 'polkadot') as RELAY_CHAIN_OPTION;
export const RELAY_CHAIN_ENDPOINT = RELAY_CHAIN_ENDPOINTS[RELAY_CHAIN];
105 changes: 105 additions & 0 deletions src/contexts/RelayApi/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import { ApiPromise, WsProvider } from '@polkadot/api';
import jsonrpc from '@polkadot/types/interfaces/jsonrpc';
import { DefinitionRpcExt } from '@polkadot/types/types';
import React, { useContext, useEffect, useReducer } from 'react';

import { RELAY_CHAIN_ENDPOINT } from '@/consts';

import { useToast } from '../Toast';

///
// Initial state for `useReducer`

type State = {
socket: string;
jsonrpc: Record<string, Record<string, DefinitionRpcExt>>;
api: any;
apiError: any;
apiState: any;
};

const initialState: State = {
// These are the states
socket: RELAY_CHAIN_ENDPOINT,
jsonrpc: { ...jsonrpc },
api: null,
apiError: null,
apiState: null,
};

///
// Reducer function for `useReducer`

const reducer = (state: any, action: any) => {
switch (action.type) {
case 'CONNECT_INIT':
return { ...state, apiState: 'CONNECT_INIT' };
case 'CONNECT':
return { ...state, api: action.payload, apiState: 'CONNECTING' };
case 'CONNECT_SUCCESS':
return { ...state, apiState: 'READY' };
case 'CONNECT_ERROR':
return { ...state, apiState: 'ERROR', apiError: action.payload };
default:
throw new Error(`Unknown type: ${action.type}`);
}
};

///
// Connecting to the Substrate node

const connect = (state: any, dispatch: any) => {
const { apiState, socket, jsonrpc } = state;
// We only want this function to be performed once
if (apiState) return;

dispatch({ type: 'CONNECT_INIT' });

const provider = new WsProvider(socket);
const _api = new ApiPromise({ provider, rpc: jsonrpc });

// Set listeners for disconnection and reconnection event.
_api.on('connected', () => {
dispatch({ type: 'CONNECT', payload: _api });
// `ready` event is not emitted upon reconnection and is checked explicitly here.
_api.isReady.then(() => dispatch({ type: 'CONNECT_SUCCESS' }));
});
_api.on('ready', () => dispatch({ type: 'CONNECT_SUCCESS' }));
_api.on('error', (err) => dispatch({ type: 'CONNECT_ERROR', payload: err }));
};

const defaultValue = {
state: initialState,
};

const RelayApiContext = React.createContext(defaultValue);

const RelayApiContextProvider = (props: any) => {
const [state, dispatch] = useReducer(reducer, initialState);
const { toastError, toastSuccess } = useToast();

useEffect(() => {
state.apiError &&
toastError(
`Failed to connect to relay chain: error = ${state.apiError.toString()}`
);
}, [state.apiError]);

useEffect(() => {
state.apiState === 'READY' &&
toastSuccess('Successfully connected to relay chain');
}, [state.apiState]);

useEffect(() => {
connect(state, dispatch);
}, [process.env.RELAY_CHAIN_ENDPOINT]);

return (
<RelayApiContext.Provider value={{ state }}>
{props.children}
</RelayApiContext.Provider>
);
};
const useRelayApi = () => useContext(RelayApiContext);

export { RelayApiContextProvider, useRelayApi };
29 changes: 16 additions & 13 deletions src/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import theme from '@/utils/muiTheme';

import { Layout } from '@/components/Layout';

import { RelayApiContextProvider } from '@/contexts/RelayApi';
import { ToastProvider } from '@/contexts/Toast';
import { IdentityContractProvider } from '@/contracts';
import { AddressBookContractProvider } from '@/contracts/addressbook/context';
Expand Down Expand Up @@ -42,19 +43,21 @@ export default function MyApp(props: MyAppProps) {
{/* CssBaseline kickstart an elegant, consistent, and simple baseline to build upon. */}
<CssBaseline />
<ToastProvider>
<UseInkathonProvider
appName='DotFlow UI'
connectOnInit={false}
defaultChain={shibuya}
>
<IdentityContractProvider>
<AddressBookContractProvider>
<ConfirmProvider>
{getLayout(<Component {...pageProps} />)}
</ConfirmProvider>
</AddressBookContractProvider>
</IdentityContractProvider>
</UseInkathonProvider>
<RelayApiContextProvider>
<UseInkathonProvider
appName='DotFlow UI'
connectOnInit={false}
defaultChain={shibuya}
>
<IdentityContractProvider>
<AddressBookContractProvider>
<ConfirmProvider>
{getLayout(<Component {...pageProps} />)}
</ConfirmProvider>
</AddressBookContractProvider>
</IdentityContractProvider>
</UseInkathonProvider>
</RelayApiContextProvider>
</ToastProvider>
</ThemeProvider>
</CacheProvider>
Expand Down
4 changes: 2 additions & 2 deletions src/pages/identity.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import {
Grid,
Typography,
} from '@mui/material';
import styles from '@styles/pages/identity.module.scss';
import { useState } from 'react';
import '@styles/pages/identity.module.scss';

import { CreateIdentity, RemoveIdentity } from '@/components/Buttons';
import { AddressCard } from '@/components/Cards';
Expand All @@ -35,7 +35,7 @@ const IdentityPage = () => {

return (
<>
<Box className='identity-container'>
<Box className={styles.identityContainer}>
<Typography variant='h4' fontWeight={700}>
My Identity
</Typography>
Expand Down
114 changes: 86 additions & 28 deletions src/pages/transfer.tsx
Original file line number Diff line number Diff line change
@@ -1,39 +1,97 @@
import { Box, FormLabel, MenuItem, TextField } from '@mui/material';
import '@styles/pages/transfer.module.scss';
import {
Backdrop,
Box,
CircularProgress,
FormControl,
FormLabel,
MenuItem,
TextField,
} from '@mui/material';
import styles from '@styles/pages/transfer.module.scss';
import { useCallback, useEffect, useState } from 'react';

import { useRelayApi } from '@/contexts/RelayApi';
import { useToast } from '@/contexts/Toast';
import { useIdentity } from '@/contracts';

const TransferPage = () => {
const { networks } = useIdentity();
const [sourceChainId, setSourceChainId] = useState<number>();
const [destChainId, setDestChainId] = useState<number>();
const {
state: { api: relayApi },
} = useRelayApi();
const { toastSuccess, toastError } = useToast();
const [loadingAssets, setLoadingAssets] = useState(false);

const loadAssets = useCallback(async () => {
if (sourceChainId === undefined || destChainId === undefined) return;
setLoadingAssets(true);

if (sourceChainId !== destChainId) {
const hrmp = await relayApi.query.hrmp.hrmpChannels({
sender: sourceChainId,
recipient: destChainId,
});

if (hrmp.isEmpty) {
toastError(
"There's no HRMP channel open between the source and destination chain"
);
}
}

setLoadingAssets(false);
}, [sourceChainId, destChainId]);

useEffect(() => {
loadAssets();
}, [sourceChainId, destChainId]);

return (
<Box
sx={{
display: 'flex',
flexDirection: 'column',
background: 'white',
ml: 'auto',
mr: 'auto',
minWidth: 500,
px: '16px',
py: '24px',
}}
>
<FormLabel>List of networks</FormLabel>
<TextField
label='Select source chain'
select
sx={{ mt: '8px' }}
required
// value={networkId}
// onChange={(e) => setNetworkId(Number(e.target.value))}
<Box className={styles.transferContainer}>
<Box className='form-group'>
<FormControl className='form-item'>
<FormLabel>Source chain</FormLabel>
<TextField
label='Select source chain'
select
sx={{ mt: '8px' }}
required
value={sourceChainId || ''}
onChange={(e) => setSourceChainId(Number(e.target.value))}
>
{Object.values(networks).map((network, index) => (
<MenuItem value={network.paraId} key={index}>
{network.name}
</MenuItem>
))}
</TextField>
</FormControl>
<FormControl className='form-item'>
<FormLabel>Destination chain</FormLabel>
<TextField
label='Select destination chain'
select
sx={{ mt: '8px' }}
required
value={destChainId || ''}
onChange={(e) => setDestChainId(Number(e.target.value))}
>
{Object.values(networks).map((network, index) => (
<MenuItem value={network.paraId} key={index}>
{network.name}
</MenuItem>
))}
</TextField>
</FormControl>
</Box>
<Backdrop
sx={{ color: '#fff', zIndex: (theme) => theme.zIndex.drawer + 1 }}
open={loadingAssets}
>
{Object.entries(networks).map(([id, network], index) => (
<MenuItem value={id} key={index}>
{network.name}
</MenuItem>
))}
</TextField>
<CircularProgress color='inherit' />
</Backdrop>
</Box>
);
};
Expand Down
4 changes: 2 additions & 2 deletions styles/global.scss
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@

.MuiFormLabel-root {
font-size: 16px;
font-weight: 600;
// font-weight: 600;
line-height: 1.6;
color: #181336;
}
Expand All @@ -70,7 +70,7 @@
.form-item {
display: flex;
flex-direction: column;
gap: 4px;
gap: 8px;
}

.modal-buttons {
Expand Down
2 changes: 1 addition & 1 deletion styles/pages/identity.module.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.identity-container {
.identityContainer {
display: flex;
align-items: center;
justify-content: space-between;
Expand Down
9 changes: 9 additions & 0 deletions styles/pages/transfer.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.transferContainer {
display: flex;
flex-direction: column;
background: white;
margin-left: auto;
margin-right: auto;
min-width: 500px;
padding: 24px 16px;
}

0 comments on commit 09c594d

Please sign in to comment.