179 lines
4.5 KiB
JavaScript
179 lines
4.5 KiB
JavaScript
import {
|
|
createContext,
|
|
useState,
|
|
useContext,
|
|
useEffect,
|
|
useMemo,
|
|
useCallback,
|
|
} from 'react';
|
|
import { useKeysContext } from './keys';
|
|
import { db } from '../db/initializeFirebase';
|
|
import {
|
|
getSavedPOSTransactions,
|
|
isSavedPOSTxsDatabaseOpen,
|
|
pointOfSaleEventEmitter,
|
|
POS_EVENT_UPDATE,
|
|
queuePOSTransactions,
|
|
} from '../app/functions/pos';
|
|
import { getTwoWeeksAgoDate } from '../app/functions/rotateAddressDateChecker';
|
|
import {
|
|
collection,
|
|
getDocs,
|
|
onSnapshot,
|
|
orderBy,
|
|
query,
|
|
startAfter,
|
|
where,
|
|
} from '@react-native-firebase/firestore';
|
|
// Initiate context
|
|
const POSTransactionsContextManager = createContext(null);
|
|
|
|
const POSTransactionsProvider = ({ children }) => {
|
|
const { publicKey, contactsPrivateKey } = useKeysContext();
|
|
const [txList, setTxList] = useState([]);
|
|
const [isLoading, setIsLoading] = useState(true);
|
|
const didOpenTable = isSavedPOSTxsDatabaseOpen();
|
|
|
|
const updateTxListFunction = useCallback(async () => {
|
|
const txs = await getSavedPOSTransactions();
|
|
setTxList(txs || []);
|
|
return txs || [];
|
|
}, []);
|
|
|
|
const groupedTxs = useMemo(() => {
|
|
try {
|
|
let totals = {};
|
|
for (const tx of txList) {
|
|
const serverName = tx.serverName?.toLowerCase()?.trim();
|
|
let savedAccount = totals[serverName];
|
|
if (!savedAccount) {
|
|
totals[serverName] = {
|
|
totalTipAmount: 0,
|
|
txs: [],
|
|
unpaidTxs: [],
|
|
lastActivity: 0,
|
|
totalUnpaidTxs: 0,
|
|
totalPaidTxs: 0,
|
|
};
|
|
}
|
|
savedAccount = totals[serverName];
|
|
|
|
let newUnpaidTxArray = [...savedAccount.unpaidTxs];
|
|
if (!tx.didPay) newUnpaidTxArray.push(tx);
|
|
|
|
totals[serverName] = {
|
|
totalTipAmount:
|
|
savedAccount.totalTipAmount + (tx.didPay ? 0 : tx.tipAmountSats),
|
|
txs: [tx, ...savedAccount.txs],
|
|
unpaidTxs: newUnpaidTxArray,
|
|
lastActivity:
|
|
tx.timestamp > savedAccount.lastActivity
|
|
? tx.timestamp
|
|
: savedAccount.lastActivity,
|
|
totalUnpaidTxs:
|
|
savedAccount.totalUnpaidTxs + (!tx.didPay ? tx.tipAmountSats : 0),
|
|
totalPaidTxs:
|
|
savedAccount.totalPaidTxs + (!!tx.didPay ? tx.tipAmountSats : 0),
|
|
};
|
|
}
|
|
|
|
if (!Object.keys(totals).length) {
|
|
return [];
|
|
}
|
|
|
|
return Object.entries(totals);
|
|
} catch (err) {
|
|
console.log('getting tip totals error', err);
|
|
return [];
|
|
}
|
|
}, [txList]);
|
|
|
|
useEffect(() => {
|
|
if (!didOpenTable || !publicKey) return;
|
|
|
|
let unsubscribe;
|
|
|
|
async function initListener() {
|
|
const txs = await updateTxListFunction();
|
|
const lastTimestamp = txs.length
|
|
? txs[0]?.dbDateAdded
|
|
: getTwoWeeksAgoDate();
|
|
|
|
const catchUpQuery = query(
|
|
collection(db, 'posTransactions'),
|
|
where('storePubKey', '==', publicKey),
|
|
where('dateAdded', '>', lastTimestamp),
|
|
orderBy('dateAdded'),
|
|
);
|
|
|
|
unsubscribe = onSnapshot(catchUpQuery, snapshot => {
|
|
const newTxs = [];
|
|
|
|
snapshot.docChanges().forEach(change => {
|
|
if (change.type === 'added') {
|
|
newTxs.push(change.doc.data());
|
|
}
|
|
});
|
|
|
|
if (!newTxs.length) return;
|
|
|
|
console.log(
|
|
'received pos transactions (catch-up + live):',
|
|
newTxs.length,
|
|
);
|
|
queuePOSTransactions({
|
|
transactionsList: newTxs,
|
|
privateKey: contactsPrivateKey,
|
|
});
|
|
});
|
|
|
|
setIsLoading(false);
|
|
}
|
|
|
|
initListener();
|
|
|
|
return () => {
|
|
console.log('unsubscribing pos transactions listener...', !!unsubscribe);
|
|
if (unsubscribe) unsubscribe();
|
|
};
|
|
}, [publicKey, didOpenTable]);
|
|
|
|
useEffect(() => {
|
|
// listens for events from the db and updates the state
|
|
pointOfSaleEventEmitter.on(POS_EVENT_UPDATE, updateTxListFunction);
|
|
return () => {
|
|
pointOfSaleEventEmitter.removeAllListeners(POS_EVENT_UPDATE);
|
|
};
|
|
}, []);
|
|
|
|
const contextValue = useMemo(
|
|
() => ({
|
|
groupedTxs,
|
|
isLoading,
|
|
}),
|
|
[groupedTxs, isLoading],
|
|
);
|
|
|
|
return (
|
|
<POSTransactionsContextManager.Provider value={contextValue}>
|
|
{children}
|
|
</POSTransactionsContextManager.Provider>
|
|
);
|
|
};
|
|
|
|
function usePOSTransactions() {
|
|
const context = useContext(POSTransactionsContextManager);
|
|
if (!context) {
|
|
throw new Error(
|
|
'usePOSTransactions must be used within a POSTransactionsProvider',
|
|
);
|
|
}
|
|
return context;
|
|
}
|
|
|
|
export {
|
|
POSTransactionsContextManager,
|
|
POSTransactionsProvider,
|
|
usePOSTransactions,
|
|
};
|