diff --git a/src/components/sweep/SweepScheduleProgress.tsx b/src/components/sweep/SweepScheduleProgress.tsx index 73ea7aaa..05b93fd0 100644 --- a/src/components/sweep/SweepScheduleProgress.tsx +++ b/src/components/sweep/SweepScheduleProgress.tsx @@ -4,7 +4,7 @@ import { Button } from '@/components/ui/button' import { Card, CardContent } from '@/components/ui/card' import { cn } from '@/lib/utils' import { Spinner } from '../ui/spinner' -import type { Schedule } from './scheduleUtils' +import type { Schedule, ScheduleEntryState } from './scheduleUtils' import { toScheduleProgressSummary } from './scheduleUtils' interface SweepScheduleProgressProps { @@ -43,6 +43,30 @@ export const SweepScheduleProgress = ({ schedule, isStopping, onStop }: SweepSch '3': , } + const formatWaitTime = (seconds: number): string => { + const roundedSeconds = Math.max(0, Math.ceil(seconds)) + const minutes = Math.floor(roundedSeconds / 60) + const remainingSeconds = roundedSeconds % 60 + + if (minutes === 0) { + return t('scheduler.progress_wait_seconds', { seconds: remainingSeconds }) + } + if (remainingSeconds === 0) { + return t('scheduler.progress_wait_minutes', { minutes }) + } + return t('scheduler.progress_wait_minutes_seconds', { minutes, seconds: remainingSeconds }) + } + + const toScheduleEntryStateText = (state: ScheduleEntryState, txid?: string): string => { + if (state === 'confirmed') { + return t('scheduler.progress_entry_state_confirmed') + } + if (state === 'broadcasted') { + return t('scheduler.progress_entry_state_waiting_confirmation', { txid: txid ?? '-' }) + } + return t('scheduler.progress_entry_state_pending') + } + return ( @@ -78,19 +102,73 @@ export const SweepScheduleProgress = ({ schedule, isStopping, onStop }: SweepSch - + {/* Keep a stable fallback state so brief polling gaps never leave this header empty. */} + {progress.currentState?.type === 'waiting_before_next' ? ( + + ) : progress.currentState?.type === 'waiting_for_confirmation' ? ( + + ) : progress.currentState?.type === 'transaction_confirmed' ? ( + + ) : ( + + )} )} +
+
{t('scheduler.progress_schedule_info_title')}
+
+ {progress.entries.map((entry) => ( +
+
{t('scheduler.progress_entry_label', { index: entry.index + 1 })}
+
{toScheduleEntryStateText(entry.state, entry.txid)}
+
+ {entry.isLast + ? t('scheduler.progress_entry_wait_final') + : t('scheduler.progress_entry_wait_before_next', { + wait: formatWaitTime(entry.waitBeforeNextSeconds), + })} +
+
+ ))} +
+
+