Add delete pending incoming transactions feature

- Add deleteIncomingPending action to TransactionsStore
- Add getIncomingPendingCount and deleteIncomingPending to sqlite
- Update TranHistoryScreen with UI for deleting pending incoming
- Add i18n translations for the new feature

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
minibits-cash
2026-01-29 10:10:10 +01:00
co-authored by Claude Opus 4.5
parent a6b9bd55d8
commit b57d582f6a
7 changed files with 124 additions and 10 deletions
+3
View File
@@ -623,6 +623,9 @@
"tranHistory_deleteErroredDesc": "This will delete %{count} transactions with errors", "tranHistory_deleteErroredDesc": "This will delete %{count} transactions with errors",
"tranHistory_deleteExpired": "Delete expired", "tranHistory_deleteExpired": "Delete expired",
"tranHistory_deleteExpiredDesc": "This will delete %{count} expired transactions", "tranHistory_deleteExpiredDesc": "This will delete %{count} expired transactions",
"tranHistory_deleteIncomingPending": "Delete pending incoming",
"tranHistory_deleteIncomingPendingDesc": "This will delete %{count} pending incoming transaction",
"tranHistory_deleteIncomingPendingDesc_plural": "This will delete %{count} pending incoming transactions",
"tranHistory_deleteReverted": "Delete reverted", "tranHistory_deleteReverted": "Delete reverted",
"tranHistory_deleteRevertedDesc": "This will delete %{count} reverted transactions", "tranHistory_deleteRevertedDesc": "This will delete %{count} reverted transactions",
"tranHistory_listIsComplete": "List is complete", "tranHistory_listIsComplete": "List is complete",
+3
View File
@@ -620,6 +620,9 @@
"tranHistory_deleteErroredDesc": "Esto eliminará %{count} transacciones con errores", "tranHistory_deleteErroredDesc": "Esto eliminará %{count} transacciones con errores",
"tranHistory_deleteExpired": "Eliminar caducado", "tranHistory_deleteExpired": "Eliminar caducado",
"tranHistory_deleteExpiredDesc": "Esto eliminará %{count} transacciones vencidas", "tranHistory_deleteExpiredDesc": "Esto eliminará %{count} transacciones vencidas",
"tranHistory_deleteIncomingPending": "Eliminar pendientes entrantes",
"tranHistory_deleteIncomingPendingDesc": "Esto eliminará %{count} transacción entrante pendiente",
"tranHistory_deleteIncomingPendingDesc_plural": "Esto eliminará %{count} transacciones entrantes pendientes",
"tranHistory_deleteReverted": "Eliminación revertida", "tranHistory_deleteReverted": "Eliminación revertida",
"tranHistory_deleteRevertedDesc": "Esto eliminará %{count} transacciones revertidas", "tranHistory_deleteRevertedDesc": "Esto eliminará %{count} transacciones revertidas",
"tranHistory_listIsComplete": "La lista está completa", "tranHistory_listIsComplete": "La lista está completa",
+3
View File
@@ -621,6 +621,9 @@
"tranHistory_deleteErroredDesc": "Isso excluirá %{count} transações com erros", "tranHistory_deleteErroredDesc": "Isso excluirá %{count} transações com erros",
"tranHistory_deleteExpired": "Excluir expirado", "tranHistory_deleteExpired": "Excluir expirado",
"tranHistory_deleteExpiredDesc": "Isso excluirá %{count} transações expiradas", "tranHistory_deleteExpiredDesc": "Isso excluirá %{count} transações expiradas",
"tranHistory_deleteIncomingPending": "Excluir pendentes recebidas",
"tranHistory_deleteIncomingPendingDesc": "Isso excluirá %{count} transação recebida pendente",
"tranHistory_deleteIncomingPendingDesc_plural": "Isso excluirá %{count} transações recebidas pendentes",
"tranHistory_deleteReverted": "Excluir revertido", "tranHistory_deleteReverted": "Excluir revertido",
"tranHistory_deleteRevertedDesc": "Isso excluirá %{count} transações revertidas", "tranHistory_deleteRevertedDesc": "Isso excluirá %{count} transações revertidas",
"tranHistory_listIsComplete": "Lista completa", "tranHistory_listIsComplete": "Lista completa",
+3
View File
@@ -621,6 +621,9 @@
"tranHistory_deleteErroredDesc": "Toto zmaže %{count} chybných transakcií", "tranHistory_deleteErroredDesc": "Toto zmaže %{count} chybných transakcií",
"tranHistory_deleteExpired": "Zmaž expirované", "tranHistory_deleteExpired": "Zmaž expirované",
"tranHistory_deleteExpiredDesc": "Toto zmaže %{count} expirovaných transakcií", "tranHistory_deleteExpiredDesc": "Toto zmaže %{count} expirovaných transakcií",
"tranHistory_deleteIncomingPending": "Zmaž čakajúce prichádzajúce",
"tranHistory_deleteIncomingPendingDesc": "Toto zmaže %{count} čakajúcu prichádzajúcu transakciu",
"tranHistory_deleteIncomingPendingDesc_plural": "Toto zmaže %{count} čakajúcich prichádzajúcich transakcií",
"tranHistory_deleteReverted": "Zmaž vrátené", "tranHistory_deleteReverted": "Zmaž vrátené",
"tranHistory_deleteRevertedDesc": "Toto zmaže %{count} vrátených transakcií", "tranHistory_deleteRevertedDesc": "Toto zmaže %{count} vrátených transakcií",
"tranHistory_listIsComplete": "Zoznam je ukončený", "tranHistory_listIsComplete": "Zoznam je ukončený",
+22
View File
@@ -10,6 +10,7 @@ import {
TransactionModel, TransactionModel,
Transaction, Transaction,
TransactionStatus, TransactionStatus,
TransactionType,
} from './Transaction' } from './Transaction'
import { Database } from '../services' import { Database } from '../services'
import { log } from '../services/logService' import { log } from '../services/logService'
@@ -262,6 +263,27 @@ export const TransactionsStoreModel = types
return Database.deleteTransactionsByStatus(status) return Database.deleteTransactionsByStatus(status)
}, },
deleteIncomingPending() {
const toDelete: number[] = []
self.transactionsMap.forEach((tx, key) => {
const isPendingIncoming = tx.status === TransactionStatus.PENDING &&
(tx.type === TransactionType.RECEIVE || tx.type === TransactionType.RECEIVE_BY_PAYMENT_REQUEST)
if (isPendingIncoming) {
toDelete.push(tx.id)
self.transactionsMap.delete(key as string)
}
})
if (toDelete.length > 0) {
self.history.replace(self.history.filter(t => !toDelete.includes(t.id)))
self.recentByUnit.replace(self.recentByUnit.filter(t => !toDelete.includes(t.id)))
}
return Database.deleteIncomingPending()
},
})) }))
.actions(self => ({ .actions(self => ({
+31
View File
@@ -62,6 +62,7 @@ export const TranHistoryScreen = observer(function TranHistoryScreen({ route }:
const [expiredDbCount, setExpiredDbCount] = useState<number>(0) const [expiredDbCount, setExpiredDbCount] = useState<number>(0)
const [erroredDbCount, setErroredDbCount] = useState<number>(0) const [erroredDbCount, setErroredDbCount] = useState<number>(0)
const [revertedDbCount, setRevertedDbCount] = useState<number>(0) const [revertedDbCount, setRevertedDbCount] = useState<number>(0)
const [incomingPendingDbCount, setIncomingPendingDbCount] = useState<number>(0)
const [isAll, setIsAll] = useState<boolean>(false) const [isAll, setIsAll] = useState<boolean>(false)
const [pendingIsAll, setPendingIsAll] = useState<boolean>(false) const [pendingIsAll, setPendingIsAll] = useState<boolean>(false)
@@ -76,6 +77,7 @@ export const TranHistoryScreen = observer(function TranHistoryScreen({ route }:
setExpiredDbCount(countByStatus[TransactionStatus.EXPIRED] || 0) setExpiredDbCount(countByStatus[TransactionStatus.EXPIRED] || 0)
setErroredDbCount(countByStatus[TransactionStatus.ERROR] || 0) setErroredDbCount(countByStatus[TransactionStatus.ERROR] || 0)
setRevertedDbCount(countByStatus[TransactionStatus.REVERTED] || 0) setRevertedDbCount(countByStatus[TransactionStatus.REVERTED] || 0)
setIncomingPendingDbCount(Database.getIncomingPendingCount())
setTotalDbCount(countByStatus.total) setTotalDbCount(countByStatus.total)
// Preload transactions to model in case they are not there // Preload transactions to model in case they are not there
@@ -211,6 +213,26 @@ export const TranHistoryScreen = observer(function TranHistoryScreen({ route }:
setExpiredDbCount(countByStatus[TransactionStatus.EXPIRED] || 0) setExpiredDbCount(countByStatus[TransactionStatus.EXPIRED] || 0)
setErroredDbCount(countByStatus[TransactionStatus.ERROR] || 0) setErroredDbCount(countByStatus[TransactionStatus.ERROR] || 0)
setRevertedDbCount(countByStatus[TransactionStatus.REVERTED] || 0) setRevertedDbCount(countByStatus[TransactionStatus.REVERTED] || 0)
setIncomingPendingDbCount(Database.getIncomingPendingCount())
setTotalDbCount(countByStatus.total)
setIsLoading(false)
} catch (e: any) {
handleError(e)
}
}
const onDeleteIncomingPending = function () {
try {
toggleDeleteModal()
setIsLoading(true)
transactionsStore.deleteIncomingPending()
const countByStatus = Database.getTransactionsCount()
setPendingDbCount(countByStatus[TransactionStatus.PENDING] || 0)
setExpiredDbCount(countByStatus[TransactionStatus.EXPIRED] || 0)
setErroredDbCount(countByStatus[TransactionStatus.ERROR] || 0)
setRevertedDbCount(countByStatus[TransactionStatus.REVERTED] || 0)
setIncomingPendingDbCount(Database.getIncomingPendingCount())
setTotalDbCount(countByStatus.total) setTotalDbCount(countByStatus.total)
setIsLoading(false) setIsLoading(false)
} catch (e: any) { } catch (e: any) {
@@ -361,6 +383,15 @@ export const TranHistoryScreen = observer(function TranHistoryScreen({ route }:
style={{alignItems: 'stretch'}} style={{alignItems: 'stretch'}}
ContentComponent={ ContentComponent={
<> <>
<ListItem
tx="tranHistory_deleteIncomingPending"
subText={translate("tranHistory_deleteIncomingPendingDesc", {
count: incomingPendingDbCount
})}
leftIcon='faArrowDown'
onPress={onDeleteIncomingPending}
bottomSeparator={true}
/>
<ListItem <ListItem
tx="tranHistory_deleteExpired" tx="tranHistory_deleteExpired"
subText={translate("tranHistory_deleteExpiredDesc", { subText={translate("tranHistory_deleteExpiredDesc", {
+49
View File
@@ -809,6 +809,53 @@ const deleteTransactionsByStatus = function (status: TransactionStatus) {
} }
const getIncomingPendingCount = function () {
try {
const query = `
SELECT COUNT(*) AS total
FROM transactions
WHERE status = 'PENDING' AND type IN ('RECEIVE', 'RECEIVE_BY_PAYMENT_REQUEST')
`
const db = getInstance()
const {rows} = db.execute(query)
return rows?.item(0)['total'] as number
} catch (e: any) {
throw new AppError(
Err.DATABASE_ERROR,
'Could not get incoming pending count.',
e.message,
)
}
}
const deleteIncomingPending = function () {
try {
const query = `
DELETE FROM transactions
WHERE status = 'PENDING' AND type IN ('RECEIVE', 'RECEIVE_BY_PAYMENT_REQUEST')
`
const db = getInstance()
const {rows} = db.execute(query)
log.debug('[deleteIncomingPending]', 'Pending incoming transactions were deleted')
return rows
} catch (e: any) {
throw new AppError(
Err.DATABASE_ERROR,
'Could not delete incoming pending transactions.',
e.message,
)
}
}
const deleteTransactionById = function (id: number) { const deleteTransactionById = function (id: number) {
try { try {
const query = ` const query = `
@@ -1099,6 +1146,8 @@ export const Database = {
updateStatusesAsync, updateStatusesAsync,
deleteTransactionsByStatus, deleteTransactionsByStatus,
deleteTransactionById, deleteTransactionById,
getIncomingPendingCount,
deleteIncomingPending,
getPendingAmount, getPendingAmount,
addOrUpdateProof, addOrUpdateProof,
addOrUpdateProofs, addOrUpdateProofs,