From 728045e81a4a8e33be38ab42b4bf1e2fd6ae9a84 Mon Sep 17 00:00:00 2001 From: Patricio Marroquin <55117912+patricio0312rev@users.noreply.github.com> Date: Tue, 16 Jul 2024 04:51:01 -0500 Subject: [PATCH] refactor: back button for approval pages (#439) --- src/components/approve/ApproveFooter.tsx | 5 ++-- src/components/approve/ApproveTransaction.tsx | 14 +++++++++- src/components/approve/ApproveVote.tsx | 22 ++++++++++++--- src/components/fees/FeeOption.tsx | 6 +++-- src/components/fees/FeeOptionsList.tsx | 9 ++++++- src/components/fees/FeeSection.tsx | 27 ++++++++++++++++++- src/components/send/SendForm.tsx | 2 ++ src/components/vote/VoteFee.tsx | 6 +++++ src/constants.ts | 10 +++++++ src/i18n/ns/action.ts | 1 + src/pages/Send.tsx | 15 ++++++++++- src/pages/Vote.tsx | 27 ++++++++++++++++--- 12 files changed, 129 insertions(+), 15 deletions(-) diff --git a/src/components/approve/ApproveFooter.tsx b/src/components/approve/ApproveFooter.tsx index cea628885..a852025bb 100644 --- a/src/components/approve/ApproveFooter.tsx +++ b/src/components/approve/ApproveFooter.tsx @@ -5,9 +5,10 @@ type Props = { disabled?: boolean; onSubmit: () => Promise; onCancel: () => Promise; + isNative?: boolean; }; -const ApproveFooter = ({ disabled, onSubmit, onCancel }: Props) => { +const ApproveFooter = ({ disabled, onSubmit, onCancel, isNative }: Props) => { const { t } = useTranslation(); const onApprove = async () => { if (disabled) return; @@ -18,7 +19,7 @@ const ApproveFooter = ({ disabled, onSubmit, onCancel }: Props) => { return (
); diff --git a/src/components/fees/FeeSection.tsx b/src/components/fees/FeeSection.tsx index 93f4bea31..b51158b15 100644 --- a/src/components/fees/FeeSection.tsx +++ b/src/components/fees/FeeSection.tsx @@ -6,6 +6,7 @@ import { useNetworkFees } from '@/lib/hooks/useNetworkFees'; import useActiveNetwork from '@/lib/hooks/useActiveNetwork'; import { NumericInput } from '@/shared/components/input/NumericInput'; import { useProfileContext } from '@/lib/context/Profile'; +import constants from '@/constants'; type AddressDropdownProps = ComponentPropsWithRef<'input'> & { variant?: 'primary' | 'destructive'; @@ -14,6 +15,8 @@ type AddressDropdownProps = ComponentPropsWithRef<'input'> & { setValue: (value: string) => void; feeType?: string; step?: number; + feeClass?: string; + handleFeeClassChange?: (feeClass: string) => void; }; export const FeeSection = ({ @@ -23,10 +26,14 @@ export const FeeSection = ({ setValue, step = 0.01, feeType = 'transfer', + feeClass = constants.FEE_DEFAULT, + handleFeeClassChange, ...rest }: AddressDropdownProps) => { const { t } = useTranslation(); - const [advancedFeeView, setAdvancedFeeView] = useState(false); + const [advancedFeeView, setAdvancedFeeView] = useState( + feeClass === constants.FEE_CUSTOM, + ); const activeNetwork = useActiveNetwork(); const { profile } = useProfileContext(); @@ -42,6 +49,7 @@ export const FeeSection = ({ onFeeChange(fees.avg); } setAdvancedFeeView(!advancedFeeView); + handleFeeClassChange?.(!advancedFeeView ? constants.FEE_CUSTOM : constants.FEE_DEFAULT); }; const onFeeChange = (value: string) => { @@ -54,6 +62,22 @@ export const FeeSection = ({ } }, [fees, advancedFeeView]); + useEffect(() => { + if (feeClass !== constants.FEE_CUSTOM && fees) { + switch (feeClass) { + case constants.FEE_SLOW: + onFeeChange(fees.min); + break; + case constants.FEE_DEFAULT: + onFeeChange(fees.avg); + break; + case constants.FEE_FAST: + onFeeChange(fees.max); + break; + } + } + }, []); + return (
@@ -85,6 +109,7 @@ export const FeeSection = ({ isLoading={isLoadingFee} setFee={onFeeChange} fee={value} + setFeeClass={(feeClass: string) => handleFeeClassChange?.(feeClass)} /> )}
diff --git a/src/components/send/SendForm.tsx b/src/components/send/SendForm.tsx index 343d8017b..168850dd0 100644 --- a/src/components/send/SendForm.tsx +++ b/src/components/send/SendForm.tsx @@ -119,6 +119,8 @@ export const SendForm = ({ formik }: { formik: FormikProps }) => { helperText={formik.values.fee ? formik.errors.fee : undefined} value={formik.values.fee} setValue={(value: string) => formik.setFieldValue('fee', value)} + feeClass={formik.values.feeClass} + handleFeeClassChange={(value: string) => formik.setFieldValue('feeClass', value)} />
); diff --git a/src/components/vote/VoteFee.tsx b/src/components/vote/VoteFee.tsx index d85427aff..0273c312c 100644 --- a/src/components/vote/VoteFee.tsx +++ b/src/components/vote/VoteFee.tsx @@ -12,6 +12,8 @@ export const VoteFee = ({ onSelectedFee, onBlur, handleFeeInputChange, + feeClass, + handleFeeClassChange, }: { delegateAddress?: string; fee: string; @@ -19,6 +21,8 @@ export const VoteFee = ({ onSelectedFee: (fee: string) => void; onBlur: FocusEventHandler; handleFeeInputChange: (event: React.ChangeEvent) => void; + feeClass?: string; + handleFeeClassChange?: (feeClass: string) => void; }) => { const { t } = useTranslation(); const [isEditing, setIsEditing] = useState(false); @@ -56,6 +60,8 @@ export const VoteFee = ({ value={fee} setValue={onSelectedFee} feeType='vote' + feeClass={feeClass} + handleFeeClassChange={handleFeeClassChange} /> ); diff --git a/src/constants.ts b/src/constants.ts index a03373fa7..d81f3f8aa 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -39,6 +39,12 @@ const MAX_FEES = { const MAC_OS = 'mac'; const DEFAULT_OS = 'default'; // For Windows and Linux +// Fee classes +const FEE_SLOW = 'slow'; +const FEE_FAST = 'fast'; +const FEE_DEFAULT = 'default'; +const FEE_CUSTOM = 'custom'; + const constants = { APP_NAME, SUPPORT_EMAIL, @@ -65,6 +71,10 @@ const constants = { GITHUB_RELEASES_URL, MAC_OS, DEFAULT_OS, + FEE_SLOW, + FEE_FAST, + FEE_DEFAULT, + FEE_CUSTOM, }; export default constants; diff --git a/src/i18n/ns/action.ts b/src/i18n/ns/action.ts index 858645dc9..c8d25f317 100644 --- a/src/i18n/ns/action.ts +++ b/src/i18n/ns/action.ts @@ -1,5 +1,6 @@ export default { APPROVE: 'Approve', + BACK: 'Back', CANCEL: 'Cancel', CLOSE: 'Close', CONFIRM_IMPORT: 'Confirm & Import', diff --git a/src/pages/Send.tsx b/src/pages/Send.tsx index b1a238430..11911c0b9 100644 --- a/src/pages/Send.tsx +++ b/src/pages/Send.tsx @@ -3,7 +3,7 @@ import { useEffect, useState } from 'react'; import { BigNumber } from '@ardenthq/sdk-helpers'; import { runtime } from 'webextension-polyfill'; import { useFormik } from 'formik'; -import { useNavigate } from 'react-router-dom'; +import { useNavigate, useSearchParams } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { validateAddress } from './CreateContact'; @@ -23,6 +23,7 @@ export type SendFormik = { memo?: string; fee: string; receiverAddress: string; + feeClass?: string; }; interface PageData extends SendFormik { @@ -40,6 +41,7 @@ const Send = () => { const { t } = useTranslation(); const { profile } = useProfileContext(); const [isModalOpen, setIsModalOpen] = useState(false); + const [searchParams] = useSearchParams(); const lastVisitedPage = profile.settings().get('LAST_VISITED_PAGE') as { data: PageData }; @@ -99,6 +101,12 @@ const Send = () => { return Number(value) <= constants.MAX_FEES.transfer; }) .trim(), + feeClass: string().oneOf([ + constants.FEE_CUSTOM, + constants.FEE_DEFAULT, + constants.FEE_FAST, + constants.FEE_SLOW, + ]), receiverAddress: string() .required(t('ERROR.IS_REQUIRED', { name: 'Address' })) .min( @@ -134,6 +142,10 @@ const Send = () => { amount: lastVisitedPage?.data?.amount || '', memo: lastVisitedPage?.data?.memo || '', fee: lastVisitedPage?.data?.fee || '', + feeClass: + searchParams.get('feeClass') || + lastVisitedPage?.data?.feeClass || + constants.FEE_DEFAULT, receiverAddress: lastVisitedPage?.data?.receiverAddress || '', }, validationSchema: validationSchema, @@ -155,6 +167,7 @@ const Send = () => { logo: 'icon/128.png', domain: constants.APP_NAME, }, + feeClass: formik.values.feeClass, }, }); }, diff --git a/src/pages/Vote.tsx b/src/pages/Vote.tsx index 891f9afb8..31a0e2fde 100644 --- a/src/pages/Vote.tsx +++ b/src/pages/Vote.tsx @@ -5,7 +5,7 @@ import { useEffect, useMemo, useState } from 'react'; import { BigNumber } from '@ardenthq/sdk-helpers'; import { runtime } from 'webextension-polyfill'; import { useFormik } from 'formik'; -import { useNavigate } from 'react-router-dom'; +import { useNavigate, useSearchParams } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { DelegatesList } from '@/components/vote/DelegatesList'; import { DelegatesSearchInput } from '@/components/vote/DelegatesSearchInput'; @@ -25,6 +25,7 @@ import { useVote } from '@/lib/hooks/useVote'; export type VoteFormik = { delegateAddress?: string; fee: string; + feeClass?: string; }; interface PageData extends VoteFormik { @@ -38,7 +39,7 @@ interface PageData extends VoteFormik { const Vote = () => { const navigate = useNavigate(); - + const [searchParams] = useSearchParams(); const { t } = useTranslation(); const { profile } = useProfileContext(); const { env } = useEnvironmentContext(); @@ -78,6 +79,12 @@ const Vote = () => { return Number(value) <= constants.MAX_FEES.vote; }) .trim(), + feeClass: string().oneOf([ + constants.FEE_CUSTOM, + constants.FEE_DEFAULT, + constants.FEE_FAST, + constants.FEE_SLOW, + ]), delegateAddress: string() .required(t('ERROR.IS_REQUIRED', { name: 'Delegate' })) .min( @@ -134,14 +141,22 @@ const Vote = () => { logo: 'icon/128.png', domain: constants.APP_NAME, }, + feeClass: formik.values.feeClass, }, }); }; const formik = useFormik({ initialValues: { - fee: lastVisitedPage?.data?.fee || '', - delegateAddress: lastVisitedPage?.data?.delegateAddress, + fee: searchParams.get('fee') || lastVisitedPage?.data?.fee || '', + feeClass: + searchParams.get('feeClass') || + lastVisitedPage?.data?.feeClass || + constants.FEE_DEFAULT, + delegateAddress: + searchParams.get('vote') || + searchParams.get('unvote') || + lastVisitedPage?.data?.delegateAddress, }, validationSchema: validationSchema, validateOnMount: true, @@ -220,6 +235,10 @@ const Vote = () => { onBlur={formik.handleBlur} feeError={formik.errors.fee} handleFeeInputChange={handleFeeInputChange} + feeClass={formik.values.feeClass} + handleFeeClassChange={(feeClass) => + formik.setFieldValue('feeClass', feeClass) + } />