Skip to content

Commit

Permalink
Merge branch 'fix/misc-bugs' into 'dev'
Browse files Browse the repository at this point in the history
fix(watcher-app): misc bugs

Closes #67

See merge request ergo/rosen-bridge/ui!67
  • Loading branch information
zargarzadehm committed Sep 26, 2023
2 parents 24799ac + 8edc9b2 commit 7343839
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 40 deletions.
4 changes: 2 additions & 2 deletions apps/watcher/app/(home)/@infoWidgets/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ const InfoWidgets = () => {
<InfoWidgetCard
title="ERG"
value={
ergToken?.amount
ergToken?.amount !== undefined
? getDecimalString(ergToken.amount.toString(), ergToken.decimals)
: ''
}
Expand All @@ -108,7 +108,7 @@ const InfoWidgets = () => {
<InfoWidgetCard
title="RSN"
value={
rsnToken?.amount
rsnToken?.amount !== undefined
? getDecimalString(rsnToken.amount.toString(), rsnToken.decimals)
: ''
}
Expand Down
4 changes: 2 additions & 2 deletions apps/watcher/app/actions/@form/lock/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const LockForm = () => {
>('/permit', mutator);

useEffect(() => {
if (!isRsnTokenLoading && !rsnToken) {
if (!isRsnTokenLoading && !rsnToken?.amount) {
setAlertData({
severity: 'error',
message: 'RSN token does not exist',
Expand Down Expand Up @@ -90,7 +90,7 @@ const LockForm = () => {
</AlertCard>
);

const disabled = isRsnTokenLoading || !rsnToken;
const disabled = isRsnTokenLoading || !rsnToken?.amount;

const renderTokenAmountTextField = () => (
<TokenAmountTextField
Expand Down
29 changes: 18 additions & 11 deletions apps/watcher/app/actions/@form/unlock/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,14 @@ import {
} from '@rosen-bridge/ui-kit';
import { fetcher, mutator } from '@rosen-ui/swr-helpers';
import { TokenInfo } from '@rosen-ui/types';
import { getNonDecimalString } from '@rosen-ui/utils';

import TokenAmountTextField, {
TokenAmountCompatibleFormSchema,
} from '../../TokenAmountTextField';

import useRsnToken from '@/_hooks/useRsnToken';

import {
ApiInfoResponse,
ApiPermitRequestBody,
Expand All @@ -31,17 +34,20 @@ const UnlockForm = () => {
fetcher,
);

const { rsnToken, isLoading: isRsnTokenLoading } = useRsnToken();

const rwtPartialToken = useMemo<
Pick<TokenInfo, 'amount' | 'decimals'> | undefined
>(
() =>
info?.permitCount.active
? {
amount: info.permitCount.active,
decimals: 0,
decimals: rsnToken?.decimals ?? 0,
name: rsnToken?.name,
}
: undefined,
[info?.permitCount],
[info, rsnToken],
);

const [alertData, setAlertData] = useState<{
Expand All @@ -63,24 +69,22 @@ const UnlockForm = () => {
});
const { handleSubmit } = formMethods;

const noRwtToken = !!rwtPartialToken && !rwtPartialToken.amount;

useEffect(() => {
if (noRwtToken) {
if (!isInfoLoading && !rwtPartialToken?.amount) {
setAlertData({
severity: 'error',
message: 'no Permit',
message: "You don't have any permit tokens",
});
} else {
setAlertData(null);
}
}, [noRwtToken]);
}, [isInfoLoading, rwtPartialToken?.amount]);

const onSubmit: SubmitHandler<TokenAmountCompatibleFormSchema> = async (
data,
) => {
try {
const count = data.amount;
const count = getNonDecimalString(data.amount, rsnToken?.decimals ?? 0);
const response = await trigger({ count });

if (response?.txId) {
Expand Down Expand Up @@ -112,10 +116,13 @@ const UnlockForm = () => {
</AlertCard>
);

const disabled =
isInfoLoading || isRsnTokenLoading || !rwtPartialToken?.amount;

const renderTokenAmountTextField = () => (
<TokenAmountTextField
disabled={isInfoLoading || noRwtToken}
loading={isInfoLoading}
disabled={disabled}
loading={isInfoLoading || isRsnTokenLoading}
token={rwtPartialToken}
/>
);
Expand All @@ -129,7 +136,7 @@ const UnlockForm = () => {
{renderTokenAmountTextField()}
</Grid>

<SubmitButton loading={isUnlockPending} disabled={noRwtToken}>
<SubmitButton loading={isUnlockPending} disabled={disabled}>
Unlock
</SubmitButton>
</form>
Expand Down
51 changes: 36 additions & 15 deletions apps/watcher/app/actions/@form/withdraw/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ import TokenAmountTextField, {
TokenAmountCompatibleFormSchema,
} from '../../TokenAmountTextField';

import useToken from '@/_hooks/useToken';

import {
ApiAddressAssetsResponse,
ApiWithdrawRequestBody,
Expand All @@ -43,7 +45,14 @@ interface Form extends TokenAmountCompatibleFormSchema {

const WithdrawForm = () => {
const { data, isLoading: isTokensListLoading } =
useSWR<ApiAddressAssetsResponse>('/address/assets', fetcher);
useSWR<ApiAddressAssetsResponse>('/address/assets', fetcher, {});

const { token: ergToken, isLoading: isErgTokenLoading } = useToken('erg');

const tokens = useMemo(
() => data?.items.filter((token) => !!token.amount),
[data],
);

const [alertData, setAlertData] = useState<{
severity: AlertProps['severity'];
Expand All @@ -57,30 +66,39 @@ const WithdrawForm = () => {
ApiWithdrawRequestBody
>('/withdraw', mutator);

useEffect(() => {
if (!isErgTokenLoading && !ergToken?.amount) {
setAlertData({
severity: 'error',
message: 'Your wallet is empty. There is nothing to withdraw.',
});
}
}, [isErgTokenLoading, ergToken]);

const formMethods = useForm({
defaultValues: {
address: '',
tokenId: data?.items?.[0].tokenId ?? '',
tokenId: tokens?.[0]?.tokenId ?? '',
amount: '',
},
});
const { handleSubmit, control, resetField, register, setValue } = formMethods;
const { handleSubmit, control, resetField, register } = formMethods;

const { field: tokenIdField } = useController({
control,
name: 'tokenId',
});

const selectedToken = useMemo(
() => data?.items?.find((token) => token.tokenId === tokenIdField.value),
[data, tokenIdField.value],
() => tokens?.find((token) => token.tokenId === tokenIdField.value),
[tokens, tokenIdField.value],
);

useEffect(() => {
if (data && !tokenIdField.value) {
resetField('tokenId', { defaultValue: data?.items[0].tokenId });
if (tokens && !tokenIdField.value) {
resetField('tokenId', { defaultValue: tokens?.[0]?.tokenId ?? '' });
}
}, [data, resetField, tokenIdField.value]);
}, [tokens, resetField, tokenIdField.value]);

const onSubmit: SubmitHandler<Form> = async (data) => {
try {
Expand Down Expand Up @@ -122,10 +140,14 @@ const WithdrawForm = () => {
</AlertCard>
);

const disabled =
isTokensListLoading || isErgTokenLoading || !ergToken?.amount;

const renderAddressTextField = () => (
<TextField
autoFocus
label="Address"
disabled={disabled}
{...register('address', { required: true })}
/>
);
Expand All @@ -134,7 +156,7 @@ const WithdrawForm = () => {
<TextField
label="Token"
select={!isTokensListLoading}
disabled={isTokensListLoading}
disabled={disabled}
InputProps={{
startAdornment: isTokensListLoading && (
<InputAdornment position="start">
Expand All @@ -144,7 +166,7 @@ const WithdrawForm = () => {
}}
{...tokenIdField}
>
{data?.items?.map((token) => (
{tokens?.map((token) => (
<MenuItem value={token.tokenId} key={token.tokenId}>
{token.name ?? TOKEN_NAME_PLACEHOLDER}
&nbsp;
Expand All @@ -159,10 +181,7 @@ const WithdrawForm = () => {
);

const renderTokenAmountTextField = () => (
<TokenAmountTextField
disabled={isTokensListLoading}
token={selectedToken}
/>
<TokenAmountTextField disabled={disabled} token={selectedToken} />
);

return (
Expand All @@ -183,7 +202,9 @@ const WithdrawForm = () => {
{renderTokenAmountTextField()}
</Grid>
</Grid>
<SubmitButton loading={isWithdrawPending}>Withdraw</SubmitButton>
<SubmitButton disabled={disabled} loading={isWithdrawPending}>
Withdraw
</SubmitButton>
</form>
</FormProvider>
);
Expand Down
17 changes: 12 additions & 5 deletions apps/watcher/app/actions/TokenAmountTextField.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect } from 'react';
import { MouseEventHandler, useEffect } from 'react';
import { useController, useFormContext } from 'react-hook-form';

import {
Expand All @@ -18,7 +18,7 @@ export interface TokenAmountCompatibleFormSchema {
interface TokenAmountTextFieldProps {
disabled: boolean;
loading?: boolean;
token: Pick<TokenInfo, 'amount' | 'decimals'> | undefined;
token: Pick<TokenInfo, 'amount' | 'decimals' | 'name'> | undefined;
}
/**
* render a react-hook-form compatible text field for token amount input,
Expand Down Expand Up @@ -58,8 +58,11 @@ const TokenAmountTextField = ({
const getMaxAvailableTokenAmount = () =>
getDecimalString(token!.amount.toString(), token!.decimals);

const setAmountToMaxAvailable = () =>
const setAmountToMaxAvailable: MouseEventHandler = (event) => {
event.preventDefault();

setAmountFieldValue(getMaxAvailableTokenAmount());
};

return (
<TextField
Expand Down Expand Up @@ -96,14 +99,18 @@ const TokenAmountTextField = ({
<Link component="button" onClick={setAmountToMaxAvailable}>
{getMaxAvailableTokenAmount()}
</Link>{' '}
available
{token.name} available
</>
)
}
InputProps={{
endAdornment: token && (
<InputAdornment position="end">
<Button size="small" onClick={setAmountToMaxAvailable}>
<Button
size="small"
onClick={setAmountToMaxAvailable}
disabled={disabled}
>
Max
</Button>
</InputAdornment>
Expand Down
24 changes: 24 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions packages/utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,15 @@
"type-check": "tsc --noEmit"
},
"devDependencies": {
"@types/lodash-es": "^4.17.9",
"@typescript-eslint/eslint-plugin": "^5.30.7",
"@typescript-eslint/parser": "^5.26.0",
"eslint": "^8.16.0",
"eslint-config-prettier": "^9.0.0",
"prettier": "^3.0.2",
"typescript": "^5.0.0"
},
"dependencies": {
"lodash-es": "^4.17.21"
}
}
14 changes: 9 additions & 5 deletions packages/utils/src/decimals.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
import { trimEnd } from 'lodash-es';

/**
* convert a raw value to a string representation of the same value but
* considering decimals
* considering decimals (removing any leading redundant zeros)
*
* @param value
* @param decimals
*
* @example
* getDecimalString('123', 2) === '1.23' // true
* getDecimalString('1230', 2) === '12.3' // true
*/
export const getDecimalString = (value: string, decimals: number) => {
if (!decimals) return value;

if (value.length > decimals) {
return `${value.slice(0, -1 * decimals)}.${value.slice(-1 * decimals)}`;
}
const untrimmedResult =
value.length > decimals
? `${value.slice(0, -decimals)}.${value.slice(-decimals)}`
: `0.${value.padStart(decimals, '0')}`;

return `0.${'0'.repeat(decimals - value.length)}${value}`;
return trimEnd(trimEnd(untrimmedResult, '0'), '.') || '0';
};

/**
Expand Down

0 comments on commit 7343839

Please sign in to comment.