Skip to content

Commit

Permalink
Merge pull request #8 from ar-io/PE-6149-delegated-staking-landing-pa…
Browse files Browse the repository at this point in the history
…ge-and-stake-unstake-modal

PE-6149: delegated staking landing page and stake/unstake modal
  • Loading branch information
kunstmusik authored May 30, 2024
2 parents f113a39 + fc79c94 commit 1c24534
Show file tree
Hide file tree
Showing 29 changed files with 1,801 additions and 821 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build_and_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
matrix:
step: [
'lint:check',
#'test',
'test',
'build',
]
steps:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:
matrix:
step: [
'lint:check',
#'test',
'test',
'build',
]
steps:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/production.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
matrix:
step: [
'lint:check',
#'test',
'test',
'build',
]
steps:
Expand Down
10 changes: 9 additions & 1 deletion jest.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,16 @@
"\\.(css|gif|png)$": "jest-transform-stub",
"\\.svg": "<rootDir>/tests/common/mocks/svg.js",
"^@tests/(.*)$": "<rootDir>/tests/$1",
"^@src/(.*)$": "<rootDir>/src/$1"
"^@src/(.*)$": "<rootDir>/src/$1",
"@ar.io/sdk/web": "<rootDir>/node_modules/@ar.io/sdk/lib/cjs/web/index.js",
"warp-contracts": "<rootDir>/node_modules/warp-contracts/lib/cjs/index.js"
},
"transform": {
"^.+\\.(ts|tsx|js|jsx|mjs)$": ["ts-jest", { "useESM": true }]
},
"transformIgnorePatterns": [
"/node_modules/(?!arbundles|arweave-wallet-connector).+\\.js$"
],
"moduleDirectories": ["node_modules", "assets"],
"testPathIgnorePatterns": ["tests/common/"],
"coverageThreshold": {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"vis": "yarn vite-bundle-visualizer"
},
"dependencies": {
"@ar.io/sdk": "^1.0.7-alpha.2",
"@ar.io/sdk": "^1.0.7",
"@fontsource/rubik": "^5.0.19",
"@headlessui/react": "^1.7.19",
"@radix-ui/react-tooltip": "^1.0.7",
Expand Down
6 changes: 3 additions & 3 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import PendingInteractionsProvider from './components/PendingInteractionsProvide
// const Dashboard = React.lazy(() => import('./pages/Dashboard'));
const Gateways = React.lazy(() => import('./pages/Gateways'));
const Gateway = React.lazy(() => import('./pages/Gateway'));
// const Staking = React.lazy(() => import('./pages/Staking'));
const Staking = React.lazy(() => import('./pages/Staking'));
// const Observers = React.lazy(() => import('./pages/Observers'));

const sentryCreateBrowserRouter = wrapCreateBrowserRouter(createBrowserRouter);
Expand Down Expand Up @@ -58,7 +58,7 @@ function App() {
}
/>
,
{/* <Route
<Route
path="staking"
element={
<Suspense fallback={<Loading />}>
Expand All @@ -67,7 +67,7 @@ function App() {
}
/>
,
<Route
{/*<Route
path="observers"
element={
<Suspense fallback={<Loading />}>
Expand Down
7 changes: 6 additions & 1 deletion src/components/Profile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,12 @@ const Profile = () => {
text="Connect"
onClick={() => setIsModalOpen(true)}
/>
<ConnectModal open={isModalOpen} onClose={() => setIsModalOpen(false)} />
{isModalOpen && (
<ConnectModal
open={isModalOpen}
onClose={() => setIsModalOpen(false)}
/>
)}
</div>
) : (
<div></div>
Expand Down
33 changes: 33 additions & 0 deletions src/components/forms/ErrorMessageIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import * as Tooltip from '@radix-ui/react-tooltip';
import { FormErrorIcon } from '../icons';

const ErrorMessageIcon = ({
errorMessage,
tooltipPadding = 0,
}: {
errorMessage: string;
tooltipPadding?: number;
}) => {

const marginBottom = tooltipPadding ? `mb-[${tooltipPadding}px]` : '';

return (
<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 max-w-[400px] rounded-md bg-red-1000 px-[24px] py-[12px]">
<Tooltip.Arrow className={`fill-red-1000 ${marginBottom}`} />
<div className="text-sm text-red-600">{errorMessage}</div>
</Tooltip.Content>
</Tooltip.Portal>
</Tooltip.Root>
</Tooltip.Provider>
</div>
);
};

export default ErrorMessageIcon;
53 changes: 18 additions & 35 deletions src/components/forms/FormRow.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import * as Tooltip from '@radix-ui/react-tooltip';
import { FormErrorIcon, ResetIcon } from '../icons';
import { ResetIcon } from '../icons';
import ErrorMessageIcon from './ErrorMessageIcon';
import FormSwitch from './FormSwitch';

export enum RowType {
TOP,
MIDDLE,
BOTTOM,
SINGLE,
LAST // special hack for last row due to rounding of container vs form
LAST, // special hack for last row due to rounding of container vs form
}

const ROUND_STYLES = {
Expand Down Expand Up @@ -71,7 +71,7 @@ const FormRow = ({
const cleared = { ...errorMessages };
delete cleared[formPropertyName];
setErrorMessages(cleared);
}
};

const resetFormValue = () => {
if (initialState) {
Expand All @@ -83,7 +83,6 @@ const FormRow = ({
}
};


return (
<>
<div className="bg-grey-900 pb-px">
Expand Down Expand Up @@ -113,11 +112,11 @@ const FormRow = ({
title={`${value ? 'Disable' : 'Enable'} ${label}`}
/>

{modified &&

// using fixed position to avoid the modified dot from being clipped by the overflow-hidden parent
// may need to revisit if form parent placement changes to not be flush right with viewport
<ModifiedDot className="fixed right-[17.5px] z-10" />}
{modified && (
// using fixed position to avoid the modified dot from being clipped by the overflow-hidden parent
// may need to revisit if form parent placement changes to not be flush right with viewport
<ModifiedDot className="fixed right-[17.5px] z-10" />
)}
</div>
) : (
<div
Expand Down Expand Up @@ -164,34 +163,18 @@ const FormRow = ({
}
}}
/>
{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>
)}
{enabled && initialState && initialState[formPropertyName] !== value && (
<button className="pr-[16px]" onClick={resetFormValue}>
<ResetIcon />
</button>
)}
{hasError && <ErrorMessageIcon errorMessage={errorMessage} />}
{enabled &&
initialState &&
initialState[formPropertyName] !== value && (
<button className="pr-[16px]" onClick={resetFormValue}>
<ResetIcon />
</button>
)}
{rightComponent}
{enabled && modified && (
// using fixed position to avoid the modified dot from being clipped by the overflow-hidden parent
// may need to revisit if form parent placement changes to not be flush right with viewport
// may need to revisit if form parent placement changes to not be flush right with viewport
<ModifiedDot className="fixed right-[17.5px] z-10" />
)}
</div>
Expand Down
52 changes: 44 additions & 8 deletions src/components/forms/validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,20 @@ export const validateIOAmount = (
max?: number,
): FormValidationFunction => {
return (v: string) => {
const value = parseFloat(v);
const value = +v;

if(max) {
return value < min || value > max || isNaN(v as unknown as number)
if (max) {
if (isNaN(value)) {
return `${propertyName} must be a number.`;
} else if (max <= min && value < min) {
return `${propertyName} must be a number >= ${min} IO.`;
}

return value < min || value > max
? `${propertyName} must be a number from ${min} to ${max} IO.`
: undefined;
}
return value < min || isNaN(v as unknown as number)
return value < min || isNaN(value)
? `${propertyName} must be a number >= ${min} IO.`
: undefined;
};
Expand All @@ -71,12 +77,42 @@ export const validateNumberRange = (
max: number,
): FormValidationFunction => {
return (v: string) => {
const value = parseFloat(v);
const value = +v;

// because parseFloat parses initial valid numbers then discards any remaining invalid text,
// need to use isNan(v as unknown as number) to check for invalid text like "3adsfwe".
return value < min || value > max || isNaN(v as unknown as number)
return value < min || value > max || isNaN(value)
? `${propertyName} must be a number from ${min} to ${max}.`
: undefined;
};
};

export const validateUnstakeAmount = (
propertyName: string,
currentStake: number,
minDelegatedStake: number,
): FormValidationFunction => {
return (v: string) => {
const value = +v;

if (isNaN(value) || v.length === 0) {
return `${propertyName} must be a number.`;
}

if (value < 1) {
return `${propertyName} must be at least 1 IO.`;
}

if (value > currentStake) {
return `${propertyName} cannot be greater than your current stake of ${currentStake} IO.`;
}

if (
currentStake - value < minDelegatedStake &&
value != minDelegatedStake &&
value != currentStake
) {
return `Withdrawing this amount will put you below the gateway's minimum stake of ${minDelegatedStake} IO. You can either: withdraw a smaller amount so your remaining stake is above the minimum - or - withdraw your full delegated stake.`;
}

return undefined;
};
};
2 changes: 2 additions & 0 deletions src/components/icons/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import OpenDrawerIcon from './open_drawer.svg?react';
import PinkArrowIcon from './pink_arrow.svg?react';
import ResetIcon from './reset.svg?react';
import StakingIcon from './staking.svg?react';
import StakingSplash from './staking_splash.svg?react';
import StartGatewayCubes from './start_gateway_cubes.svg?react';
import StatsArrowIcon from './stats_arrow.svg?react';
import SuccessCheck from './success_check.svg?react';
Expand Down Expand Up @@ -52,6 +53,7 @@ export {
PinkArrowIcon,
ResetIcon,
StakingIcon,
StakingSplash,
StartGatewayCubes,
StatsArrowIcon,
SuccessCheck,
Expand Down
65 changes: 65 additions & 0 deletions src/components/icons/staking_splash.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 1c24534

Please sign in to comment.