-
Notifications
You must be signed in to change notification settings - Fork 26
feat: keep form data in memory #1525
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import { useFormContext, useWatch } from "@babylonlabs-io/core-ui"; | ||
import { useEffect, useMemo, useRef } from "react"; | ||
|
||
import { | ||
useFormPersistenceState, | ||
type BabyStakeDraft, | ||
} from "@/ui/common/state/FormPersistenceState"; | ||
|
||
export function BabyFormPersistence() { | ||
const { setValue, control } = useFormContext<BabyStakeDraft>(); | ||
const { babyStakeDraft, setBabyStakeDraft } = useFormPersistenceState(); | ||
const hasHydratedRef = useRef(false); | ||
|
||
const amount = useWatch({ control, name: "amount" }); | ||
const validatorAddresses = useWatch({ control, name: "validatorAddresses" }); | ||
const feeAmount = useWatch({ control, name: "feeAmount" }); | ||
|
||
// Hydrate once on mount | ||
useEffect(() => { | ||
if (hasHydratedRef.current) return; | ||
|
||
if (babyStakeDraft) { | ||
if (babyStakeDraft.amount !== undefined) { | ||
setValue("amount", babyStakeDraft.amount, { | ||
shouldValidate: true, | ||
shouldDirty: false, | ||
shouldTouch: false, | ||
}); | ||
} | ||
if (babyStakeDraft.validatorAddresses !== undefined) { | ||
setValue("validatorAddresses", babyStakeDraft.validatorAddresses, { | ||
shouldValidate: true, | ||
shouldDirty: false, | ||
shouldTouch: false, | ||
}); | ||
} | ||
if (babyStakeDraft.feeAmount !== undefined) { | ||
setValue("feeAmount", babyStakeDraft.feeAmount, { | ||
shouldValidate: true, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could probably move these {shouldValidate: true, shouldDirty: false, shouldTouch: false} to a const and assign on each of these setValues. Would make the code a bit cleaner. Actually, since we are at it, this is simply a matter of doing something like
|
||
shouldDirty: false, | ||
shouldTouch: false, | ||
}); | ||
} | ||
} | ||
|
||
hasHydratedRef.current = true; | ||
}, [babyStakeDraft, setValue]); | ||
|
||
const draft = useMemo( | ||
() => ({ | ||
amount, | ||
validatorAddresses, | ||
feeAmount, | ||
}), | ||
[amount, validatorAddresses, feeAmount], | ||
); | ||
|
||
// Persist on change | ||
useEffect(() => { | ||
setBabyStakeDraft(draft); | ||
}, [draft, setBabyStakeDraft]); | ||
|
||
return null; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,8 @@ import { SubmitButton } from "@/ui/baby/widgets/SubmitButton"; | |
import { ValidatorField } from "@/ui/baby/widgets/ValidatorField"; | ||
import { FormAlert } from "@/ui/common/components/Multistaking/MultistakingForm/FormAlert"; | ||
|
||
import { BabyFormPersistence } from "./BabyFormPersistence"; | ||
|
||
interface FormFields { | ||
amount: number; | ||
validatorAddresses: string[]; | ||
|
@@ -44,6 +46,7 @@ export default function StakingForm({ | |
className="flex flex-col gap-2 h-[500px]" | ||
onSubmit={handlePreview} | ||
> | ||
<BabyFormPersistence /> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this a functional component? can't this be a hook instead? Since it's returning null that is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. agree |
||
<AmountField balance={availableBalance} price={babyPrice} /> | ||
<ValidatorField /> | ||
<FeeField babyPrice={babyPrice} calculateFee={calculateFee} /> | ||
|
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,94 @@ | ||||||||
import { useFormContext, useWatch } from "@babylonlabs-io/core-ui"; | ||||||||
import { useEffect, useMemo, useRef } from "react"; | ||||||||
|
||||||||
import { | ||||||||
useFormPersistenceState, | ||||||||
type BtcStakeDraft, | ||||||||
} from "@/ui/common/state/FormPersistenceState"; | ||||||||
import { useStakingState } from "@/ui/common/state/StakingState"; | ||||||||
|
||||||||
export function BtcFormPersistence() { | ||||||||
const { setValue, control } = useFormContext<BtcStakeDraft>(); | ||||||||
const { btcStakeDraft, setBtcStakeDraft } = useFormPersistenceState(); | ||||||||
const { stakingInfo } = useStakingState(); | ||||||||
const hasHydratedRef = useRef(false); | ||||||||
|
||||||||
const finalityProviders = useWatch({ control, name: "finalityProviders" }); | ||||||||
const amount = useWatch({ control, name: "amount" }); | ||||||||
const term = useWatch({ control, name: "term" }); | ||||||||
const feeRate = useWatch({ control, name: "feeRate" }); | ||||||||
const feeAmount = useWatch({ control, name: "feeAmount" }); | ||||||||
|
||||||||
// Hydrate once on mount | ||||||||
useEffect(() => { | ||||||||
if (hasHydratedRef.current) return; | ||||||||
|
||||||||
if (btcStakeDraft) { | ||||||||
if (btcStakeDraft.finalityProviders) { | ||||||||
setValue("finalityProviders", btcStakeDraft.finalityProviders, { | ||||||||
shouldValidate: false, | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here |
||||||||
shouldDirty: false, | ||||||||
shouldTouch: false, | ||||||||
}); | ||||||||
} | ||||||||
if (btcStakeDraft.amount !== undefined) { | ||||||||
setValue("amount", btcStakeDraft.amount, { | ||||||||
shouldValidate: true, | ||||||||
shouldDirty: false, | ||||||||
shouldTouch: false, | ||||||||
}); | ||||||||
} | ||||||||
if (btcStakeDraft.term !== undefined) { | ||||||||
setValue("term", btcStakeDraft.term, { | ||||||||
shouldValidate: false, | ||||||||
shouldDirty: false, | ||||||||
shouldTouch: false, | ||||||||
}); | ||||||||
} | ||||||||
if (btcStakeDraft.feeRate !== undefined) { | ||||||||
setValue("feeRate", btcStakeDraft.feeRate, { | ||||||||
shouldValidate: true, | ||||||||
shouldDirty: false, | ||||||||
shouldTouch: false, | ||||||||
}); | ||||||||
} | ||||||||
if (btcStakeDraft.feeAmount !== undefined) { | ||||||||
setValue("feeAmount", btcStakeDraft.feeAmount, { | ||||||||
shouldValidate: true, | ||||||||
shouldDirty: false, | ||||||||
shouldTouch: false, | ||||||||
}); | ||||||||
} | ||||||||
} else if ( | ||||||||
stakingInfo?.defaultFeeRate !== undefined && | ||||||||
(feeRate === undefined || feeRate === "") | ||||||||
Comment on lines
+63
to
+64
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [nitpick] The condition
Suggested change
Copilot uses AI. Check for mistakes. Positive FeedbackNegative Feedback |
||||||||
) { | ||||||||
// Apply default only when no persisted draft and no current value | ||||||||
setValue("feeRate", stakingInfo.defaultFeeRate.toString(), { | ||||||||
shouldValidate: true, | ||||||||
shouldDirty: false, | ||||||||
shouldTouch: false, | ||||||||
}); | ||||||||
} | ||||||||
|
||||||||
hasHydratedRef.current = true; | ||||||||
}, [btcStakeDraft, stakingInfo?.defaultFeeRate, feeRate, setValue]); | ||||||||
|
||||||||
const draft = useMemo( | ||||||||
() => ({ | ||||||||
finalityProviders, | ||||||||
amount, | ||||||||
term, | ||||||||
feeRate, | ||||||||
feeAmount, | ||||||||
}), | ||||||||
[finalityProviders, amount, term, feeRate, feeAmount], | ||||||||
); | ||||||||
|
||||||||
// Persist on change | ||||||||
useEffect(() => { | ||||||||
setBtcStakeDraft(draft); | ||||||||
}, [draft, setBtcStakeDraft]); | ||||||||
|
||||||||
return null; | ||||||||
} |
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -22,9 +22,15 @@ interface FeeModalProps { | |||||||
open?: boolean; | ||||||||
onSubmit?: (value: number) => void; | ||||||||
onClose?: () => void; | ||||||||
currentFeeRate?: number; | ||||||||
} | ||||||||
|
||||||||
export function FeeModal({ open, onSubmit, onClose }: FeeModalProps) { | ||||||||
export function FeeModal({ | ||||||||
open, | ||||||||
onSubmit, | ||||||||
onClose, | ||||||||
currentFeeRate, | ||||||||
}: FeeModalProps) { | ||||||||
const [selectedValue, setSelectedValue] = useState(""); | ||||||||
const [customFee, setCustomFee] = useState(""); | ||||||||
const customFeeRef = useRef<HTMLInputElement>(null); | ||||||||
|
@@ -45,6 +51,32 @@ export function FeeModal({ open, onSubmit, onClose }: FeeModalProps) { | |||||||
} | ||||||||
}, [selectedValue]); | ||||||||
|
||||||||
// Initialize selection based on current fee rate when opening | ||||||||
useEffect(() => { | ||||||||
if (!open || isLoading) return; | ||||||||
|
||||||||
const fee = Number(currentFeeRate); | ||||||||
if (!fee || !Number.isFinite(fee)) { | ||||||||
Comment on lines
+58
to
+59
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The condition
Suggested change
Copilot uses AI. Check for mistakes. Positive FeedbackNegative Feedback |
||||||||
setSelectedValue(""); | ||||||||
setCustomFee(""); | ||||||||
return; | ||||||||
} | ||||||||
|
||||||||
if (fee === fastestFee) { | ||||||||
setSelectedValue("fast"); | ||||||||
setCustomFee(""); | ||||||||
} else if (fee === mediumFee) { | ||||||||
setSelectedValue("medium"); | ||||||||
setCustomFee(""); | ||||||||
} else if (fee === lowestFee) { | ||||||||
setSelectedValue("slow"); | ||||||||
setCustomFee(""); | ||||||||
} else { | ||||||||
setSelectedValue("custom"); | ||||||||
setCustomFee(fee.toString()); | ||||||||
} | ||||||||
}, [open, isLoading, currentFeeRate, fastestFee, mediumFee, lowestFee]); | ||||||||
|
||||||||
const feeOptions = [ | ||||||||
{ | ||||||||
label: ( | ||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we have comments on these values so it's easier to understand why, besides
Hydrate once on mount