Skip to content

Commit

Permalink
Merge pull request #6 from ar-io/PE-5965-gateways-page-join-network-m…
Browse files Browse the repository at this point in the history
…anage-gateway

PE-5965: gateways page (start gateway, gateway information banner)
  • Loading branch information
kunstmusik authored May 10, 2024
2 parents 0c7ada3 + cdfe25f commit 721dd36
Show file tree
Hide file tree
Showing 41 changed files with 1,592 additions and 151 deletions.
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"files.insertFinalNewline": true
}
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,19 @@
"vis": "yarn vite-bundle-visualizer"
},
"dependencies": {
"@ar.io/sdk": "^1.0.3",
"@ar.io/sdk": "^1.0.6",
"@fontsource/rubik": "^5.0.19",
"@headlessui/react": "^1.7.19",
"@radix-ui/react-tooltip": "^1.0.7",
"@sentry/browser": "^7.101.1",
"@sentry/react": "^7.101.1",
"arweave": "^1.15.0",
"axios": "^1.6.7",
"axios-retry": "^4.0.0",
"lottie-react": "^2.4.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hot-toast": "^2.4.1",
"react-router-dom": "^6.22.1",
"tailwindcss-animate": "^1.0.7",
"winston": "^3.11.0",
Expand Down
16 changes: 8 additions & 8 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,27 @@ import AppRouterLayout from './layout/AppRouterLayout';
import Loading from './pages/Loading';
import NotFound from './pages/NotFound';

const Dashboard = React.lazy(() => import('./pages/Dashboard'));
// const Dashboard = React.lazy(() => import('./pages/Dashboard'));
const Gateways = React.lazy(() => import('./pages/Gateways'));
const Staking = React.lazy(() => import('./pages/Staking'));
const Observers = React.lazy(() => import('./pages/Observers'));
// const Staking = React.lazy(() => import('./pages/Staking'));
// const Observers = React.lazy(() => import('./pages/Observers'));

const sentryCreateBrowserRouter = wrapCreateBrowserRouter(createBrowserRouter);

function App() {
const router = sentryCreateBrowserRouter(
createRoutesFromElements(
<Route element={<AppRouterLayout />} errorElement={<NotFound />}>
<Route index path="/" element={<Navigate to="/dashboard" />} />
<Route
<Route index path="/" element={<Navigate to="/gateways" />} />
{/* <Route
path="dashboard"
element={
<Suspense fallback={<Loading />}>
<Dashboard />
</Suspense>
}
/>
,
, */}
<Route
path="gateways"
element={
Expand All @@ -45,7 +45,7 @@ function App() {
}
/>
,
<Route
{/* <Route
path="staking"
element={
<Suspense fallback={<Loading />}>
Expand All @@ -62,7 +62,7 @@ function App() {
</Suspense>
}
/>
,
, */}
<Route path="*" element={<Navigate to="/" />} />
</Route>,
),
Expand Down
1 change: 1 addition & 0 deletions src/animations/ario-spinner.json

Large diffs are not rendered by default.

31 changes: 16 additions & 15 deletions src/components/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,28 +28,27 @@ export const Button = ({
onClick?: MouseEventHandler;
}) => {
if (buttonType === ButtonType.PRIMARY) {
const classNames = [
'rounded-md bg-gradient-to-b from-btn-primary-outer-gradient-start to-btn-primary-outer-gradient-end p-px',
className,
].join(' ');

const btnClassNames =
'inline-flex size-full items-center gap-[11px] rounded-md bg-btn-primary-base bg-gradient-to-b from-btn-primary-gradient-start to-btn-primary-gradient-end px-[11px] py-[5px] shadow-inner';

return (
<div
className="rounded-md bg-gradient-to-b from-btn-primary-outer-gradient-start
to-btn-primary-outer-gradient-end p-px"
>
<div className={classNames}>
<button
title={title}
ref={forwardRef}
className="inline-flex items-center justify-start
gap-[11px] rounded-md bg-btn-primary-base bg-gradient-to-b
from-btn-primary-gradient-start to-btn-primary-gradient-end
px-[11px] py-[5px] shadow-inner"
className={
btnClassNames + (icon ? ' justify-start' : ' justify-center')
}
onClick={onClick}
>
{icon}
{text && (
<div
className="bg-gradient-to-r from-gradient-primary-start to-gradient-primary-end
bg-clip-text text-sm leading-tight text-transparent"
>
{text}
</div>
<div className="text-gradient text-sm leading-tight">{text}</div>
)}
</button>
</div>
Expand All @@ -76,7 +75,9 @@ export const Button = ({
>
{icon}
{text && (
<div className="flex grow items-center space-x-[4px] text-left leading-none">
<div
className={`flex grow items-center space-x-[4px] leading-none ${icon ? 'justify-start' : 'justify-center'}`}
>
{text} {rightIcon}
</div>
)}
Expand Down
2 changes: 1 addition & 1 deletion src/components/Profile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ const Profile = () => {
<Popover.Button as={CustomPopoverButton} />

<Popover.Panel
className="absolute right-0 z-10 mt-[10px] w-[240px]
className="absolute right-0 z-50 mt-[10px] w-[240px]
rounded-[12px] border border-grey-800 bg-grey-1000 px-[16px] text-sm shadow-md"
>
<div className="flex gap-[8px] py-[20px]">
Expand Down
46 changes: 43 additions & 3 deletions src/components/WalletProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import { ArIO } from '@ar.io/sdk/web';
import { ARNS_REGISTRY_ADDRESS } from '@src/constants';
import { useEffectOnce } from '@src/hooks/useEffectOnce';
import { ArConnectWalletConnector } from '@src/services/wallets/ArConnectWalletConnector';
import { useGlobalState } from '@src/store';
import { KEY_WALLET_TYPE } from '@src/store/persistent';
import { WALLET_TYPES } from '@src/types';
import { mioToIo } from '@src/utils';
import { ArweaveTransactionID } from '@src/utils/ArweaveTransactionId';
import { showErrorToast } from '@src/utils/toast';
import Ar from 'arweave/web/ar';
import { ReactElement, useEffect } from 'react';

Expand All @@ -15,10 +19,16 @@ const WalletProvider = ({ children }: { children: ReactElement }) => {
const setWalletStateInitialized = useGlobalState(
(state) => state.setWalletStateInitialized,
);
const setGateway = useGlobalState((state) => state.setGateway);

const wallet = useGlobalState((state) => state.wallet);
const updateWallet = useGlobalState((state) => state.updateWallet);
const setBalances = useGlobalState((state) => state.setBalances);
const arweave = useGlobalState((state) => state.arweave);
const arIOReadSDK = useGlobalState((state) => state.arIOReadSDK);
const setArIOWriteableSDK = useGlobalState(
(state) => state.setArIOWriteableSDK,
);

useEffect(() => {
window.addEventListener('arweaveWalletLoaded', updateIfConnected);
Expand Down Expand Up @@ -48,16 +58,46 @@ const WalletProvider = ({ children }: { children: ReactElement }) => {

setBalances(arBalance, ioBalance);
} catch (error) {
// eventEmitter.emit('error', error);
showErrorToast(`${error}`);
}
};

updateBalances(walletAddress);
}
}, [walletAddress, blockHeight, arIOReadSDK, arweave, setBalances]);

useEffect(() => {
if (wallet) {
const signer = wallet.signer;

if (signer) {
const writeable = ArIO.init({
contractTxId: ARNS_REGISTRY_ADDRESS.toString(),
signer,
});
setArIOWriteableSDK(writeable);
}
} else {
setArIOWriteableSDK(undefined);
}
}, [setArIOWriteableSDK, wallet]);

useEffect(() => {
if (walletAddress) {
const update = async () => {
const gateway = await arIOReadSDK.getGateway({
address: walletAddress.toString(),
});
setGateway(gateway);
};
update();
} else {
setGateway(undefined);
}
}, [arIOReadSDK, setGateway, walletAddress]);

const updateIfConnected = async () => {
const walletType = window.localStorage.getItem('walletType');
const walletType = window.localStorage.getItem(KEY_WALLET_TYPE);

try {
if (walletType === WALLET_TYPES.ARCONNECT) {
Expand All @@ -67,7 +107,7 @@ const WalletProvider = ({ children }: { children: ReactElement }) => {
updateWallet(address, connector);
}
} catch (error) {
// eventEmitter.emit('error', error);
showErrorToast(`${error}`);
} finally {
setWalletStateInitialized(true);
}
Expand Down
134 changes: 134 additions & 0 deletions src/components/forms/FormRow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import * as Tooltip from '@radix-ui/react-tooltip';
import { FormErrorIcon } from '../icons';

export enum RowType {
TOP,
MIDDLE,
BOTTOM,
SINGLE,
}

const ROUND_STYLES = {
[RowType.TOP]: 'rounded-t-md',
[RowType.BOTTOM]: 'rounded-b-md',
[RowType.SINGLE]: 'rounded-md',
[RowType.MIDDLE]: '',
};

const FormRow = ({
formPropertyName,
formState,
placeholder,
enabled = true,
setFormState,
errorMessages,
setErrorMessages,
label,
rowType = RowType.MIDDLE,
leftComponent,
rightComponent,
validateProperty,
}: {
formPropertyName: string;
placeholder?: string;
enabled?: boolean;
formState: Record<string, string>;
setFormState: (formState: Record<string, string>) => void;
errorMessages: Record<string, string>;
setErrorMessages: (errorMessages: Record<string, string>) => void;
label: string;
rowType?: RowType;
leftComponent?: JSX.Element;
rightComponent?: JSX.Element;
validateProperty: (value: string) => string | undefined;
}) => {
const roundStyle = ROUND_STYLES[rowType];

const errorMessage = errorMessages[formPropertyName];
const hasError = enabled && errorMessage?.trim().length > 0;

return (
<>
<div className="bg-grey-900 pb-px">
<div className="h-[39px] bg-grey-1000 px-[24px] py-[12px] text-xs text-low">
{label}
</div>
</div>
<div>
<div
className={[
'h-[40px] overflow-hidden from-gradient-primary-start to-gradient-primary-end p-px focus-within:bg-gradient-to-r',
hasError
? 'bg-red-600'
: 'bg-grey-800 focus-within:p-px',
roundStyle,
].join(' ')}
>
<div
className={`flex h-[38px] items-center gap-[3px] overflow-hidden bg-grey-1000 ${roundStyle}`}
>
{leftComponent}
<input
className={
'size-full overflow-hidden border-none bg-grey-1000 px-[24px] py-[12px] text-sm text-mid outline-none placeholder:text-grey-600 focus:text-high'
}
type="text"
contentEditable={enabled}
readOnly={!enabled}
placeholder={placeholder}
value={enabled ? formState[formPropertyName] : ''}
onChange={(e) => {
if (hasError) {
const cleared = { ...errorMessages };
delete cleared[formPropertyName];
setErrorMessages(cleared);
}
setFormState({
...formState,
[formPropertyName]: e.target.value,
});
}}
onBlur={() => {
const errMessage = validateProperty(
formState[formPropertyName],
);
if (errMessage) {
setErrorMessages({
...errorMessages,
[formPropertyName]: errMessage,
});
} else {
const cleared = { ...errorMessages };
delete cleared[formPropertyName];
setErrorMessages(cleared);
}
}}
/>
{hasError && (
<div className="relative flex px-[12px] text-red-600">
<Tooltip.Provider>
<Tooltip.Root>
<Tooltip.Trigger>
<FormErrorIcon />
</Tooltip.Trigger>
<Tooltip.Portal>
<Tooltip.Content className="z-50 w-fit rounded-md bg-red-1000 px-[24px] py-[12px]">
<Tooltip.Arrow className="fill-red-1000" />
<div className="text-sm text-red-600">
{errorMessage}
</div>
</Tooltip.Content>
</Tooltip.Portal>
</Tooltip.Root>
</Tooltip.Provider>
</div>
)}
{rightComponent}
</div>
</div>
</div>
</>
);
};

export default FormRow;
31 changes: 31 additions & 0 deletions src/components/forms/FormSwitch.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Switch } from '@headlessui/react';

const FormSwitch = ({
checked,
onChange,
title,
}: {
checked: boolean;
onChange: (checked: boolean) => void;
title: string;
}) => {
return (
<Switch
className={`${
checked ? 'bg-green-600' : 'bg-grey-800'
} relative inline-flex h-[18px] w-[30px] items-center rounded-full border border-transparent-100-8`}
checked={checked}
onChange={onChange}
title={title}
>
<span className="sr-only"></span>
<span
className={`${
checked ? 'translate-x-[14px]' : 'translate-x-[2px]'
} inline-block size-[12px] rounded-full ${checked ? 'bg-neutrals-1100' : 'bg-neutrals-100'} transition`}
/>
</Switch>
);
};

export default FormSwitch;
Loading

0 comments on commit 721dd36

Please sign in to comment.