204 lines
5.5 KiB
JavaScript
204 lines
5.5 KiB
JavaScript
import {
|
|
createContext,
|
|
useState,
|
|
useContext,
|
|
useEffect,
|
|
useMemo,
|
|
useCallback,
|
|
} from 'react';
|
|
import { useKeysContext } from './keys';
|
|
import { db } from '../db/initializeFirebase';
|
|
import {
|
|
DID_OPEN_TABLES_EVENT_NAME,
|
|
getSavedPOSTransactions,
|
|
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 [didOpenTable, setDidOpenTable] = useState(false);
|
|
|
|
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) return;
|
|
if (!publicKey) return;
|
|
console.log('running pos transactions listener...');
|
|
const now = new Date().getTime();
|
|
|
|
const transaction = query(
|
|
collection(db, 'posTransactions'),
|
|
where('storePubKey', '==', publicKey),
|
|
orderBy('dateAdded'),
|
|
startAfter(now),
|
|
);
|
|
|
|
const unsubscribe = onSnapshot(transaction, snapshot => {
|
|
snapshot?.docChanges()?.forEach(change => {
|
|
console.log('recived a new pos transaction', change.type);
|
|
if (change.type === 'added') {
|
|
const newTX = change.doc.data();
|
|
queuePOSTransactions({
|
|
transactionsList: [newTX],
|
|
privateKey: contactsPrivateKey,
|
|
});
|
|
}
|
|
});
|
|
});
|
|
|
|
return () => {
|
|
console.log(`unsubscribing pos transactions listener...`, !!unsubscribe);
|
|
if (unsubscribe) unsubscribe();
|
|
};
|
|
}, [publicKey, didOpenTable]);
|
|
|
|
useEffect(() => {
|
|
async function loadSavedTxs() {
|
|
const txs = await updateTxListFunction();
|
|
console.log('saved pos transactions', txs);
|
|
const lastMessageTimestamp = txs.length
|
|
? txs[0]?.dbDateAdded
|
|
: getTwoWeeksAgoDate();
|
|
|
|
console.log('last pos transaction timestamp', txs[0]?.dbDateAdded);
|
|
const transactionsRef = collection(db, 'posTransactions');
|
|
|
|
const messagesQuery = query(
|
|
transactionsRef,
|
|
where('storePubKey', '==', publicKey),
|
|
where('dateAdded', '>', lastMessageTimestamp),
|
|
);
|
|
|
|
const querySnapshot = await getDocs(messagesQuery);
|
|
|
|
if (querySnapshot.empty) return;
|
|
|
|
let messsageList = [];
|
|
|
|
for (const doc of querySnapshot.docs) {
|
|
const data = doc.data();
|
|
messsageList.push(data);
|
|
}
|
|
console.log('loaded missed pos transactions', messsageList);
|
|
queuePOSTransactions({
|
|
transactionsList: messsageList,
|
|
privateKey: contactsPrivateKey,
|
|
});
|
|
}
|
|
if (!didOpenTable) return;
|
|
if (!publicKey) return;
|
|
loadSavedTxs();
|
|
}, [publicKey, didOpenTable]);
|
|
|
|
const handlePosTableOpen = useCallback(eventType => {
|
|
if (eventType === 'opened') {
|
|
setDidOpenTable(true);
|
|
}
|
|
}, []);
|
|
useEffect(() => {
|
|
// listens for events from the db and updates the state
|
|
pointOfSaleEventEmitter.on(DID_OPEN_TABLES_EVENT_NAME, handlePosTableOpen);
|
|
pointOfSaleEventEmitter.on(POS_EVENT_UPDATE, updateTxListFunction);
|
|
return () => {
|
|
pointOfSaleEventEmitter.removeAllListeners(POS_EVENT_UPDATE);
|
|
pointOfSaleEventEmitter.removeAllListeners(DID_OPEN_TABLES_EVENT_NAME);
|
|
};
|
|
}, []);
|
|
|
|
const contextValue = useMemo(
|
|
() => ({
|
|
groupedTxs,
|
|
}),
|
|
[groupedTxs],
|
|
);
|
|
|
|
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,
|
|
};
|