diff --git a/src/modules/core/components/RuntimeErrorAlert.tsx b/src/modules/core/components/RuntimeErrorAlert.tsx new file mode 100644 index 00000000..ed9d9a04 --- /dev/null +++ b/src/modules/core/components/RuntimeErrorAlert.tsx @@ -0,0 +1,19 @@ +import { Alert, AlertDescription, AlertTitle } from "@/common/ui/components"; + +export type RuntimeErrorAlertProps = { + customMessage?: string; +}; + +export const RuntimeErrorAlert: React.FC = ({ + customMessage, +}) => ( + + Runtime error! + + + {customMessage} + + Please contact PotLock team for help. + + +); diff --git a/src/modules/core/index.ts b/src/modules/core/index.ts index 178cd64f..ef542ee8 100644 --- a/src/modules/core/index.ts +++ b/src/modules/core/index.ts @@ -1 +1,2 @@ export * from "./utils"; +export * from "./components/RuntimeErrorAlert"; diff --git a/src/modules/donation/components/DonationFlow.tsx b/src/modules/donation/components/DonationFlow.tsx index 4d9bae20..4dbd5754 100644 --- a/src/modules/donation/components/DonationFlow.tsx +++ b/src/modules/donation/components/DonationFlow.tsx @@ -1,7 +1,13 @@ import { useMemo } from "react"; import { dispatch } from "@/app/_store"; -import { Button, DialogFooter, Form } from "@/common/ui/components"; +import { + Button, + DialogFooter, + DialogHeader, + Form, +} from "@/common/ui/components"; +import { RuntimeErrorAlert } from "@/modules/core"; import { DonationConfirmation } from "./DonationConfirmation"; import { DonationPotAllocation } from "./DonationPotAllocation"; @@ -41,7 +47,11 @@ export const DonationFlow: React.FC = ({ return ; default: - return "Error: Unable to proceed with the next step"; + return ( + + + + ); } }, [closeModal, currentStep, form, props]); diff --git a/src/modules/donation/components/DonationModal.tsx b/src/modules/donation/components/DonationModal.tsx index f8f53f82..51f7b993 100644 --- a/src/modules/donation/components/DonationModal.tsx +++ b/src/modules/donation/components/DonationModal.tsx @@ -3,14 +3,8 @@ import { useCallback } from "react"; import { create, useModal } from "@ebay/nice-modal-react"; import { dispatch, useTypedSelector } from "@/app/_store"; -import { - Alert, - AlertDescription, - AlertTitle, - Dialog, - DialogContent, - DialogHeader, -} from "@/common/ui/components"; +import { Dialog, DialogContent, DialogHeader } from "@/common/ui/components"; +import { RuntimeErrorAlert } from "@/modules/core"; import { DonationFlow } from "./DonationFlow"; import { DonationParameters } from "../models"; @@ -40,13 +34,7 @@ export const DonationModal = create((props: DonationModalProps) => { > {!("accountId" in props) && !("potId" in props) ? ( - - Runtime error! - - - Please contact PotLock team for help. - - + ) : ( diff --git a/src/modules/donation/components/DonationProjectAllocation.tsx b/src/modules/donation/components/DonationProjectAllocation.tsx index 91c55674..6d80dd3b 100644 --- a/src/modules/donation/components/DonationProjectAllocation.tsx +++ b/src/modules/donation/components/DonationProjectAllocation.tsx @@ -21,9 +21,10 @@ import { SelectValue, TextField, } from "@/common/ui/components"; +import { RuntimeErrorAlert } from "@/modules/core"; import { DONATION_MIN_NEAR_AMOUNT } from "../constants"; -import { DonationInputs } from "../models"; +import { DonationInputs, tokenIdSchema } from "../models"; export type DonationProjectAllocationProps = ByAccountId & { form: UseFormReturn; @@ -43,15 +44,23 @@ export const DonationProjectAllocation: React.FC< error: accountError, } = potlock.useAccount({ accountId }); - const { data: { balance: availableNearBalance = null } = {} } = - pagoda.useNearAccountBalance({ - accountId: walletApi.accountId ?? "unknown", - }); + const { + isLoading: isNearBalanceLoading, + data: { balance: availableNearBalance = null } = {}, + error: nearBalanceError, + } = pagoda.useNearAccountBalance({ + accountId: walletApi.accountId ?? "unknown", + }); + + const { + isLoading: isFtBalanceLoading, + data: { balances: availableFtBalances = null } = {}, + error: ftBalancesError, + } = pagoda.useFtAccountBalances({ + accountId: walletApi.accountId ?? "unknown", + }); - const { data: { balances: availableFtBalances = null } = {} } = - pagoda.useFtAccountBalances({ - accountId: walletApi.accountId ?? "unknown", - }); + const dataFetchError = accountError ?? nearBalanceError ?? ftBalancesError; const availableBalance = useMemo( () => @@ -64,7 +73,7 @@ export const DonationProjectAllocation: React.FC< [availableFtBalances, availableNearBalance, isFtDonation, tokenId], ); - return isAccountLoading || availableBalance === null ? ( + return isAccountLoading || isNearBalanceLoading || isFtBalanceLoading ? ( ) : ( <> - {accountError && accountError.message} + {dataFetchError && ( + + + + )} {account !== undefined && ( <> @@ -114,22 +127,28 @@ export const DonationProjectAllocation: React.FC< - - {`${availableBalance.amount} ${availableBalance.metadata.symbol}`} - - - - available + availableBalance === null ? ( + + Unable to load available balance! - + ) : ( +
+ + {`${availableBalance.amount} ${availableBalance.metadata.symbol}`} + + + + available + +
+ ) } fieldExtension={ - diff --git a/src/modules/donation/hooks/forms.ts b/src/modules/donation/hooks/forms.ts index 32f4abf2..e8f98cbe 100644 --- a/src/modules/donation/hooks/forms.ts +++ b/src/modules/donation/hooks/forms.ts @@ -11,18 +11,17 @@ import { DonationInputs, DonationSubmissionInputs, donationSchema, + tokenIdSchema, } from "../models"; export const useDonationForm = (params: DonationSubmissionInputs) => { const form = useForm({ resolver: zodResolver(donationSchema), + defaultValues: { tokenId: tokenIdSchema.parse(undefined) }, }); - const tokenId = form.watch("tokenId"); const isSenderHumanVerified = useIsHuman(walletApi.accountId ?? "unknown"); - console.log(tokenId); - const onSubmit: SubmitHandler = useCallback( (values) => dispatch.donation.submit({ ...values, ...params }), [params], diff --git a/src/modules/donation/models.ts b/src/modules/donation/models.ts index 4ccc9aac..a7eec69c 100644 --- a/src/modules/donation/models.ts +++ b/src/modules/donation/models.ts @@ -63,6 +63,11 @@ export const donationAllocationStrategies: Record< export type DonationStep = "allocation" | "confirmation" | "success"; +export const tokenIdSchema = literal(NEAR_TOKEN_DENOM) + .or(string().min(6)) + .default(NEAR_TOKEN_DENOM) + .describe('Either "NEAR" or FT contract account id.'); + export const donationSchema = object({ allocationStrategy: nativeEnum(DonationAllocationStrategyEnum, { message: "Incorrect allocation strategy.", @@ -72,10 +77,7 @@ export const donationSchema = object({ message: "Incorrect donation distribution strategy.", }).default(DonationPotDistributionStrategyEnum.evenly), - tokenId: literal(NEAR_TOKEN_DENOM) - .or(string().min(6)) - .default(NEAR_TOKEN_DENOM) - .describe('Either "NEAR" or FT contract account id.'), + tokenId: tokenIdSchema, amount: number() .positive()