diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b909a43..c5992336 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ### Fixed +- `BatchTip` now reports accurate outcome summaries after on-chain + confirmation instead of always showing a blanket success toast. Non-strict + batch results are parsed to show full success, partial success, or all + failed outcomes (Issue #238). + - `RecentTips` tip-back modal now provides complete dialog keyboard support: it traps `Tab`/`Shift+Tab` focus within the modal, closes on `Escape`, restores focus to the previously focused trigger on close, and supports @@ -56,6 +61,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). `Escape` close with focus restoration, focus trapping, and backdrop click close behavior. +### Added (Issue #238) + +- `frontend/src/lib/batchTipResults.js` with result parsing helpers used to + summarize per-recipient outcomes from confirmed batch-tip transactions. +- `frontend/src/test/batch-tip-results.test.js` with 6 tests covering + non-strict result parsing, strict-mode fallback parsing, and final + user-facing outcome message generation. + - Four components (`Leaderboard`, `RecentTips`, `TipHistory`, `useNotifications`) each polled the same Stacks API contract-events endpoint on independent intervals, generating up to 15+ requests per diff --git a/frontend/src/components/BatchTip.jsx b/frontend/src/components/BatchTip.jsx index bfb4172f..3b0005ce 100644 --- a/frontend/src/components/BatchTip.jsx +++ b/frontend/src/components/BatchTip.jsx @@ -14,10 +14,12 @@ import { CONTRACT_ADDRESS, CONTRACT_NAME, FN_SEND_BATCH_TIPS, FN_SEND_BATCH_TIPS import { toMicroSTX, formatSTX, formatAddress } from '../lib/utils'; import { formatBalance } from '../lib/balance-utils'; import { analytics } from '../lib/analytics'; +import { summarizeBatchTipResult, buildBatchTipOutcomeMessage } from '../lib/batchTipResults'; import { useBalance } from '../hooks/useBalance'; import { useTipContext } from '../context/TipContext'; import { Users, Plus, Trash2, Send, Loader2, AlertTriangle } from 'lucide-react'; import ConfirmDialog from './ui/confirm-dialog'; +import TxStatus from './ui/tx-status'; const MAX_BATCH_SIZE = 50; const MIN_TIP_STX = 0.001; @@ -33,6 +35,7 @@ export default function BatchTip({ addToast }) { const [sending, setSending] = useState(false); const [showConfirm, setShowConfirm] = useState(false); const [errors, setErrors] = useState({}); + const [pendingTx, setPendingTx] = useState(null); const senderAddress = useMemo(() => getSenderAddress(), []); @@ -187,13 +190,12 @@ export default function BatchTip({ addToast }) { postConditionMode: PostConditionMode.Deny, onFinish: (data) => { setSending(false); - analytics.trackBatchTipConfirmed(); + setPendingTx({ txId: data.txId, totalRecipients: recipients.length, strictMode }); setRecipients([emptyRecipient()]); setErrors({}); - notifyTipSent(); addToast?.( - `Batch of ${recipients.length} tips sent! Tx: ${data.txId}`, - 'success' + `Batch transaction submitted. Waiting for confirmation... Tx: ${data.txId}`, + 'info' ); }, onCancel: () => { @@ -210,6 +212,25 @@ export default function BatchTip({ addToast }) { } }; + const handleBatchTxConfirmed = useCallback((txData) => { + analytics.trackBatchTipConfirmed(); + notifyTipSent(); + + const summary = summarizeBatchTipResult(txData, pendingTx?.totalRecipients ?? 0); + const toastType = summary.failureCount === 0 + ? 'success' + : summary.successCount > 0 + ? 'warning' + : 'error'; + + addToast?.(buildBatchTipOutcomeMessage(summary), toastType); + }, [addToast, notifyTipSent, pendingTx?.totalRecipients]); + + const handleBatchTxFailed = useCallback((reason) => { + analytics.trackBatchTipFailed(); + addToast?.(`Batch transaction failed: ${reason}`, 'error'); + }, [addToast]); + return (