Reinitialize wallet form if initial values change + fix readOnly hydration error (#1354)
* Reinitialize wallet form if initial values change This fixes that enabled is not set on first render if only recv is configured * Remove unnecessary old usage of ClientCheckbox This isn't needed even without enableReinitialize since for send, enabled is correctly set on first render. It was needed in the past when we were still validating wallets before enabling them on first page load but now, we simply load the configuration from localStorage which is immediately available on the client. * Fix readOnly hydration error * Replace repetitive isMounted logic with useIsClient hook
This commit is contained in:
parent
69916117b1
commit
d9024ff837
|
@ -3,6 +3,7 @@ import { Checkbox, Input } from './form'
|
|||
import { useMe } from './me'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { isNumber } from '@/lib/validate'
|
||||
import { useIsClient } from './use-client'
|
||||
|
||||
function autoWithdrawThreshold ({ me }) {
|
||||
return isNumber(me?.privates?.autoWithdrawThreshold) ? me?.privates?.autoWithdrawThreshold : 10000
|
||||
|
@ -25,15 +26,12 @@ export function AutowithdrawSettings ({ wallet }) {
|
|||
setSendThreshold(Math.max(Math.floor(threshold / 10), 1))
|
||||
}, [autoWithdrawThreshold])
|
||||
|
||||
const [mounted, setMounted] = useState(false)
|
||||
useEffect(() => {
|
||||
setMounted(true)
|
||||
}, [])
|
||||
const isClient = useIsClient()
|
||||
|
||||
return (
|
||||
<>
|
||||
<Checkbox
|
||||
disabled={mounted && !wallet.isConfigured}
|
||||
disabled={isClient && !wallet.isConfigured}
|
||||
label='enabled'
|
||||
id='enabled'
|
||||
name='enabled'
|
||||
|
|
|
@ -803,7 +803,7 @@ const StorageKeyPrefixContext = createContext()
|
|||
|
||||
export function Form ({
|
||||
initial, validate, schema, onSubmit, children, initialError, validateImmediately,
|
||||
storageKeyPrefix, validateOnChange = true, requireSession, innerRef,
|
||||
storageKeyPrefix, validateOnChange = true, requireSession, innerRef, enableReinitialize,
|
||||
...props
|
||||
}) {
|
||||
const toaster = useToast()
|
||||
|
@ -855,6 +855,7 @@ export function Form ({
|
|||
return (
|
||||
<Formik
|
||||
initialValues={initial}
|
||||
enableReinitialize={enableReinitialize}
|
||||
validateOnChange={validateOnChange}
|
||||
validate={validate}
|
||||
validationSchema={schema}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
import { useEffect, useState } from 'react'
|
||||
|
||||
// https://usehooks-ts.com/react-hook/use-is-client#hook
|
||||
export function useIsClient () {
|
||||
const [isClient, setClient] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
setClient(true)
|
||||
}, [])
|
||||
|
||||
return isClient
|
||||
}
|
|
@ -1,15 +1,16 @@
|
|||
import { getGetServerSideProps } from '@/api/ssrApollo'
|
||||
import { Form, ClientInput, ClientCheckbox, PasswordInput, CheckboxGroup } from '@/components/form'
|
||||
import { Form, ClientInput, PasswordInput, CheckboxGroup, Checkbox } from '@/components/form'
|
||||
import { CenterLayout } from '@/components/layout'
|
||||
import { WalletSecurityBanner } from '@/components/banners'
|
||||
import { WalletLogs } from '@/components/wallet-logger'
|
||||
import { useToast } from '@/components/toast'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useWallet, Status } from 'wallets'
|
||||
import { useWallet } from 'wallets'
|
||||
import Info from '@/components/info'
|
||||
import Text from '@/components/text'
|
||||
import { AutowithdrawSettings } from '@/components/autowithdraw-shared'
|
||||
import dynamic from 'next/dynamic'
|
||||
import { useIsClient } from '@/components/use-client'
|
||||
|
||||
const WalletButtonBar = dynamic(() => import('@/components/wallet-buttonbar.js'), { ssr: false })
|
||||
|
||||
|
@ -45,6 +46,7 @@ export default function WalletSettings () {
|
|||
{wallet.canSend && wallet.hasConfig > 0 && <WalletSecurityBanner />}
|
||||
<Form
|
||||
initial={initial}
|
||||
enableReinitialize
|
||||
{...validateProps}
|
||||
onSubmit={async ({ amount, ...values }) => {
|
||||
try {
|
||||
|
@ -70,9 +72,8 @@ export default function WalletSettings () {
|
|||
? <AutowithdrawSettings wallet={wallet} />
|
||||
: (
|
||||
<CheckboxGroup name='enabled'>
|
||||
<ClientCheckbox
|
||||
<Checkbox
|
||||
disabled={!wallet.isConfigured}
|
||||
initialValue={wallet.status === Status.Enabled}
|
||||
label='enabled'
|
||||
name='enabled'
|
||||
groupClassName='mb-0'
|
||||
|
@ -101,13 +102,15 @@ export default function WalletSettings () {
|
|||
}
|
||||
|
||||
function WalletFields ({ wallet: { config, fields, isConfigured } }) {
|
||||
const isClient = useIsClient()
|
||||
|
||||
return fields
|
||||
.map(({ name, label = '', type, help, optional, editable, clientOnly, serverOnly, ...props }, i) => {
|
||||
const rawProps = {
|
||||
...props,
|
||||
name,
|
||||
initialValue: config?.[name],
|
||||
readOnly: isConfigured && editable === false && !!config?.[name],
|
||||
readOnly: isClient && isConfigured && editable === false && !!config?.[name],
|
||||
groupClassName: props.hidden ? 'd-none' : undefined,
|
||||
label: label
|
||||
? (
|
||||
|
|
|
@ -3,8 +3,9 @@ import Layout from '@/components/layout'
|
|||
import styles from '@/styles/wallet.module.css'
|
||||
import Link from 'next/link'
|
||||
import { useWallets, walletPrioritySort } from 'wallets'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useState } from 'react'
|
||||
import dynamic from 'next/dynamic'
|
||||
import { useIsClient } from '@/components/use-client'
|
||||
|
||||
const WalletCard = dynamic(() => import('@/components/wallet-card'), { ssr: false })
|
||||
|
||||
|
@ -29,17 +30,10 @@ async function reorder (wallets, sourceIndex, targetIndex) {
|
|||
export default function Wallet ({ ssrData }) {
|
||||
const { wallets } = useWallets()
|
||||
|
||||
const [mounted, setMounted] = useState(false)
|
||||
const isClient = useIsClient()
|
||||
const [sourceIndex, setSourceIndex] = useState(null)
|
||||
const [targetIndex, setTargetIndex] = useState(null)
|
||||
|
||||
useEffect(() => {
|
||||
// mounted is required since draggable is false
|
||||
// for wallets only available on the client during SSR
|
||||
// and thus we need to render the component again on the client
|
||||
setMounted(true)
|
||||
}, [])
|
||||
|
||||
const onDragStart = (i) => (e) => {
|
||||
// e.dataTransfer.dropEffect = 'move'
|
||||
// We can only use the DataTransfer API inside the drop event
|
||||
|
@ -94,7 +88,7 @@ export default function Wallet ({ ssrData }) {
|
|||
return walletPrioritySort(w1, w2)
|
||||
})
|
||||
.map((w, i) => {
|
||||
const draggable = mounted && w.enabled
|
||||
const draggable = isClient && w.enabled
|
||||
|
||||
return (
|
||||
<div
|
||||
|
|
Loading…
Reference in New Issue