* adding new payment type for contact transactions * adding contact to expanded details page * fixed dark mode style * adding custom font for Asterisk * make buttons for memo edit show when opening keyboard
193 lines
5.9 KiB
JavaScript
193 lines
5.9 KiB
JavaScript
import { useEffect, useRef, useCallback } from 'react';
|
|
import { useGlobalContextProvider } from './context';
|
|
import {
|
|
collection,
|
|
onSnapshot,
|
|
query,
|
|
} from '@react-native-firebase/firestore';
|
|
import { db } from '../db/initializeFirebase';
|
|
import { batchDeleteLnurlPayments } from '../db';
|
|
// import {initializeTempSparkWallet} from '../app/functions/spark';
|
|
// import {getBitcoinKeyPair, getSharedKey} from '../app/functions/lnurl';
|
|
import { useSparkWallet } from './sparkContext';
|
|
// import {retrieveData} from '../app/functions';
|
|
import { addSingleUnpaidSparkLightningTransaction } from '../app/functions/spark/transactions';
|
|
import i18next from 'i18next';
|
|
|
|
export default function HandleLNURLPayments() {
|
|
const { sparkInformation } = useSparkWallet();
|
|
const { masterInfoObject } = useGlobalContextProvider();
|
|
const sparkAddress = sparkInformation?.sparkAddress;
|
|
|
|
// Initialize refs
|
|
const loadListener = useRef(false); // Changed to boolean for clarity
|
|
const timeoutRef = useRef(null);
|
|
const isProcessingRef = useRef(false);
|
|
|
|
const paymentQueueRef = useRef([]);
|
|
|
|
const deleteActiveLNURLPaymentsRef = useRef([]);
|
|
|
|
const parseDescription = message => {
|
|
try {
|
|
const parsed = JSON.parse(message);
|
|
return i18next.t(parsed.translation, { name: parsed.name });
|
|
} catch (err) {
|
|
console.log(err);
|
|
return message;
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
if (!masterInfoObject.uuid) return;
|
|
if (!sparkAddress || loadListener.current) return;
|
|
loadListener.current = true;
|
|
|
|
const setupListener = () => {
|
|
const paymentsRef = collection(
|
|
db,
|
|
'blitzWalletUsers',
|
|
masterInfoObject.uuid,
|
|
'lnurlPayments',
|
|
);
|
|
// Remove the timestamp filter to get ALL payments initially
|
|
const q = query(paymentsRef);
|
|
|
|
let isInitialLoad = true;
|
|
|
|
const unsubscribe = onSnapshot(q, snapshot => {
|
|
if (isInitialLoad) {
|
|
// First load - process all existing payments
|
|
snapshot.docs.forEach(doc => {
|
|
const payment = doc.data();
|
|
paymentQueueRef.current.push({
|
|
...payment,
|
|
id: doc.id,
|
|
shouldNavigate: false, // Don't navigate for restored payments
|
|
runCount: 0,
|
|
});
|
|
});
|
|
|
|
if (paymentQueueRef.current.length > 0) {
|
|
console.log(
|
|
`Restoring ${paymentQueueRef.current.length} offline lnurl payments`,
|
|
);
|
|
processQueue();
|
|
}
|
|
|
|
isInitialLoad = false;
|
|
} else {
|
|
// Handle real-time updates
|
|
snapshot?.docChanges().forEach(change => {
|
|
if (change.type === 'added') {
|
|
const payment = change.doc.data();
|
|
paymentQueueRef.current.push({
|
|
...payment,
|
|
id: change.doc.id,
|
|
shouldNavigate: false,
|
|
runCount: 0,
|
|
});
|
|
}
|
|
});
|
|
|
|
if (snapshot?.docChanges().length > 0) {
|
|
processQueue();
|
|
}
|
|
}
|
|
});
|
|
return unsubscribe;
|
|
};
|
|
const unsubscribe = setupListener();
|
|
|
|
return () => {
|
|
if (unsubscribe) {
|
|
unsubscribe();
|
|
}
|
|
loadListener.current = false;
|
|
};
|
|
}, [sparkAddress, masterInfoObject.uuid]);
|
|
|
|
// Process payment queue
|
|
const processQueue = useCallback(async () => {
|
|
if (!masterInfoObject?.uuid) return;
|
|
if (!sparkAddress) return;
|
|
if (isProcessingRef.current) return;
|
|
|
|
isProcessingRef.current = true;
|
|
|
|
try {
|
|
const currentQueue = [...paymentQueueRef.current];
|
|
console.log(`Processing ${currentQueue.length} LNURL payments`);
|
|
if (currentQueue.length === 0) return;
|
|
|
|
const newQueue = [];
|
|
const processedIds = [];
|
|
|
|
for (const payment of currentQueue) {
|
|
console.log(`Processing LNURL payment ${payment.id}`, payment);
|
|
|
|
if (!payment.sparkID) {
|
|
console.warn(`Skipping payment ${payment.id} - missing sparkID`);
|
|
continue;
|
|
}
|
|
|
|
try {
|
|
await addSingleUnpaidSparkLightningTransaction({
|
|
id: payment.sparkID,
|
|
amount: payment.amountSats,
|
|
expiration: payment.expiredTime,
|
|
description: parseDescription(payment.description) || '',
|
|
shouldNavigate: payment.shouldNavigate,
|
|
details: {
|
|
sendingUUID: payment.senderUUID,
|
|
isBlitzContactPayment: payment.isBlitzContactPayment,
|
|
createdTime: payment.createdAt,
|
|
sharedPublicKey: payment.sharedPublicKey || '',
|
|
sparkPubKey: payment.sparkPubKey || '',
|
|
isLNURL: true,
|
|
},
|
|
});
|
|
processedIds.push(payment.id);
|
|
deleteActiveLNURLPaymentsRef.current.push(payment.id);
|
|
} catch (error) {
|
|
console.error(`Error processing payment ${payment.id}:`, error);
|
|
// Don't add to processedIds so it can be retried
|
|
}
|
|
}
|
|
|
|
// Update queue and clean up processed payments
|
|
paymentQueueRef.current = paymentQueueRef.current
|
|
.filter(
|
|
item =>
|
|
!processedIds.includes(item.id) &&
|
|
!currentQueue.some(processed => processed.id === item.id),
|
|
)
|
|
.concat(newQueue);
|
|
|
|
if (deleteActiveLNURLPaymentsRef.current.length > 0) {
|
|
try {
|
|
await batchDeleteLnurlPayments(
|
|
masterInfoObject.uuid,
|
|
deleteActiveLNURLPaymentsRef.current,
|
|
);
|
|
deleteActiveLNURLPaymentsRef.current = [];
|
|
} catch (error) {
|
|
console.error('Error deleting processed payments:', error);
|
|
}
|
|
}
|
|
|
|
if (newQueue.length > 0) {
|
|
timeoutRef.current = setTimeout(() => {
|
|
processQueue();
|
|
}, 10000);
|
|
}
|
|
} catch (error) {
|
|
console.error('Error in processQueue:', error);
|
|
} finally {
|
|
isProcessingRef.current = false;
|
|
}
|
|
}, [sparkAddress, masterInfoObject.uuid]);
|
|
|
|
return null;
|
|
}
|