From a5cc4cafefebc0f8c6d88143ed03928163b3354e Mon Sep 17 00:00:00 2001 From: theborakompanioni Date: Fri, 6 Oct 2023 10:16:20 +0200 Subject: [PATCH] refactor: Earn component from jsx to tsx --- src/components/Earn.tsx | 574 +++++++++++++++++++++++----------------- 1 file changed, 328 insertions(+), 246 deletions(-) diff --git a/src/components/Earn.tsx b/src/components/Earn.tsx index f87f4eea..857980a9 100644 --- a/src/components/Earn.tsx +++ b/src/components/Earn.tsx @@ -1,4 +1,4 @@ -import { useEffect, useMemo, useState } from 'react' +import { useCallback, useEffect, useMemo, useState } from 'react' import { Formik, FormikErrors } from 'formik' import * as rb from 'react-bootstrap' import { useTranslation } from 'react-i18next' @@ -132,7 +132,7 @@ function CurrentOffer({ offer, nickname }: CurrentOfferProps) {
{t('earn.current.text_cjfee')}
{isRelativeOffer(offer.ordertype) ? ( - <>{factorToPercentage(parseInt(offer.cjfee, 10) || 0)}% + <>{factorToPercentage(parseFloat(offer.cjfee) || 0)}% ) : ( <> React.ReactNode | string + onSubmit: (values: EarnFormValues) => Promise + isLoading: boolean + disabled?: boolean +} + +const EarnForm = ({ + initialValues = FORM_INPUT_DEFAULT_VALUES, + submitButtonText, + onSubmit, + isLoading, + disabled = false, +}: EarnFormProps) => { + const { t } = useTranslation() + + const validate = (values: EarnFormValues) => { + const errors = {} as FormikErrors + const isRelOffer = isRelativeOffer(values.offertype) + const isAbsOffer = isAbsoluteOffer(values.offertype) + + if (!isRelOffer && !isAbsOffer) { + // currently no need for translation, this should never occur -> input is controlled by toggle + errors.offertype = 'Offertype is not supported' + } + + if (isRelOffer) { + if (typeof values.feeRel !== 'number' || values.feeRel < feeRelMin || values.feeRel > feeRelMax) { + errors.feeRel = t('earn.feedback_invalid_rel_fee', { + feeRelPercentageMin: `${factorToPercentage(feeRelMin)}%`, + feeRelPercentageMax: `${factorToPercentage(feeRelMax)}%`, + }) + } + } + + if (isAbsOffer) { + if (typeof values.feeAbs !== 'number' || values.feeAbs < 0) { + errors.feeAbs = t('earn.feedback_invalid_abs_fee') + } + } + + if (typeof values.minsize !== 'number' || values.minsize < 0) { + errors.minsize = t('earn.feedback_invalid_min_amount') + } + + return errors + } + + return ( + + {({ handleSubmit, setFieldValue, handleChange, handleBlur, values, touched, errors, isSubmitting }) => ( + <> + + + <> + + { + checked && setFieldValue('offertype', tab.value, true) + }} + initialValue={values.offertype} + disabled={isLoading || isSubmitting} + /> + + {values.offertype === OFFERTYPE_REL ? ( + + + {t('earn.label_rel_fee', { + fee: typeof values.feeRel === 'number' ? `(${factorToPercentage(values.feeRel)}%)` : '', + })} + + {t('earn.description_rel_fee')} + {isLoading ? ( + + + + ) : ( + + + % + + { + const value = e.target.value || '' + setFieldValue('feeRel', value !== '' ? percentageToFactor(parseFloat(value)) : '', true) + }} + onBlur={handleBlur} + value={typeof values.feeRel === 'number' ? factorToPercentage(values.feeRel) : ''} + isValid={touched.feeRel && !errors.feeRel} + isInvalid={touched.feeRel && !!errors.feeRel} + min={0} + step={feeRelPercentageStep} + /> + {errors.feeRel} + + )} + + ) : ( + + + {t('earn.label_abs_fee', { + fee: + typeof values.feeAbs === 'number' + ? `(${values.feeAbs} ${values.feeAbs === 1 ? 'sat' : 'sats'})` + : '', + })} + + {t('earn.description_abs_fee')} + {isLoading ? ( + + + + ) : ( + + + + + + {errors.feeAbs} + + )} + + )} + + + {t('earn.label_min_amount')} + {isLoading ? ( + + + + ) : ( + + + + + + {errors.minsize} + + )} + + + + +
{submitButtonText(isSubmitting)}
+
+
+ + )} +
+ ) +} + const toStartMakerRequest = (values: EarnFormValues): Api.StartMakerRequest => { // both fee properties need to be provided. // prevent providing an invalid value by setting the ignored prop to zero @@ -225,32 +429,38 @@ export default function Earn({ wallet }: EarnProps) { const [isWaitingMakerStop, setIsWaitingMakerStop] = useState(false) const [isShowReport, setIsShowReport] = useState(false) const [isShowOrderbook, setIsShowOrderbook] = useState(false) + + const [initialValues, setInitialValues] = useState(initialFormValues()) + const fidelityBonds = useMemo(() => { return currentWalletInfo?.fidelityBondSummary.fbOutputs || [] }, [currentWalletInfo]) const [moveToJarFidelityBondId, setMoveToJarFidelityBondId] = useState() - const startMakerService = (values: EarnFormValues) => { - setIsSending(true) - setIsWaitingMakerStart(true) - - // There is no response data to check if maker got started: - // Wait for the websocket or session response! - return ( - Api.postMakerStart({ ...wallet }, toStartMakerRequest(values)) - .then((res) => (res.ok ? true : Api.Helper.throwError(res))) - // show the loader a little longer to avoid flickering - .then((result) => new Promise((r) => setTimeout(() => r(result), 200))) - .catch((e) => { - setIsWaitingMakerStart(false) - throw e - }) - .finally(() => setIsSending(false)) - ) - } + const startMakerService = useCallback( + (values: EarnFormValues) => { + setIsSending(true) + setIsWaitingMakerStart(true) + + // There is no response data to check if maker got started: + // Wait for the websocket or session response! + return ( + Api.postMakerStart({ ...wallet }, toStartMakerRequest(values)) + .then((res) => (res.ok ? true : Api.Helper.throwError(res))) + // show the loader a little longer to avoid flickering + .then((result) => new Promise((r) => setTimeout(() => r(result), 200))) + .catch((e) => { + setIsWaitingMakerStart(false) + throw e + }) + .finally(() => setIsSending(false)) + ) + }, + [wallet], + ) - const stopMakerService = () => { + const stopMakerService = useCallback(() => { setIsSending(true) setIsWaitingMakerStop(true) @@ -264,7 +474,7 @@ export default function Earn({ wallet }: EarnProps) { throw e }) .finally(() => setIsSending(false)) - } + }, [wallet]) useEffect(() => { if (isSending) return @@ -308,65 +518,53 @@ export default function Earn({ wallet }: EarnProps) { }) }, [isSending, serviceInfo, isWaitingMakerStart, isWaitingMakerStop, t]) - const reloadFidelityBonds = ({ delay }: { delay: number }) => { - const abortCtrl = new AbortController() + const reloadFidelityBonds = useCallback( + ({ delay }: { delay: number }) => { + const abortCtrl = new AbortController() - setIsLoading(true) + setIsLoading(true) - new Promise((resolve) => { - setTimeout(async () => { - resolve(await reloadCurrentWalletInfo.reloadUtxos({ signal: abortCtrl.signal })) - }, delay) - }) - .catch((err) => { - if (abortCtrl.signal.aborted) return - setAlert({ variant: 'danger', message: err.message }) + new Promise((resolve) => { + setTimeout(async () => { + resolve(await reloadCurrentWalletInfo.reloadUtxos({ signal: abortCtrl.signal })) + }, delay) }) - .finally(() => { - if (abortCtrl.signal.aborted) return - setIsLoading(false) - }) - } - - const feeRelMin = 0.0 - const feeRelMax = 0.1 // 10% - const feeRelPercentageStep = 0.0001 + .catch((err) => { + if (abortCtrl.signal.aborted) return + setAlert({ variant: 'danger', message: err.message || t('global.errors.reason_unknown') }) + }) + .finally(() => { + if (abortCtrl.signal.aborted) return + setIsLoading(false) + }) + }, + [reloadCurrentWalletInfo, t], + ) - const initialValues = initialFormValues() + const onSubmitStart = useCallback( + async (values: EarnFormValues) => { + if (isLoading || isSending || isWaitingMakerStart || isWaitingMakerStop) { + return + } - const validate = (values: EarnFormValues) => { - const errors = {} as FormikErrors - const isRelOffer = isRelativeOffer(values.offertype) - const isAbsOffer = isAbsoluteOffer(values.offertype) + setAlert(undefined) - if (!isRelOffer && !isAbsOffer) { - // currently no need for translation, this should never occur -> input is controlled by toggle - errors.offertype = 'Offertype is not supported' - } + try { + persistFormValues(values) + setInitialValues(initialFormValues()) - if (isRelOffer) { - if (typeof values.feeRel !== 'number' || values.feeRel < feeRelMin || values.feeRel > feeRelMax) { - errors.feeRel = t('earn.feedback_invalid_rel_fee', { - feeRelPercentageMin: `${factorToPercentage(feeRelMin)}%`, - feeRelPercentageMax: `${factorToPercentage(feeRelMax)}%`, - }) - } - } + setServiceInfoAlert({ variant: 'success', message: t('earn.alert_starting') }) - if (isAbsOffer) { - if (typeof values.feeAbs !== 'number' || values.feeAbs < 0) { - errors.feeAbs = t('earn.feedback_invalid_abs_fee') + await startMakerService(values) + } catch (e: any) { + setServiceInfoAlert(undefined) + setAlert({ variant: 'danger', message: e.message || t('global.errors.reason_unknown') }) } - } - - if (typeof values.minsize !== 'number' || values.minsize < 0) { - errors.minsize = t('earn.feedback_invalid_min_amount') - } - - return errors - } + }, + [startMakerService, isLoading, isSending, isWaitingMakerStart, isWaitingMakerStop, t], + ) - const onSubmit = async (values: EarnFormValues) => { + const onSubmitStop = useCallback(async () => { if (isLoading || isSending || isWaitingMakerStart || isWaitingMakerStop) { return } @@ -374,21 +572,13 @@ export default function Earn({ wallet }: EarnProps) { setAlert(undefined) try { - if (serviceInfo?.makerRunning === true) { - setServiceInfoAlert({ variant: 'success', message: t('earn.alert_stopping') }) - await stopMakerService() - } else { - persistFormValues(values) - - setServiceInfoAlert({ variant: 'success', message: t('earn.alert_starting') }) - - await startMakerService(values) - } + setServiceInfoAlert({ variant: 'success', message: t('earn.alert_stopping') }) + await stopMakerService() } catch (e: any) { setServiceInfoAlert(undefined) setAlert({ variant: 'danger', message: e.message || t('global.errors.reason_unknown') }) } - } + }, [stopMakerService, isLoading, isSending, isWaitingMakerStart, isWaitingMakerStop, t]) return (
@@ -494,166 +684,18 @@ export default function Earn({ wallet }: EarnProps) {
)} - {!serviceInfo?.coinjoinInProgress && ( - - {({ handleSubmit, setFieldValue, handleChange, handleBlur, values, touched, errors, isSubmitting }) => ( - <> - - {!serviceInfo?.makerRunning && !isWaitingMakerStart && !isWaitingMakerStop && ( - - <> - - { - checked && setFieldValue('offertype', tab.value, true) - }} - initialValue={values.offertype} - disabled={isLoading || isSubmitting} - /> - - {values.offertype === OFFERTYPE_REL ? ( - - - {t('earn.label_rel_fee', { - fee: - typeof values.feeRel === 'number' ? `(${factorToPercentage(values.feeRel)}%)` : '', - })} - - - {t('earn.description_rel_fee')} - - {isLoading ? ( - - - - ) : ( - - - % - - { - const value = e.target.value || '' - setFieldValue( - 'feeRel', - value !== '' ? percentageToFactor(parseInt(value, 10)) : '', - true, - ) - }} - onBlur={handleBlur} - value={typeof values.feeRel === 'number' ? factorToPercentage(values.feeRel) : ''} - isValid={touched.feeRel && !errors.feeRel} - isInvalid={touched.feeRel && !!errors.feeRel} - min={0} - step={feeRelPercentageStep} - /> - {errors.feeRel} - - )} - - ) : ( - - - {t('earn.label_abs_fee', { - fee: - typeof values.feeAbs === 'number' - ? `(${values.feeAbs} ${values.feeAbs === 1 ? 'sat' : 'sats'})` - : '', - })} - - - {t('earn.description_abs_fee')} - - {isLoading ? ( - - - - ) : ( - - - - - - {errors.feeAbs} - - )} - - )} - - {t('earn.label_min_amount')} - {isLoading ? ( - - - - ) : ( - - - - - - {errors.minsize} - - )} - - - - )} - -
+ {!serviceInfo?.coinjoinInProgress && ( + <> + {!serviceInfo?.makerRunning && !isWaitingMakerStart && !isWaitingMakerStop ? ( + { + return ( + <> {isWaitingMakerStart || isWaitingMakerStop ? ( <> {serviceInfo?.makerRunning === true ? t('earn.button_stop') : t('earn.button_start')} )} -
-
-
- + + ) + }} + /> + ) : ( + + {({ handleSubmit, isSubmitting }) => ( + + +
+ {isWaitingMakerStart || isWaitingMakerStop ? ( + <> +
+
+
+ )} +
)} -
+ )}