Skip to content

Commit

Permalink
Merge branch 'main' of github.com:thesis/acre into action-form-input-…
Browse files Browse the repository at this point in the history
…field-improvements
  • Loading branch information
kkosiorowska committed Aug 21, 2024
2 parents 971a375 + 183e193 commit 48411ba
Show file tree
Hide file tree
Showing 17 changed files with 159 additions and 45 deletions.
2 changes: 1 addition & 1 deletion dapp/src/components/TransactionModal/ActionFormModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ function ActionFormModal({ type }: { type: ActionFlowType }) {
<>
{!isLoading && <ModalCloseButton />}
<ModalHeader>{heading}</ModalHeader>
<ModalBody>
<ModalBody px={10}>
<Box w="100%">
<FormComponent onSubmitForm={handleSubmitFormWrapper} />
</Box>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import TokenAmountForm from "#/components/shared/TokenAmountForm"
import { TokenAmountFormValues } from "#/components/shared/TokenAmountForm/TokenAmountFormBase"
import { useMinDepositAmount, useWallet } from "#/hooks"
import { FormSubmitButton } from "#/components/shared/Form"
import { BaseFormProps } from "#/types"
import { ACTION_FLOW_TYPES, BaseFormProps } from "#/types"
import { fixedPointNumberToString, getCurrencyByType } from "#/utils"
import StakeDetails from "./StakeDetails"

function StakeFormModal({
Expand All @@ -12,11 +13,16 @@ function StakeFormModal({
const minDepositAmount = useMinDepositAmount()
const { balance: tokenBalance } = useWallet()

const { decimals } = getCurrencyByType("bitcoin")
const inputPlaceholder = `Minimum ${fixedPointNumberToString(minDepositAmount, decimals)} BTC`
const tokenAmountLabel = "Wallet balance"

return (
<TokenAmountForm
tokenBalanceInputPlaceholder="BTC"
actionType={ACTION_FLOW_TYPES.STAKE}
tokenBalanceInputPlaceholder={inputPlaceholder}
tokenAmountLabel={tokenAmountLabel}
currency="bitcoin"
fiatCurrency="usd"
tokenBalance={tokenBalance ?? 0n}
minTokenAmount={minDepositAmount}
onSubmitForm={onSubmitForm}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ import React from "react"
import TokenAmountForm from "#/components/shared/TokenAmountForm"
import { TokenAmountFormValues } from "#/components/shared/TokenAmountForm/TokenAmountFormBase"
import { FormSubmitButton } from "#/components/shared/Form"
import { BaseFormProps, PROCESS_STATUSES } from "#/types"
import { ACTION_FLOW_TYPES, BaseFormProps, PROCESS_STATUSES } from "#/types"
import {
useActionFlowStatus,
useBitcoinPosition,
useMinWithdrawAmount,
} from "#/hooks"
import { fixedPointNumberToString, getCurrencyByType } from "#/utils"
import UnstakeDetails from "./UnstakeDetails"

function UnstakeFormModal({
Expand All @@ -18,11 +19,16 @@ function UnstakeFormModal({
const minTokenAmount = useMinWithdrawAmount()
const status = useActionFlowStatus()

const { decimals } = getCurrencyByType("bitcoin")
const inputPlaceholder = `Minimum ${fixedPointNumberToString(minTokenAmount, decimals)} BTC`
const tokenAmountLabel = "Acre balance"

return (
<TokenAmountForm
tokenBalanceInputPlaceholder="BTC"
actionType={ACTION_FLOW_TYPES.UNSTAKE}
tokenBalanceInputPlaceholder={inputPlaceholder}
tokenAmountLabel={tokenAmountLabel}
currency="bitcoin"
fiatCurrency="usd"
tokenBalance={balance}
minTokenAmount={minTokenAmount}
onSubmitForm={onSubmitForm}
Expand Down
11 changes: 7 additions & 4 deletions dapp/src/components/shared/ActivitiesList/ActivitiesList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ function ActivitiesList(props: ListProps) {
return (
<MotionList pos="relative" w="full" {...props}>
<AnimatePresence mode="popLayout">
{latestActivities.map((item) => (
{latestActivities.map(({ id, amount, status, type, txHash }) => (
<MotionListItem
key={item.id}
key={id}
layout="position"
variants={listItemVariants}
initial={false}
Expand All @@ -43,8 +43,11 @@ function ActivitiesList(props: ListProps) {
_last={{ pb: 0 }}
>
<ActivitiesListItem
{...item}
handleDismiss={() => handleItemDismiss(item.id)}
amount={amount}
status={status}
type={type}
txHash={txHash}
handleDismiss={() => handleItemDismiss(id)}
/>
</MotionListItem>
))}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
import { TextMd } from "../Typography"

type ActivitiesListItemProps = Omit<AlertProps, "status"> &
ActivityType & {
Omit<ActivityType, "id" | "finalizedAt" | "initializedAt"> & {
handleDismiss?: () => void
}

Expand Down
3 changes: 2 additions & 1 deletion dapp/src/components/shared/Form/FormSubmitButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ import { ButtonProps } from "@chakra-ui/react"
import { LoadingButton } from "../LoadingButton"

export function FormSubmitButton({ children, ...props }: ButtonProps) {
const { isSubmitting } = useFormikContext()
const { isSubmitting, isValid } = useFormikContext()

return (
<LoadingButton
type="submit"
size="lg"
width="100%"
isLoading={isSubmitting}
isDisabled={!isValid}
{...props}
>
{children}
Expand Down
7 changes: 5 additions & 2 deletions dapp/src/components/shared/Form/FormTokenBalanceInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export type FormTokenBalanceInputProps = {
name: string
defaultValue?: bigint
} & Omit<TokenBalanceInputProps, "setAmount" | "defaultValue">

export function FormTokenBalanceInput({
name,
defaultValue,
Expand All @@ -17,9 +18,11 @@ export function FormTokenBalanceInput({
const setAmount = useCallback(
(value?: bigint) => {
if (!meta.touched) logPromiseFailure(helpers.setTouched(true))
if (meta.error) helpers.setError(undefined)

logPromiseFailure(helpers.setValue(value))
},
[helpers, meta.touched],
[helpers, meta.touched, meta.error],
)

useEffect(() => {
Expand All @@ -34,7 +37,7 @@ export function FormTokenBalanceInput({
{...field}
amount={defaultValue ?? (meta.value as bigint)}
setAmount={setAmount}
hasError={Boolean(meta.touched && meta.error)}
hasError={Boolean(meta.error)}
errorMsgText={meta.error}
/>
)
Expand Down
31 changes: 25 additions & 6 deletions dapp/src/components/shared/NumberFormatInput/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import React from "react"
import { NumericFormat, NumericFormatProps } from "react-number-format"
import {
NumberFormatValues,
NumericFormat,
NumericFormatProps,
} from "react-number-format"
import { InputProps, chakra, useMultiStyleConfig } from "@chakra-ui/react"

const ChakraWrapper = chakra(NumericFormat)
const ChakraNumericFormat = chakra(NumericFormat)

export type NumberFormatInputValues = {
formattedValue: string
Expand All @@ -12,8 +16,9 @@ export type NumberFormatInputValues = {

export type NumberFormatInputProps = {
onValueChange: (values: NumberFormatInputValues) => void
integerScale?: number
} & InputProps &
Pick<NumericFormatProps, "decimalScale" | "allowNegative">
Pick<NumericFormatProps, "decimalScale" | "allowNegative" | "suffix">

/**
* Component is from the Threshold Network React Components repository.
Expand All @@ -29,17 +34,31 @@ const NumberFormatInput = React.forwardRef<
>((props, ref) => {
const { field: css } = useMultiStyleConfig("Input", props)

const { decimalScale, isDisabled, isInvalid, ...restProps } = props
const { decimalScale, isDisabled, isInvalid, integerScale, ...restProps } =
props

const handleLengthValidation = (values: NumberFormatValues) => {
const { value, floatValue } = values
if (
floatValue === undefined ||
value === undefined ||
integerScale === undefined
)
return true

const [integerPart] = value.split(".")
return integerPart.length <= integerScale
}

return (
<ChakraWrapper
allowLeadingZeros={false}
<ChakraNumericFormat
thousandSeparator
decimalScale={decimalScale}
__css={css}
disabled={isDisabled}
aria-invalid={isInvalid}
getInputRef={ref}
isAllowed={handleLengthValidation}
{...restProps}
/>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ export type TokenAmountFormBaseProps = {
formId?: string
tokenBalance: bigint
tokenBalanceInputPlaceholder: string
tokenAmountLabel?: string
currency: CurrencyType
withMaxButton: boolean
fiatCurrency?: CurrencyType
children?: React.ReactNode
defaultAmount?: bigint
}
Expand All @@ -35,8 +35,8 @@ export default function TokenAmountFormBase({
formId,
tokenBalance,
currency,
fiatCurrency,
tokenBalanceInputPlaceholder,
tokenAmountLabel,
withMaxButton,
children,
defaultAmount,
Expand All @@ -48,10 +48,11 @@ export default function TokenAmountFormBase({
name={TOKEN_AMOUNT_FIELD_NAME}
tokenBalance={tokenBalance}
placeholder={tokenBalanceInputPlaceholder}
tokenAmountLabel={tokenAmountLabel}
currency={currency}
fiatCurrency={fiatCurrency}
withMaxButton={withMaxButton}
defaultValue={defaultAmount}
autoFocus
/>
{children}
</Form>
Expand Down
11 changes: 9 additions & 2 deletions dapp/src/components/shared/TokenAmountForm/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { FormikErrors, withFormik } from "formik"
import { getErrorsObj, validateTokenAmount } from "#/utils"
import { BaseFormProps } from "#/types"
import { ActionFlowType, BaseFormProps } from "#/types"
import TokenAmountFormBase, {
TokenAmountFormBaseProps,
TokenAmountFormValues,
} from "./TokenAmountFormBase"

type TokenAmountFormProps = {
actionType: ActionFlowType
minTokenAmount: bigint
} & TokenAmountFormBaseProps &
BaseFormProps<TokenAmountFormValues>
Expand All @@ -16,10 +17,14 @@ const TokenAmountForm = withFormik<TokenAmountFormProps, TokenAmountFormValues>(
mapPropsToValues: () => ({
amount: undefined,
}),
validate: ({ amount }, { tokenBalance, currency, minTokenAmount }) => {
validate: (
{ amount },
{ tokenBalance, currency, minTokenAmount, actionType },
) => {
const errors: FormikErrors<TokenAmountFormValues> = {}

errors.amount = validateTokenAmount(
actionType,
amount,
tokenBalance,
minTokenAmount,
Expand All @@ -31,6 +36,8 @@ const TokenAmountForm = withFormik<TokenAmountFormProps, TokenAmountFormValues>(
handleSubmit: (values, { props }) => {
props.onSubmitForm(values)
},
validateOnBlur: false,
validateOnChange: false,
},
)(TokenAmountFormBase)

Expand Down
25 changes: 21 additions & 4 deletions dapp/src/components/shared/TokenBalanceInput/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
import {
fixedPointNumberToString,
getCurrencyByType,
isFormError,
userAmountToBigInt,
} from "#/utils"
import { CurrencyType } from "#/types"
Expand All @@ -25,6 +26,7 @@ import NumberFormatInput, {
NumberFormatInputProps,
} from "../NumberFormatInput"
import { CurrencyBalance } from "../CurrencyBalance"
import { Alert, AlertIcon, AlertDescription } from "../Alert"

const VARIANT = "balance"

Expand All @@ -42,7 +44,12 @@ function HelperErrorText({
if (hasError) {
return (
<FormErrorMessage>
{errorMsgText || "Please enter a valid value"}
<Alert status="error">
<AlertIcon status="error" />
<AlertDescription>
{errorMsgText || "Please enter a valid value"}
</AlertDescription>
</Alert>
</FormErrorMessage>
)
}
Expand Down Expand Up @@ -102,6 +109,7 @@ export type TokenBalanceInputProps = {
fiatCurrency?: CurrencyType
setAmount: (value?: bigint) => void
withMaxButton?: boolean
tokenAmountLabel?: string
} & InputProps &
HelperErrorTextProps &
Pick<NumberFormatInputProps, "decimalScale">
Expand All @@ -118,12 +126,14 @@ export default function TokenBalanceInput({
hasError = false,
fiatCurrency,
withMaxButton = false,
tokenAmountLabel = "Amount",
...inputProps
}: TokenBalanceInputProps) {
const valueRef = useRef<bigint | undefined>(amount)
const [displayedValue, setDisplayedValue] = useState<string | undefined>()
const styles = useMultiStyleConfig("TokenBalanceInput", { size })
const { decimals } = getCurrencyByType(currency)

const { decimals, symbol } = getCurrencyByType(currency)

const onValueChange = (values: NumberFormatInputValues) => {
const { value } = values
Expand All @@ -141,16 +151,21 @@ export default function TokenBalanceInput({
setDisplayedValue(fixedPointNumberToString(tokenBalance, decimals))
}

const isBalanceExceeded =
typeof errorMsgText === "string" &&
isFormError("EXCEEDED_VALUE", errorMsgText)

return (
<FormControl isInvalid={hasError} isDisabled={inputProps.isDisabled}>
<FormLabel htmlFor={inputProps.name} size={size}>
<FormLabel htmlFor={inputProps.name} size={size} mr={0}>
<Box __css={styles.labelContainer}>
Amount
<Box __css={styles.balanceContainer}>
<Box as="span" __css={styles.balance}>
Balance
{tokenAmountLabel}
</Box>
<CurrencyBalance
color={isBalanceExceeded ? "red.400" : "gray.700"}
size={size === "lg" ? "md" : "sm"}
amount={tokenBalance}
currency={currency}
Expand All @@ -163,7 +178,9 @@ export default function TokenBalanceInput({
size={size}
variant={VARIANT}
isInvalid={hasError}
suffix={` ${symbol}`}
placeholder={placeholder}
integerScale={10}
decimalScale={decimals}
allowNegative={false}
{...inputProps}
Expand Down
Loading

0 comments on commit 48411ba

Please sign in to comment.