From 047a8ab7794b3b0e071bfac200221064fc8ebb0e Mon Sep 17 00:00:00 2001 From: Kishore B Date: Tue, 11 Aug 2026 21:50:55 +0530 Subject: [PATCH] refactor(ui): consolidate Send and Sweep precondition alerts (#1402) Signed-off-by: kishore08-07 --- .../send/SendCoinjoinPreconditionAlert.tsx | 91 +-------- .../sweep/SweepPreconditionAlert.tsx | 91 +-------- src/components/ui/jam/PreconditionAlert.tsx | 102 ++++++++++ src/stories/jam/PreconditionAlert.stories.tsx | 179 ++++++++++++++++++ .../SendCoinJoinPreconditionAlert.stories.tsx | 116 ------------ .../jam/SweepPreconditionAlert.stories.tsx | 116 ------------ 6 files changed, 285 insertions(+), 410 deletions(-) create mode 100644 src/components/ui/jam/PreconditionAlert.tsx create mode 100644 src/stories/jam/PreconditionAlert.stories.tsx delete mode 100644 src/stories/jam/SendCoinJoinPreconditionAlert.stories.tsx delete mode 100644 src/stories/jam/SweepPreconditionAlert.stories.tsx diff --git a/src/components/send/SendCoinjoinPreconditionAlert.tsx b/src/components/send/SendCoinjoinPreconditionAlert.tsx index e02e8f92..3a470de9 100644 --- a/src/components/send/SendCoinjoinPreconditionAlert.tsx +++ b/src/components/send/SendCoinjoinPreconditionAlert.tsx @@ -1,97 +1,10 @@ -import { AlertTriangleIcon } from 'lucide-react' -import { Trans, useTranslation } from 'react-i18next' -import { Link } from 'react-router-dom' import type { SweepPreconditionSummary } from '@/components/sweep/preconditions' -import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert' -import { Balance } from '@/components/ui/jam/Balance' -import { JAM_JM_RETRIES_DOCS_URL } from '@/constants/jam' -import { routes } from '@/constants/routes' -import { shortenStringMiddle } from '@/lib/utils' -import { JarBadge } from '../earn/fidelity-bond/FidelityBondDialogParts' +import { PreconditionAlert } from '@/components/ui/jam/PreconditionAlert' interface SendCoinjoinPreconditionAlertProps { summary: SweepPreconditionSummary } -const RetryLockedUtxoList = ({ summary }: SendCoinjoinPreconditionAlertProps) => { - const { t } = useTranslation() - - return ( - <> - - ), - }} - /> -
-
{t('global.utxos')}
-
    - {summary.retryLockedUtxos.map((utxo) => ( -
  • - - - - {shortenStringMiddle(utxo.utxo, 26)} - -
  • - ))} -
-
- - ) -} - export const SendCoinjoinPreconditionAlert = ({ summary }: SendCoinjoinPreconditionAlertProps) => { - const { t } = useTranslation() - - if (summary.isFulfilled) { - return null - } - - return ( - - - {t('send.coinjoin_precondition.title')} - -
    - {summary.numberOfNonFrozenFidelityBondOutputs === 0 ? null : ( -
  • - , - }} - /> -
  • - )} - {summary.numberOfMissingUtxos === 0 ? null : ( -
  • - {t('send.coinjoin_precondition.hint_missing_utxos', { - minConfirmations: summary.options.minConfirmations, - })} -
  • - )} - {summary.numberOfMissingConfirmations === 0 ? null : ( -
  • - {t('send.coinjoin_precondition.hint_missing_confirmations', { - minConfirmations: summary.options.minConfirmations, - amountOfMissingConfirmations: summary.numberOfMissingConfirmations, - })} -
  • - )} - {summary.retryLockedUtxos.length === 0 ? null :
  • {}
  • } -
-
-
- ) + return } diff --git a/src/components/sweep/SweepPreconditionAlert.tsx b/src/components/sweep/SweepPreconditionAlert.tsx index afb1440e..fc5c6eb5 100644 --- a/src/components/sweep/SweepPreconditionAlert.tsx +++ b/src/components/sweep/SweepPreconditionAlert.tsx @@ -1,97 +1,10 @@ -import { AlertTriangleIcon } from 'lucide-react' -import { Trans, useTranslation } from 'react-i18next' -import { Link } from 'react-router-dom' import type { SweepPreconditionSummary } from '@/components/sweep/preconditions' -import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert' -import { Balance } from '@/components/ui/jam/Balance' -import { JAM_JM_RETRIES_DOCS_URL } from '@/constants/jam' -import { routes } from '@/constants/routes' -import { shortenStringMiddle } from '@/lib/utils' -import { JarBadge } from '../earn/fidelity-bond/FidelityBondDialogParts' +import { PreconditionAlert } from '@/components/ui/jam/PreconditionAlert' interface SweepPreconditionAlertProps { summary: SweepPreconditionSummary } -const RetryLockedUtxoList = ({ summary }: SweepPreconditionAlertProps) => { - const { t } = useTranslation() - - return ( - <> - - ), - }} - /> -
-
{t('global.utxos')}
-
    - {summary.retryLockedUtxos.map((utxo) => ( -
  • - - - - {shortenStringMiddle(utxo.utxo, 26)} - -
  • - ))} -
-
- - ) -} - export const SweepPreconditionAlert = ({ summary }: SweepPreconditionAlertProps) => { - const { t } = useTranslation() - - if (summary.isFulfilled) { - return null - } - - return ( - - - {t('scheduler.precondition.title')} - -
    - {summary.numberOfNonFrozenFidelityBondOutputs === 0 ? null : ( -
  • - , - }} - /> -
  • - )} - {summary.numberOfMissingUtxos === 0 ? null : ( -
  • - {t('scheduler.precondition.hint_missing_utxos', { - minConfirmations: summary.options.minConfirmations, - })} -
  • - )} - {summary.numberOfMissingConfirmations === 0 ? null : ( -
  • - {t('scheduler.precondition.hint_missing_confirmations', { - minConfirmations: summary.options.minConfirmations, - amountOfMissingConfirmations: summary.numberOfMissingConfirmations, - })} -
  • - )} - {summary.retryLockedUtxos.length === 0 ? null :
  • {}
  • } -
-
-
- ) + return } diff --git a/src/components/ui/jam/PreconditionAlert.tsx b/src/components/ui/jam/PreconditionAlert.tsx new file mode 100644 index 00000000..ce42d921 --- /dev/null +++ b/src/components/ui/jam/PreconditionAlert.tsx @@ -0,0 +1,102 @@ +import { AlertTriangleIcon } from 'lucide-react' +import { Trans, useTranslation } from 'react-i18next' +import { Link } from 'react-router-dom' +import { JarBadge } from '@/components/earn/fidelity-bond/FidelityBondDialogParts' +import type { SweepPreconditionSummary } from '@/components/sweep/preconditions' +import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert' +import { Balance } from '@/components/ui/jam/Balance' +import { JAM_JM_RETRIES_DOCS_URL } from '@/constants/jam' +import { routes } from '@/constants/routes' +import { shortenStringMiddle } from '@/lib/utils' + +export interface PreconditionAlertProps { + summary: SweepPreconditionSummary + i18nPrefix: 'send.coinjoin_precondition' | 'scheduler.precondition' +} + +const RetryLockedUtxoList = ({ summary, i18nPrefix }: PreconditionAlertProps) => { + const { t } = useTranslation() + + return ( + <> + + ), + }} + /> +
+
{t('global.utxos')}
+
    + {summary.retryLockedUtxos.map((utxo) => ( +
  • + + + + {shortenStringMiddle(utxo.utxo, 26)} + +
  • + ))} +
+
+ + ) +} + +export const PreconditionAlert = ({ summary, i18nPrefix }: PreconditionAlertProps) => { + const { t } = useTranslation() + + if (summary.isFulfilled) { + return null + } + + return ( + + + {t(`${i18nPrefix}.title`)} + +
    + {summary.numberOfNonFrozenFidelityBondOutputs === 0 ? null : ( +
  • + , + }} + /> +
  • + )} + {summary.numberOfMissingUtxos === 0 ? null : ( +
  • + {t(`${i18nPrefix}.hint_missing_utxos`, { + minConfirmations: summary.options.minConfirmations, + })} +
  • + )} + {summary.numberOfMissingConfirmations === 0 ? null : ( +
  • + {t(`${i18nPrefix}.hint_missing_confirmations`, { + minConfirmations: summary.options.minConfirmations, + amountOfMissingConfirmations: summary.numberOfMissingConfirmations, + })} +
  • + )} + {summary.retryLockedUtxos.length === 0 ? null : ( +
  • + +
  • + )} +
+
+
+ ) +} diff --git a/src/stories/jam/PreconditionAlert.stories.tsx b/src/stories/jam/PreconditionAlert.stories.tsx new file mode 100644 index 00000000..45b2d11c --- /dev/null +++ b/src/stories/jam/PreconditionAlert.stories.tsx @@ -0,0 +1,179 @@ +import type { Meta, StoryObj } from '@storybook/react-vite' +import { SWEEP_PRECONDITION_DEFAULT_OPTIONS } from '@/components/sweep/preconditions' +import { PreconditionAlert } from '@/components/ui/jam/PreconditionAlert' +import type { Utxo } from '@/hooks/useQueryUtxos' + +const DEFAULT_SUMMARY = Object.freeze({ + isFulfilled: false, + options: SWEEP_PRECONDITION_DEFAULT_OPTIONS, + numberOfMissingUtxos: 0, + numberOfMissingConfirmations: 0, + numberOfNonFrozenFidelityBondOutputs: 0, + retryLockedUtxos: [], +}) + +const makeUtxo = (overrides: Partial = {}): Utxo => + ({ + address: 'bc1qsource', + confirmations: 6, + frozen: false, + label: '', + locktime: undefined, + mixdepth: 0, + path: '', + tries_remaining: 3, + utxo: '4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0', + value: 100_000, + ...overrides, + }) as Utxo + +const meta: Meta = { + title: 'Jam/PreconditionAlert', + component: PreconditionAlert, + tags: ['autodocs'], + args: { + summary: DEFAULT_SUMMARY, + i18nPrefix: 'send.coinjoin_precondition', + }, +} +export default meta + +type Story = StoryObj + +// --- Send Flow Stories --- + +export const SendDefault: Story = { + args: { + i18nPrefix: 'send.coinjoin_precondition', + }, +} + +export const SendMissingUtxos: Story = { + args: { + i18nPrefix: 'send.coinjoin_precondition', + summary: { + ...DEFAULT_SUMMARY, + numberOfMissingUtxos: 3, + }, + }, +} + +export const SendMissingConfirmations: Story = { + args: { + i18nPrefix: 'send.coinjoin_precondition', + summary: { + ...DEFAULT_SUMMARY, + numberOfMissingConfirmations: 3, + }, + }, +} + +export const SendNonFrozenFidelityBondsPresent: Story = { + args: { + i18nPrefix: 'send.coinjoin_precondition', + summary: { + ...DEFAULT_SUMMARY, + numberOfNonFrozenFidelityBondOutputs: 3, + }, + }, +} + +export const SendRetryLockedUtxos: Story = { + args: { + i18nPrefix: 'send.coinjoin_precondition', + summary: { + ...DEFAULT_SUMMARY, + retryLockedUtxos: [ + makeUtxo({ mixdepth: 0, value: 21 }), + makeUtxo({ mixdepth: 1, value: 21_000 }), + makeUtxo({ mixdepth: 2, value: 21_000_000 }), + ], + }, + }, +} + +export const SendMultiple: Story = { + args: { + i18nPrefix: 'send.coinjoin_precondition', + summary: { + ...DEFAULT_SUMMARY, + numberOfMissingUtxos: 3, + numberOfMissingConfirmations: 3, + numberOfNonFrozenFidelityBondOutputs: 3, + retryLockedUtxos: [ + makeUtxo({ mixdepth: 0, value: 21 }), + makeUtxo({ mixdepth: 1, value: 21_000 }), + makeUtxo({ mixdepth: 2, value: 21_000_000 }), + ], + }, + }, +} + +// --- Sweep Flow Stories --- + +export const SweepDefault: Story = { + args: { + i18nPrefix: 'scheduler.precondition', + }, +} + +export const SweepMissingUtxos: Story = { + args: { + i18nPrefix: 'scheduler.precondition', + summary: { + ...DEFAULT_SUMMARY, + numberOfMissingUtxos: 3, + }, + }, +} + +export const SweepMissingConfirmations: Story = { + args: { + i18nPrefix: 'scheduler.precondition', + summary: { + ...DEFAULT_SUMMARY, + numberOfMissingConfirmations: 3, + }, + }, +} + +export const SweepNonFrozenFidelityBondsPresent: Story = { + args: { + i18nPrefix: 'scheduler.precondition', + summary: { + ...DEFAULT_SUMMARY, + numberOfNonFrozenFidelityBondOutputs: 3, + }, + }, +} + +export const SweepRetryLockedUtxos: Story = { + args: { + i18nPrefix: 'scheduler.precondition', + summary: { + ...DEFAULT_SUMMARY, + retryLockedUtxos: [ + makeUtxo({ mixdepth: 0, value: 21 }), + makeUtxo({ mixdepth: 1, value: 21_000 }), + makeUtxo({ mixdepth: 2, value: 21_000_000 }), + ], + }, + }, +} + +export const SweepMultiple: Story = { + args: { + i18nPrefix: 'scheduler.precondition', + summary: { + ...DEFAULT_SUMMARY, + numberOfMissingUtxos: 3, + numberOfMissingConfirmations: 3, + numberOfNonFrozenFidelityBondOutputs: 3, + retryLockedUtxos: [ + makeUtxo({ mixdepth: 0, value: 21 }), + makeUtxo({ mixdepth: 1, value: 21_000 }), + makeUtxo({ mixdepth: 2, value: 21_000_000 }), + ], + }, + }, +} diff --git a/src/stories/jam/SendCoinJoinPreconditionAlert.stories.tsx b/src/stories/jam/SendCoinJoinPreconditionAlert.stories.tsx deleted file mode 100644 index cca58e5c..00000000 --- a/src/stories/jam/SendCoinJoinPreconditionAlert.stories.tsx +++ /dev/null @@ -1,116 +0,0 @@ -import type { Meta, StoryObj } from '@storybook/react-vite' -import { SendCoinjoinPreconditionAlert } from '@/components/send/SendCoinjoinPreconditionAlert' -import { SWEEP_PRECONDITION_DEFAULT_OPTIONS } from '@/components/sweep/preconditions' -import type { Utxo } from '@/hooks/useQueryUtxos' - -const DEFAULT_SUMMARY = Object.freeze({ - isFulfilled: false, - options: SWEEP_PRECONDITION_DEFAULT_OPTIONS, - numberOfMissingUtxos: 0, - numberOfMissingConfirmations: 0, - numberOfNonFrozenFidelityBondOutputs: 0, - retryLockedUtxos: [], -}) - -const makeUtxo = (overrides: Partial = {}): Utxo => - ({ - address: 'bc1qsource', - confirmations: 6, - frozen: false, - label: '', - locktime: undefined, - mixdepth: 0, - path: '', - tries_remaining: 3, - utxo: '4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0', - value: 100_000, - ...overrides, - }) as Utxo - -const meta: Meta = { - title: 'Jam/SendCoinjoinPreconditionAlert', - component: SendCoinjoinPreconditionAlert, - tags: ['autodocs'], - args: { - summary: DEFAULT_SUMMARY, - }, -} -export default meta - -type Story = StoryObj - -export const Default: Story = {} - -export const MissingUtxos: Story = { - args: { - summary: { - ...DEFAULT_SUMMARY, - numberOfMissingUtxos: 3, - }, - }, -} - -export const MissingConfirmations: Story = { - args: { - summary: { - ...DEFAULT_SUMMARY, - numberOfMissingConfirmations: 3, - }, - }, -} - -export const NonFrozenFidelityBondsPresent: Story = { - args: { - summary: { - ...DEFAULT_SUMMARY, - numberOfNonFrozenFidelityBondOutputs: 3, - }, - }, -} - -export const RetryLockedUtxos: Story = { - args: { - summary: { - ...DEFAULT_SUMMARY, - retryLockedUtxos: [ - makeUtxo({ - mixdepth: 0, - value: 21, - }), - makeUtxo({ - mixdepth: 1, - value: 21_000, - }), - makeUtxo({ - mixdepth: 2, - value: 21_000_000, - }), - ], - }, - }, -} - -export const Multiple: Story = { - args: { - summary: { - ...DEFAULT_SUMMARY, - numberOfMissingUtxos: 3, - numberOfMissingConfirmations: 3, - numberOfNonFrozenFidelityBondOutputs: 3, - retryLockedUtxos: [ - makeUtxo({ - mixdepth: 0, - value: 21, - }), - makeUtxo({ - mixdepth: 1, - value: 21_000, - }), - makeUtxo({ - mixdepth: 2, - value: 21_000_000, - }), - ], - }, - }, -} diff --git a/src/stories/jam/SweepPreconditionAlert.stories.tsx b/src/stories/jam/SweepPreconditionAlert.stories.tsx deleted file mode 100644 index 9e8cbef5..00000000 --- a/src/stories/jam/SweepPreconditionAlert.stories.tsx +++ /dev/null @@ -1,116 +0,0 @@ -import type { Meta, StoryObj } from '@storybook/react-vite' -import { SweepPreconditionAlert } from '@/components/sweep/SweepPreconditionAlert' -import { SWEEP_PRECONDITION_DEFAULT_OPTIONS } from '@/components/sweep/preconditions' -import type { Utxo } from '@/hooks/useQueryUtxos' - -const DEFAULT_SUMMARY = Object.freeze({ - isFulfilled: false, - options: SWEEP_PRECONDITION_DEFAULT_OPTIONS, - numberOfMissingUtxos: 0, - numberOfMissingConfirmations: 0, - numberOfNonFrozenFidelityBondOutputs: 0, - retryLockedUtxos: [], -}) - -const makeUtxo = (overrides: Partial = {}): Utxo => - ({ - address: 'bc1qsource', - confirmations: 6, - frozen: false, - label: '', - locktime: undefined, - mixdepth: 0, - path: '', - tries_remaining: 3, - utxo: '4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0', - value: 100_000, - ...overrides, - }) as Utxo - -const meta: Meta = { - title: 'Jam/SweepPreconditionAlert', - component: SweepPreconditionAlert, - tags: ['autodocs'], - args: { - summary: DEFAULT_SUMMARY, - }, -} -export default meta - -type Story = StoryObj - -export const Default: Story = {} - -export const MissingUtxos: Story = { - args: { - summary: { - ...DEFAULT_SUMMARY, - numberOfMissingUtxos: 3, - }, - }, -} - -export const MissingConfirmations: Story = { - args: { - summary: { - ...DEFAULT_SUMMARY, - numberOfMissingConfirmations: 3, - }, - }, -} - -export const NonFrozenFidelityBondsPresent: Story = { - args: { - summary: { - ...DEFAULT_SUMMARY, - numberOfNonFrozenFidelityBondOutputs: 3, - }, - }, -} - -export const RetryLockedUtxos: Story = { - args: { - summary: { - ...DEFAULT_SUMMARY, - retryLockedUtxos: [ - makeUtxo({ - mixdepth: 0, - value: 21, - }), - makeUtxo({ - mixdepth: 1, - value: 21_000, - }), - makeUtxo({ - mixdepth: 2, - value: 21_000_000, - }), - ], - }, - }, -} - -export const Multiple: Story = { - args: { - summary: { - ...DEFAULT_SUMMARY, - numberOfMissingUtxos: 3, - numberOfMissingConfirmations: 3, - numberOfNonFrozenFidelityBondOutputs: 3, - retryLockedUtxos: [ - makeUtxo({ - mixdepth: 0, - value: 21, - }), - makeUtxo({ - mixdepth: 1, - value: 21_000, - }), - makeUtxo({ - mixdepth: 2, - value: 21_000_000, - }), - ], - }, - }, -}