Files

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,
};