From 6fd930e8513a43de2d438caee637392585359e40 Mon Sep 17 00:00:00 2001 From: minibits-cash Date: Tue, 4 Feb 2025 08:35:31 +0100 Subject: [PATCH] Upgrade to RN077 --- .editorconfig | 2 +- patches/react-native-nitro-sqlite+9.1.1.patch | 13 - src/models/Transaction.ts | 46 +- src/models/TransactionsStore.ts | 678 +++++++++--------- src/screens/MintInfoScreen.tsx | 39 +- src/screens/WalletScreen.tsx | 6 +- 6 files changed, 391 insertions(+), 393 deletions(-) delete mode 100644 patches/react-native-nitro-sqlite+9.1.1.patch diff --git a/.editorconfig b/.editorconfig index 1ed453a..ffe9a1f 100644 --- a/.editorconfig +++ b/.editorconfig @@ -7,4 +7,4 @@ insert_final_newline = true [*.{js,json,yml}] charset = utf-8 indent_style = space -indent_size = 2 +indent_size = 4 diff --git a/patches/react-native-nitro-sqlite+9.1.1.patch b/patches/react-native-nitro-sqlite+9.1.1.patch deleted file mode 100644 index d4dff74..0000000 --- a/patches/react-native-nitro-sqlite+9.1.1.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/node_modules/react-native-nitro-sqlite/cpp/operations.cpp b/node_modules/react-native-nitro-sqlite/cpp/operations.cpp -index 0655754..88e80cd 100644 ---- a/node_modules/react-native-nitro-sqlite/cpp/operations.cpp -+++ b/node_modules/react-native-nitro-sqlite/cpp/operations.cpp -@@ -165,7 +165,7 @@ SQLiteExecuteQueryResult sqliteExecute(const std::string& dbName, const std::str - switch (column_type) { - - case SQLITE_INTEGER: { -- auto column_value = sqlite3_column_int64(statement, i); -+ auto column_value = sqlite3_column_double(statement, i); - row[column_name] = column_value; - break; - } \ No newline at end of file diff --git a/src/models/Transaction.ts b/src/models/Transaction.ts index 1ffa346..a9ed0bc 100644 --- a/src/models/Transaction.ts +++ b/src/models/Transaction.ts @@ -11,18 +11,18 @@ export interface TransactionRecord { fee: number unit: MintUnit data: string - sentFrom?: string - sentTo?: string - profile?: string - memo?: string - zapRequest?: string - inputToken?: string - outputToken?: string - proof?: string + sentFrom?: string | null + sentTo?: string | null + profile?: string | null + memo?: string | null + zapRequest?: string | null + inputToken?: string | null + outputToken?: string | null + proof?: string | null mint: string - balanceAfter?: number - noteToSelf?: string - tags?: Array + balanceAfter?: number | null + noteToSelf?: string | null + tags?: Array | null status: TransactionStatus createdAt: Date } @@ -63,18 +63,18 @@ export const TransactionModel = types fee: types.optional(types.integer, 0), unit: types.frozen(), data: types.string, - sentFrom: types.maybe(types.string), - sentTo: types.maybe(types.string), - profile: types.maybe(types.string), - memo: types.maybe(types.string), + sentFrom: types.maybe(types.maybeNull(types.string)), + sentTo: types.maybe(types.maybeNull(types.string)), + profile: types.maybe(types.maybeNull(types.string)), + memo: types.maybe(types.maybeNull(types.string)), mint: types.string, - zapRequest: types.maybe(types.string), - inputToken: types.maybe(types.string), - outputToken: types.maybe(types.string), - proof: types.maybe(types.string), - balanceAfter: types.maybe(types.integer), - noteToSelf: types.maybe(types.string), - tags: types.maybe(types.array(types.string)), + zapRequest: types.maybe(types.maybeNull(types.string)), + inputToken: types.maybe(types.maybeNull(types.string)), + outputToken: types.maybe(types.maybeNull(types.string)), + proof: types.maybe(types.maybeNull(types.string)), + balanceAfter: types.maybe(types.maybeNull(types.integer)), + noteToSelf: types.maybe(types.maybeNull(types.string)), + tags: types.maybe(types.maybeNull(types.array(types.string))), status: types.frozen(), createdAt: types.optional(types.Date, new Date()), }) @@ -177,4 +177,4 @@ export interface Transaction extends Instance {} export interface TransactionSnapshotOut extends SnapshotOut {} export interface TransactionSnapshotIn - extends SnapshotIn {} + extends SnapshotIn {} \ No newline at end of file diff --git a/src/models/TransactionsStore.ts b/src/models/TransactionsStore.ts index 01ba698..90d69f0 100644 --- a/src/models/TransactionsStore.ts +++ b/src/models/TransactionsStore.ts @@ -1,340 +1,340 @@ import { - Instance, - SnapshotOut, - types, - flow, - detach, -} from 'mobx-state-tree' -import {withSetPropAction} from './helpers/withSetPropAction' -import { - TransactionModel, - Transaction, - TransactionStatus, - TransactionRecord, -} from './Transaction' -import {Database} from '../services' -import {log} from '../services/logService' -import { getRootStore } from './helpers/getRootStore' -import { formatDistance } from 'date-fns' -import { MintUnit } from '../services/wallet/currency' -import { Mint } from './Mint' - -export const maxTransactionsInHistory = 10 -export const maxTransactionsByUnit = 3 - -export type GroupedByTimeAgo = { - [timeAgo: string]: Transaction[]; -} - -export const TransactionsStoreModel = types - .model('TransactionsStore', { - transactionsMap: types.map(TransactionModel), - history: types.array(types.safeReference(TransactionModel, { acceptsUndefined: false })), - recentByUnit: types.array(types.safeReference(TransactionModel, { acceptsUndefined: false })), - }) - .actions(withSetPropAction) - .views(self => ({ - get pendingHistory() { - return self.history - .slice() - .sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime()) - .filter(t => t.status === TransactionStatus.PENDING) - }, - get historyByTimeAgo() { - return self.history - .slice() - .sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime()) - .reduce((groups: GroupedByTimeAgo, transaction: Transaction) => { - const timeAgo = formatDistance(transaction.createdAt as Date, new Date(), {addSuffix: true}) - if (!groups[timeAgo]) { - groups[timeAgo] = [] - } - groups[timeAgo].push(transaction) - return groups - }, {}) - }, - get historyPendingByTimeAgo() { - return this.pendingHistory.reduce((groups: GroupedByTimeAgo, transaction: Transaction) => { - const timeAgo = formatDistance(transaction.createdAt as Date, new Date(), {addSuffix: true}) - if (!groups[timeAgo]) { - groups[timeAgo] = [] - } - groups[timeAgo].push(transaction) - return groups - }, {}) - }, - get historyCount() { - return self.history.length - }, - get pendingHistoryCount() { - return this.pendingHistory.length - }, - getRecentByUnit(unit: MintUnit) { - return self.recentByUnit - .slice() - .sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime()) - .filter(t => t.unit === unit) - }, - countRecentByUnit(unit: MintUnit) { - return this.getRecentByUnit(unit).length - } - })) - .actions(self => ({ - findById(id: number, loadTokens?: boolean) { - let transaction = self.transactionsMap.get(id) - - // Search the db and add if tx is not in the state - // Search always to retrieve full tokens in tx detail screen - if(!transaction || loadTokens === true) { - const dbTransaction = Database.getTransactionById(id) - - if(dbTransaction) { - const createdAt = new Date(dbTransaction.createdAt) - const inStoreTransaction = {...dbTransaction, createdAt} - const {id} = dbTransaction - - if(!loadTokens) { - // Shorten for performance reasons - if(inStoreTransaction.inputToken && inStoreTransaction.inputToken.length > 0) { - inStoreTransaction.inputToken = inStoreTransaction.inputToken?.slice(0, 40) - } - - if(inStoreTransaction.outputToken && inStoreTransaction.outputToken.length > 0) { - inStoreTransaction.outputToken = inStoreTransaction.outputToken?.slice(0, 40) - } - } - - self.transactionsMap.set(id, inStoreTransaction) - transaction = self.transactionsMap.get(id) - } - } - - return transaction - }, - pruneRecentByUnit(unit: MintUnit) { - const unitCount = self.countRecentByUnit(unit) - - log.trace('[pruneRecentByUnit]', {unit, unitCount}) - - if (unitCount > maxTransactionsByUnit) { - const transactionsToRemove = self.getRecentByUnit(unit) - .slice() - .sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime()) - .splice(maxTransactionsByUnit) - - self.recentByUnit.replace(self.recentByUnit.filter(t => !transactionsToRemove.some(removed => removed.id === t.id))) - - log.trace('[pruneRecentByUnit]', `${transactionsToRemove.length} pruned from recentByUnit`) - } - }, - pruneRecentWithoutCurrentMint() { - const rootStore = getRootStore(self) - const {mintsStore} = rootStore - - const transactionsToRemove = self.recentByUnit.filter(transaction => { - // Check if the mint property of the transaction does not exist in the mints array - return !mintsStore.allMints.some((mint: Mint) => mint.mintUrl === transaction.mint); - }) - - self.recentByUnit.replace(self.recentByUnit.filter(t => !transactionsToRemove.some(removed => removed.id === t.id))) - - log.trace('[pruneRecentWithoutCurrentMint]', `${transactionsToRemove.length} pruned from recentByUnit`) - }, - pruneHistory() { - // Step 1: Trim history to keep only the MAX_HISTORY_TRANSACTIONS most recent - if (self.history.length > maxTransactionsInHistory) { - const transactionsToRemove = self.history - .slice() - .sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime()) - .splice(maxTransactionsInHistory) - - self.history.replace(self.history.filter(t => !transactionsToRemove.some(removed => removed.id === t.id))) - - log.trace('[pruneHistory]', `${transactionsToRemove.length} pruned from history`) - } - }, - removeAllHistory() { - self.history.clear() - log.debug('[removeAllHistory]', 'Removed all transactions from history') - }, - removeAllRecentByUnit() { - self.recentByUnit.clear() - log.debug('[removeAllRecentByUnit]', 'Removed all transactions from recentByUnit') - }, - removeAllTransactions() { - self.recentByUnit.clear() - self.history.clear() - self.transactionsMap.clear() - log.debug('[removeAllTransactions]', 'Removed all transactions from TransactionsStore') - }, - })) - .actions(self => ({ - addTransaction: flow(function* addTransaction(newTransaction){ - // First let's store the transaction into the database - const dbTransaction: TransactionRecord = yield Database.addTransactionAsync(newTransaction) - - // Add the new transaction to the transactions store - const createdAt = new Date(dbTransaction.createdAt) - const inStoreTransaction = {...dbTransaction, createdAt} - const {id} = dbTransaction - - if (!self.transactionsMap.has(id)) { - self.transactionsMap.set(id, inStoreTransaction) - } - - const reference = self.transactionsMap.get(id) - self.history.unshift(reference!) - self.recentByUnit.unshift(reference!) - - // log.trace('[addTransaction]', 'New transaction added to the TransactionsStore', {id}) - - // Purge the oldest references from cache, but keep some for each mint - self.pruneRecentByUnit(newTransaction.unit) - self.pruneHistory() - - return reference as Transaction - }), - addToHistory(limit: number, offset: number, onlyPending: boolean){ - // Appends transaction to the map and adds reference to history from database. - const dbTransactions = Database.getTransactions(limit, offset, onlyPending) - log.trace('[addToHistory] dbResult ids', {ids: dbTransactions.map(t => t.id)}) - - if (dbTransactions && dbTransactions.length > 0) { - for (const dbTransaction of dbTransactions) { - const createdAt = new Date(dbTransaction.createdAt) - const inStoreTransaction = {...dbTransaction, createdAt} - - // Shorten for performance reasons - if(inStoreTransaction.inputToken && inStoreTransaction.inputToken.length > 0) { - inStoreTransaction.inputToken = inStoreTransaction.inputToken?.slice(0, 40) - } - - if(inStoreTransaction.outputToken && inStoreTransaction.outputToken.length > 0) { - inStoreTransaction.outputToken = inStoreTransaction.outputToken?.slice(0, 40) - } - - const {id} = dbTransaction - - if (!self.transactionsMap.has(id)) { - self.transactionsMap.set(id, inStoreTransaction) - log.trace('[addToHistory]', `${id} added to transactionsMap`) - } - - const reference = self.transactionsMap.get(id) - - if (!self.history.find(t => t.id === id)) { - self.history.push(reference!) - log.trace('[addToHistory]', `${onlyPending ? 'Pending reference' : 'Reference'} ${id} added to history`) - } - } - } - }, - addRecentByUnit() { - // Rehydrates recent from database. - const dbTransactions = Database.getRecentTransactionsByUnit(maxTransactionsByUnit) - - if (dbTransactions && dbTransactions.length > 0) { - for (const dbTransaction of dbTransactions) { - const createdAt = new Date(dbTransaction.createdAt) - const inStoreTransaction = {...dbTransaction, createdAt} as Transaction - - // Shorten for performance reasons - if(inStoreTransaction.inputToken && inStoreTransaction.inputToken.length > 0) { - inStoreTransaction.inputToken = inStoreTransaction.inputToken?.slice(0, 40) - } - if(inStoreTransaction.outputToken && inStoreTransaction.outputToken.length > 0) { - inStoreTransaction.outputToken = inStoreTransaction.outputToken?.slice(0, 40) - } - - const {id} = dbTransaction - - if (!self.transactionsMap.has(id)) { - self.transactionsMap.set(id, inStoreTransaction) - } - - const reference = self.transactionsMap.get(id) - - if (!self.recentByUnit.find(t => t.id === id)) { - self.recentByUnit.push(reference!) - log.trace('[addRecentByUnit]', `Transaction ${inStoreTransaction.id} added to recentByUnit`) - } - } - } - }, - updateStatuses: flow(function* updateStatuses( - ids: number[], - status: TransactionStatus, - data: string, - ) { - // Update status and amend to existing data in database - yield Database.updateStatusesAsync(ids, status, data) - - // Update the model status and amend related tx data - for (const id of ids) { - const transactionInstance = self.transactionsMap.get(id) - - if (transactionInstance) { - transactionInstance.status = status - - // Awkward but I want to keep function signature aligned with single status update - const updatedData = JSON.parse(transactionInstance.data) - updatedData.push(JSON.parse(data)) - transactionInstance.data = JSON.stringify(updatedData) - } - - log.trace('[updateStatuses]', 'Transaction statuses and data updated in TransactionsStore', {ids, status}) - } - }), - deleteByStatus(status: TransactionStatus){ - - self.transactionsMap.forEach((transaction, transactionId) => { - if (transaction.status === status) { - self.transactionsMap.delete(transactionId as string) - } - }) - - return Database.deleteTransactionsByStatus(status) - } - })).postProcessSnapshot((snapshot) => { - // Trim history if it exceeds the limit - let prunedHistory = snapshot.history - - if (snapshot.history.length > maxTransactionsInHistory) { - // Keep only the most recent transactions within the limit - const orderedHistory = [...snapshot.history].sort((a, b) => (b as number) - (a as number)) - prunedHistory = orderedHistory.slice(0, maxTransactionsInHistory) - } - - // Clean up transactionMap: remove transactions not in history or recentByUnit - const prunedTransactionsMap = Object.fromEntries( - Object.entries(snapshot.transactionsMap).filter(([transactionId]) => - prunedHistory.includes(parseInt(transactionId)) || - snapshot.recentByUnit.includes(parseInt(transactionId)) - ) - ) - - // Return the new snapshot with the trimmed history and filtered transactionMap - const prunedSnapshot = { - ...snapshot, - history: prunedHistory, - transactionsMap: prunedTransactionsMap - } - - // console.log('[postProcessSnapshot]', {prunedSnapshot}) - - return prunedSnapshot - }) - - const getHostname = function (mintUrl: string) { - try { - return new URL(mintUrl).hostname - } catch (e) { - return false - } - } - -// refresh -export interface TransactionsStore - extends Instance {} -export interface TransactionsStoreSnapshot - extends SnapshotOut {} + Instance, + SnapshotOut, + types, + flow, + detach, + } from 'mobx-state-tree' + import {withSetPropAction} from './helpers/withSetPropAction' + import { + TransactionModel, + Transaction, + TransactionStatus, + TransactionRecord, + } from './Transaction' + import {Database} from '../services' + import {log} from '../services/logService' + import { getRootStore } from './helpers/getRootStore' + import { formatDistance } from 'date-fns' + import { MintUnit } from '../services/wallet/currency' + import { Mint } from './Mint' + + export const maxTransactionsInHistory = 10 + export const maxTransactionsByUnit = 3 + + export type GroupedByTimeAgo = { + [timeAgo: string]: Transaction[]; + } + + export const TransactionsStoreModel = types + .model('TransactionsStore', { + transactionsMap: types.map(TransactionModel), + history: types.array(types.safeReference(TransactionModel, { acceptsUndefined: false })), + recentByUnit: types.array(types.safeReference(TransactionModel, { acceptsUndefined: false })), + }) + .actions(withSetPropAction) + .views(self => ({ + get pendingHistory() { + return self.history + .slice() + .sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime()) + .filter(t => t.status === TransactionStatus.PENDING) + }, + get historyByTimeAgo() { + return self.history + .slice() + .sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime()) + .reduce((groups: GroupedByTimeAgo, transaction: Transaction) => { + const timeAgo = formatDistance(transaction.createdAt as Date, new Date(), {addSuffix: true}) + if (!groups[timeAgo]) { + groups[timeAgo] = [] + } + groups[timeAgo].push(transaction) + return groups + }, {}) + }, + get historyPendingByTimeAgo() { + return this.pendingHistory.reduce((groups: GroupedByTimeAgo, transaction: Transaction) => { + const timeAgo = formatDistance(transaction.createdAt as Date, new Date(), {addSuffix: true}) + if (!groups[timeAgo]) { + groups[timeAgo] = [] + } + groups[timeAgo].push(transaction) + return groups + }, {}) + }, + get historyCount() { + return self.history.length + }, + get pendingHistoryCount() { + return this.pendingHistory.length + }, + getRecentByUnit(unit: MintUnit) { + return self.recentByUnit + .slice() + .sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime()) + .filter(t => t.unit === unit) + }, + countRecentByUnit(unit: MintUnit) { + return this.getRecentByUnit(unit).length + } + })) + .actions(self => ({ + findById(id: number, loadTokens?: boolean) { + let transaction = self.transactionsMap.get(id) + + // Search the db and add if tx is not in the state + // Search always to retrieve full tokens in tx detail screen + if(!transaction || loadTokens === true) { + const dbTransaction = Database.getTransactionById(id) + + if(dbTransaction) { + const createdAt = new Date(dbTransaction.createdAt) + const inStoreTransaction = {...dbTransaction, createdAt} + const {id} = dbTransaction + + if(!loadTokens) { + // Shorten for performance reasons + if(inStoreTransaction.inputToken && inStoreTransaction.inputToken.length > 0) { + inStoreTransaction.inputToken = inStoreTransaction.inputToken?.slice(0, 40) + } + + if(inStoreTransaction.outputToken && inStoreTransaction.outputToken.length > 0) { + inStoreTransaction.outputToken = inStoreTransaction.outputToken?.slice(0, 40) + } + } + + self.transactionsMap.set(id, inStoreTransaction) + transaction = self.transactionsMap.get(id) + } + } + + return transaction + }, + pruneRecentByUnit(unit: MintUnit) { + const unitCount = self.countRecentByUnit(unit) + + log.trace('[pruneRecentByUnit]', {unit, unitCount}) + + if (unitCount > maxTransactionsByUnit) { + const transactionsToRemove = self.getRecentByUnit(unit) + .slice() + .sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime()) + .splice(maxTransactionsByUnit) + + self.recentByUnit.replace(self.recentByUnit.filter(t => !transactionsToRemove.some(removed => removed.id === t.id))) + + log.trace('[pruneRecentByUnit]', `${transactionsToRemove.length} pruned from recentByUnit`) + } + }, + pruneRecentWithoutCurrentMint() { + const rootStore = getRootStore(self) + const {mintsStore} = rootStore + + const transactionsToRemove = self.recentByUnit.filter(transaction => { + // Check if the mint property of the transaction does not exist in the mints array + return !mintsStore.allMints.some((mint: Mint) => mint.mintUrl === transaction.mint); + }) + + self.recentByUnit.replace(self.recentByUnit.filter(t => !transactionsToRemove.some(removed => removed.id === t.id))) + + log.trace('[pruneRecentWithoutCurrentMint]', `${transactionsToRemove.length} pruned from recentByUnit`) + }, + pruneHistory() { + // Step 1: Trim history to keep only the MAX_HISTORY_TRANSACTIONS most recent + if (self.history.length > maxTransactionsInHistory) { + const transactionsToRemove = self.history + .slice() + .sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime()) + .splice(maxTransactionsInHistory) + + self.history.replace(self.history.filter(t => !transactionsToRemove.some(removed => removed.id === t.id))) + + log.trace('[pruneHistory]', `${transactionsToRemove.length} pruned from history`) + } + }, + removeAllHistory() { + self.history.clear() + log.debug('[removeAllHistory]', 'Removed all transactions from history') + }, + removeAllRecentByUnit() { + self.recentByUnit.clear() + log.debug('[removeAllRecentByUnit]', 'Removed all transactions from recentByUnit') + }, + removeAllTransactions() { + self.recentByUnit.clear() + self.history.clear() + self.transactionsMap.clear() + log.debug('[removeAllTransactions]', 'Removed all transactions from TransactionsStore') + }, + })) + .actions(self => ({ + addTransaction: flow(function* addTransaction(newTransaction){ + // First let's store the transaction into the database + const dbTransaction: TransactionRecord = yield Database.addTransactionAsync(newTransaction) + + // Add the new transaction to the transactions store + const createdAt = new Date(dbTransaction.createdAt) + const inStoreTransaction = {...dbTransaction, createdAt} + const {id} = dbTransaction + + if (!self.transactionsMap.has(id)) { + self.transactionsMap.set(id, inStoreTransaction) + } + + const reference = self.transactionsMap.get(id) + self.history.unshift(reference!) + self.recentByUnit.unshift(reference!) + + // log.trace('[addTransaction]', 'New transaction added to the TransactionsStore', {id}) + + // Purge the oldest references from cache, but keep some for each mint + self.pruneRecentByUnit(newTransaction.unit) + self.pruneHistory() + + return reference as Transaction + }), + addToHistory(limit: number, offset: number, onlyPending: boolean){ + // Appends transaction to the map and adds reference to history from database. + const result = Database.getTransactions(limit, offset, onlyPending) + log.trace('[addToHistory] dbResult ids', {ids: result?._array.map(t => t.id)}) + + if (result && result.length > 0) { + for (const dbTransaction of result._array) { + const createdAt = new Date(dbTransaction.createdAt) + const inStoreTransaction = {...dbTransaction, createdAt} + + // Shorten for performance reasons + if(inStoreTransaction.inputToken && inStoreTransaction.inputToken.length > 0) { + inStoreTransaction.inputToken = inStoreTransaction.inputToken?.slice(0, 40) + } + + if(inStoreTransaction.outputToken && inStoreTransaction.outputToken.length > 0) { + inStoreTransaction.outputToken = inStoreTransaction.outputToken?.slice(0, 40) + } + + const {id} = dbTransaction + + if (!self.transactionsMap.has(id)) { + self.transactionsMap.set(id, inStoreTransaction) + log.trace('[addToHistory]', `${id} added to transactionsMap`) + } + + const reference = self.transactionsMap.get(id) + + if (!self.history.find(t => t.id === id)) { + self.history.push(reference!) + log.trace('[addToHistory]', `${onlyPending ? 'Pending reference' : 'Reference'} ${id} added to history`) + } + } + } + }, + addRecentByUnit() { + // Rehydrates recent from database. + const dbTransactions = Database.getRecentTransactionsByUnit(maxTransactionsByUnit) + + if (dbTransactions && dbTransactions.length > 0) { + for (const dbTransaction of dbTransactions) { + const createdAt = new Date(dbTransaction.createdAt) + const inStoreTransaction = {...dbTransaction, createdAt} as Transaction + + // Shorten for performance reasons + if(inStoreTransaction.inputToken && inStoreTransaction.inputToken.length > 0) { + inStoreTransaction.inputToken = inStoreTransaction.inputToken?.slice(0, 40) + } + if(inStoreTransaction.outputToken && inStoreTransaction.outputToken.length > 0) { + inStoreTransaction.outputToken = inStoreTransaction.outputToken?.slice(0, 40) + } + + const {id} = dbTransaction + + if (!self.transactionsMap.has(id)) { + self.transactionsMap.set(id, inStoreTransaction) + } + + const reference = self.transactionsMap.get(id) + + if (!self.recentByUnit.find(t => t.id === id)) { + self.recentByUnit.push(reference!) + log.trace('[addRecentByUnit]', `Transaction ${inStoreTransaction.id} added to recentByUnit`) + } + } + } + }, + updateStatuses: flow(function* updateStatuses( + ids: number[], + status: TransactionStatus, + data: string, + ) { + // Update status and amend to existing data in database + yield Database.updateStatusesAsync(ids, status, data) + + // Update the model status and amend related tx data + for (const id of ids) { + const transactionInstance = self.transactionsMap.get(id) + + if (transactionInstance) { + transactionInstance.status = status + + // Awkward but I want to keep function signature aligned with single status update + const updatedData = JSON.parse(transactionInstance.data) + updatedData.push(JSON.parse(data)) + transactionInstance.data = JSON.stringify(updatedData) + } + + log.trace('[updateStatuses]', 'Transaction statuses and data updated in TransactionsStore', {ids, status}) + } + }), + deleteByStatus(status: TransactionStatus){ + + self.transactionsMap.forEach((transaction, transactionId) => { + if (transaction.status === status) { + self.transactionsMap.delete(transactionId as string) + } + }) + + return Database.deleteTransactionsByStatus(status) + } + })).postProcessSnapshot((snapshot) => { + // Trim history if it exceeds the limit + let prunedHistory = snapshot.history + + if (snapshot.history.length > maxTransactionsInHistory) { + // Keep only the most recent transactions within the limit + const orderedHistory = [...snapshot.history].sort((a, b) => (b as number) - (a as number)) + prunedHistory = orderedHistory.slice(0, maxTransactionsInHistory) + } + + // Clean up transactionMap: remove transactions not in history or recentByUnit + const prunedTransactionsMap = Object.fromEntries( + Object.entries(snapshot.transactionsMap).filter(([transactionId]) => + prunedHistory.includes(parseInt(transactionId)) || + snapshot.recentByUnit.includes(parseInt(transactionId)) + ) + ) + + // Return the new snapshot with the trimmed history and filtered transactionMap + const prunedSnapshot = { + ...snapshot, + history: prunedHistory, + transactionsMap: prunedTransactionsMap + } + + // console.log('[postProcessSnapshot]', {prunedSnapshot}) + + return prunedSnapshot + }) + + const getHostname = function (mintUrl: string) { + try { + return new URL(mintUrl).hostname + } catch (e) { + return false + } + } + + // refresh + export interface TransactionsStore + extends Instance {} + export interface TransactionsStoreSnapshot + extends SnapshotOut {} \ No newline at end of file diff --git a/src/screens/MintInfoScreen.tsx b/src/screens/MintInfoScreen.tsx index 31531af..116cdcd 100644 --- a/src/screens/MintInfoScreen.tsx +++ b/src/screens/MintInfoScreen.tsx @@ -4,7 +4,7 @@ import { isObj } from '@cashu/cashu-ts/src/utils' import Clipboard from '@react-native-clipboard/clipboard' import { observer } from 'mobx-react-lite' import { getSnapshot } from 'mobx-state-tree' -import { DimensionValue, LayoutAnimation, Platform, TextStyle, UIManager, View, ViewStyle } from 'react-native' +import { DimensionValue, Image, LayoutAnimation, Platform, TextStyle, UIManager, View, ViewStyle } from 'react-native' import JSONTree from 'react-native-json-tree' import { $sizeStyles, @@ -157,22 +157,35 @@ export const MintInfoScreen: FC> = observer return ( - - + ):( + + + /> + )} {mint?.units && ( @@ -494,7 +507,7 @@ function ContactCard(props: { info: GetInfoResponse, popupMessage: (msg: string) } /** don't render these because they're rendered in separate components */ -const detailsHiddenKeys = new Set(['name', 'motd', 'description', 'description_long', 'nuts', 'contact']) +const detailsHiddenKeys = new Set(['name', 'motd', 'description', 'description_long', 'nuts', 'contact', 'icon_url', 'time']) /** key-value pairs of details about the mint */ function MintInfoDetails(props: { info: GetInfoResponse, popupMessage: (msg: string) => void }) { diff --git a/src/screens/WalletScreen.tsx b/src/screens/WalletScreen.tsx index 96b68fe..b98a54a 100644 --- a/src/screens/WalletScreen.tsx +++ b/src/screens/WalletScreen.tsx @@ -18,9 +18,7 @@ import { import codePush, { RemotePackage } from 'react-native-code-push' import {moderateScale, verticalScale} from '@gocodingnow/rn-size-matters' import { SvgXml } from 'react-native-svg' -import notifee, { AndroidImportance } from '@notifee/react-native' import { NavigationState, Route, TabBar, TabView } from 'react-native-tab-view' -import { NotificationService, TASK_QUEUE_CHANNEL_ID, TASK_QUEUE_CHANNEL_NAME } from '../services/notificationService' import {useThemeColor, spacing, colors, typography} from '../theme' import { Button, @@ -527,7 +525,7 @@ export const WalletScreen: FC = observer( } const tabWidth = moderateScale(75) - + const getActiveTabColor = (state: NavigationState) => { return useThemeColor('headerTitle') } @@ -545,7 +543,7 @@ export const WalletScreen: FC = observer( textStyle={{color: 'white'}} containerStyle={focused ? {} : {opacity: 0.5}} /> - )} + )} indicatorStyle={{backgroundColor: getActiveTabColor(props.navigationState)}} style={{backgroundColor: headerBg, shadowColor: 'transparent'}} />