Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dev: ability to reset fee values in dev mode #698

Merged
merged 2 commits into from
Nov 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/components/Jam.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,6 @@ export default function Jam({ wallet }: JamProps) {
setFieldValue,
validateForm,
isValid,
dirty,
touched,
errors,
}) => (
Expand All @@ -474,7 +473,12 @@ export default function Jam({ wallet }: JamProps) {
{isDebugFeatureEnabled('insecureScheduleTesting') && (
<rb.Form.Group className="mb-4" controlId="offertype">
<ToggleSwitch
label={'Use insecure testing settings'}
label={
<>
Use insecure testing settings
<span className="ms-2 badge rounded-pill bg-warning">dev</span>
</>
}
subtitle={
"This is completely insecure but makes testing the schedule much faster. This option won't be available in production."
}
Expand Down
4 changes: 2 additions & 2 deletions src/components/ToggleSwitch.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { ChangeEvent } from 'react'
import { ReactNode, ChangeEvent } from 'react'
import styles from './ToggleSwitch.module.css'

interface ToggleSwitchProps {
label: string
label: string | ReactNode
subtitle?: string
onToggle: (isToggled: boolean) => void
toggledOn: boolean
Expand Down
86 changes: 71 additions & 15 deletions src/components/settings/FeeConfigModal.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import { forwardRef, useRef, useCallback, useEffect, useState } from 'react'
import * as rb from 'react-bootstrap'
import { Trans, useTranslation } from 'react-i18next'
import { Formik, FormikErrors } from 'formik'
import { Formik, FormikErrors, FormikProps } from 'formik'
import classNames from 'classnames'
import { FEE_CONFIG_KEYS, TxFeeValueUnit, toTxFeeValueUnit, FeeValues, useLoadFeeConfigValues } from '../../hooks/Fees'
import { useUpdateConfigValues } from '../../context/ServiceConfigContext'
import { isValidNumber, factorToPercentage, percentageToFactor } from '../../utils'
import Sprite from '../Sprite'
import SegmentedTabs from '../SegmentedTabs'
import styles from './FeeConfigModal.module.css'
import { isDebugFeatureEnabled } from '../../constants/debugFeatures'
import ToggleSwitch from '../ToggleSwitch'

const __dev_allowFeeValuesReset = isDebugFeatureEnabled('allowFeeValuesReset')

type SatsPerKiloVByte = number

Expand Down Expand Up @@ -53,30 +57,56 @@ export type FeeConfigSectionKey = 'tx_fee' | 'cj_fee'
const TX_FEE_SECTION_KEY: FeeConfigSectionKey = 'tx_fee'
const CJ_FEE_SECTION_KEY: FeeConfigSectionKey = 'cj_fee'

type FeeFormValues = FeeValues & {
enableValidation?: boolean
}

interface FeeConfigFormProps {
initialValues: FeeValues
validate: (values: FeeValues, txFeesUnit: TxFeeValueUnit) => FormikErrors<FeeValues>
onSubmit: (values: FeeValues, txFeesUnit: TxFeeValueUnit) => void
initialValues: FeeFormValues
validate: (values: FeeFormValues, txFeesUnit: TxFeeValueUnit) => FormikErrors<FeeFormValues>
onSubmit: (values: FeeFormValues, txFeesUnit: TxFeeValueUnit) => void
defaultActiveSectionKey?: FeeConfigSectionKey
}

const FeeConfigForm = forwardRef(
(
{ onSubmit, validate, initialValues, defaultActiveSectionKey }: FeeConfigFormProps,
ref: React.Ref<HTMLFormElement>,
ref: React.Ref<FormikProps<FeeFormValues>>,
) => {
const { t, i18n } = useTranslation()

const [txFeesUnit, setTxFeesUnit] = useState<TxFeeValueUnit>(toTxFeeValueUnit(initialValues.tx_fees) || 'blocks')

return (
<Formik
innerRef={ref}
initialValues={initialValues}
validate={(values) => validate(values, txFeesUnit)}
onSubmit={(values) => onSubmit(values, txFeesUnit)}
>
{({ handleSubmit, setFieldValue, handleBlur, validateForm, values, touched, errors, isSubmitting }) => (
<rb.Form ref={ref} onSubmit={handleSubmit} noValidate lang={i18n.resolvedLanguage || i18n.language}>
<rb.Form onSubmit={handleSubmit} noValidate lang={i18n.resolvedLanguage || i18n.language}>
{__dev_allowFeeValuesReset && (
<div className="mb-4">
<ToggleSwitch
label={
<>
Enable form validation
<span className="ms-2 badge rounded-pill bg-warning">dev</span>
</>
}
subtitle={
'Ability to reset fee values to test what the UI looks like, when a user does not have these values configured.'
}
toggledOn={values.enableValidation ?? true}
onToggle={(isToggled) => {
setFieldValue('enableValidation', isToggled, true)
}}
disabled={isSubmitting}
/>
</div>
)}

<rb.Accordion flush defaultActiveKey={defaultActiveSectionKey}>
<rb.Accordion.Item eventKey={CJ_FEE_SECTION_KEY}>
<rb.Accordion.Header>
Expand Down Expand Up @@ -332,9 +362,9 @@ export default function FeeConfigModal({
const [isLoading, setIsLoading] = useState(true)
const [isSubmitting, setIsSubmitting] = useState(false)
const [loadError, setLoadError] = useState(false)
const [saveErrorMessage, setSaveErrorMessage] = useState<string | undefined>(undefined)
const [feeConfigValues, setFeeConfigValues] = useState<FeeValues | null>(null)
const formRef = useRef<HTMLFormElement>(null)
const [saveErrorMessage, setSaveErrorMessage] = useState<string>()
const [feeFormValues, setFeeFormValues] = useState<FeeFormValues | null>(null)
const formRef = useRef<FormikProps<FeeFormValues>>(null)

useEffect(() => {
setLoadError(false)
Expand All @@ -347,7 +377,7 @@ export default function FeeConfigModal({
.then((val) => {
if (abortCtrl.signal.aborted) return
setIsLoading(false)
setFeeConfigValues(val)
setFeeFormValues(val)
})
.catch((e) => {
if (abortCtrl.signal.aborted) return
Expand Down Expand Up @@ -415,8 +445,14 @@ export default function FeeConfigModal({
}

const validate = useCallback(
(values: FeeValues, txFeesUnit: TxFeeValueUnit) => {
const errors = {} as FormikErrors<FeeValues>
(values: FeeFormValues, txFeesUnit: TxFeeValueUnit) => {
const errors = {} as FormikErrors<FeeFormValues>

if (values.enableValidation === false) {
// do not validate form to enable resetting the values
// this can only be done in dev mode!
return errors
}

if (
!isValidNumber(values.tx_fees_factor) ||
Expand Down Expand Up @@ -536,10 +572,10 @@ export default function FeeConfigModal({
</>
) : (
<>
{feeConfigValues && (
{feeFormValues && (
<FeeConfigForm
ref={formRef}
initialValues={feeConfigValues}
initialValues={feeFormValues}
validate={validate}
onSubmit={submit}
defaultActiveSectionKey={defaultActiveSectionKey}
Expand All @@ -559,12 +595,32 @@ export default function FeeConfigModal({
<rb.Button variant="light" onClick={cancel} className="d-flex justify-content-center align-items-center">
{t('settings.fees.text_button_cancel')}
</rb.Button>

{__dev_allowFeeValuesReset && (
<rb.Button
variant="outline-dark"
className="position-relative"
onClick={() => {
formRef.current?.setFieldValue('max_cj_fee_abs', '', false)
formRef.current?.setFieldValue('max_cj_fee_rel', '', false)
formRef.current?.setFieldValue('tx_fees', '', false)
formRef.current?.setFieldValue('tx_fees_factor', '', false)
setTimeout(() => formRef.current?.validateForm(), 4)
}}
disabled={isLoading || isSubmitting}
>
Reset form values
<span className="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-warning">
dev
</span>
</rb.Button>
)}
<rb.Button
variant="dark"
type="submit"
className="d-flex justify-content-center align-items-center"
disabled={isLoading || isSubmitting}
onClick={() => formRef.current?.requestSubmit()}
onClick={() => formRef.current?.submitForm()}
>
{isSubmitting ? (
<>
Expand Down
2 changes: 2 additions & 0 deletions src/constants/debugFeatures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ interface DebugFeatures {
devSetupPage: boolean
importDummyMnemonicPhrase: boolean
rescanChainPage: boolean
allowFeeValuesReset: boolean
fastThemeToggle: boolean
}

Expand All @@ -19,6 +20,7 @@ const debugFeatures: DebugFeatures = {
devSetupPage: devMode,
importDummyMnemonicPhrase: devMode,
rescanChainPage: devMode,
allowFeeValuesReset: devMode,
fastThemeToggle: devMode,
}

Expand Down