Progress on payment flow, added purchases endpoint

This commit is contained in:
austinkelsay 2024-08-11 19:10:08 -05:00
parent 42a9d243ca
commit 573f560f28
4 changed files with 69 additions and 8 deletions

View File

@ -3,6 +3,7 @@ import dynamic from 'next/dynamic';
import { initializeBitcoinConnect } from './BitcoinConnect'; import { initializeBitcoinConnect } from './BitcoinConnect';
import { LightningAddress } from '@getalby/lightning-tools'; import { LightningAddress } from '@getalby/lightning-tools';
import { useToast } from '@/hooks/useToast'; import { useToast } from '@/hooks/useToast';
import axios from 'axios'; // Import axios for API calls
const PayButton = dynamic( const PayButton = dynamic(
() => import('@getalby/bitcoin-connect-react').then((mod) => mod.PayButton), () => import('@getalby/bitcoin-connect-react').then((mod) => mod.PayButton),
@ -11,7 +12,7 @@ const PayButton = dynamic(
} }
); );
const PaymentButton = ({ lnAddress, amount, onSuccess, onError }) => { const PaymentButton = ({ lnAddress, amount, onSuccess, onError, userId, resourceId }) => {
const [invoice, setInvoice] = useState(null); const [invoice, setInvoice] = useState(null);
const { showToast } = useToast(); const { showToast } = useToast();
const [pollingInterval, setPollingInterval] = useState(null); const [pollingInterval, setPollingInterval] = useState(null);
@ -64,14 +65,31 @@ const PaymentButton = ({ lnAddress, amount, onSuccess, onError }) => {
}; };
const handlePaymentSuccess = async (response) => { const handlePaymentSuccess = async (response) => {
stopPolling(); // Stop polling after success stopPolling();
// Close the modal
await closeModal(); await closeModal();
// After the modal is closed, show the success toast try {
showToast('success', 'Payment Successful', `Paid ${amount} sats`); // Create a new purchase record
if (onSuccess) onSuccess(response); const purchaseData = {
userId: userId,
resourceId: resourceId,
amountPaid: parseInt(amount, 10) // Convert amount to integer
};
// Make an API call to add the purchase to the user
const result = await axios.post('/api/purchases', purchaseData);
if (result.status === 200) {
showToast('success', 'Payment Successful', `Paid ${amount} sats and updated user purchases`);
if (onSuccess) onSuccess(response);
} else {
throw new Error('Failed to update user purchases');
}
} catch (error) {
console.error('Error updating user purchases:', error);
showToast('error', 'Purchase Update Failed', 'Payment was successful, but failed to update user purchases.');
if (onError) onError(error);
}
}; };
const handlePaymentError = (error) => { const handlePaymentError = (error) => {

View File

@ -44,6 +44,20 @@ export const getUserByPubkey = async (pubkey) => {
}); });
} }
export const addPurchaseToUser = async (userId, purchaseData) => {
return await prisma.user.update({
where: { id: userId },
data: {
purchased: {
create: purchaseData
}
},
include: {
purchased: true
}
});
};
export const createUser = async (data) => { export const createUser = async (data) => {
return await prisma.user.create({ return await prisma.user.create({
data, data,

View File

@ -0,0 +1,21 @@
import { addPurchaseToUser } from "@/db/models/userModels";
export default async function handler(req, res) {
if (req.method === 'POST') {
try {
const { userId, resourceId, amountPaid } = req.body;
const updatedUser = await addPurchaseToUser(userId, {
resourceId,
amountPaid: parseInt(amountPaid, 10) // Ensure amountPaid is an integer
});
res.status(200).json(updatedUser);
} catch (error) {
res.status(500).json({ error: error.message });
}
} else {
res.setHeader('Allow', ['POST']);
res.status(405).end(`Method ${req.method} Not Allowed`);
}
}

View File

@ -262,7 +262,15 @@ export default function Details() {
className="w-[344px] h-[194px] object-cover object-top rounded-lg" className="w-[344px] h-[194px] object-cover object-top rounded-lg"
/> />
<div className='w-full flex flex-row justify-between'> <div className='w-full flex flex-row justify-between'>
{paidResource && !decryptedContent && <PaymentButton lnAddress={'bitcoinplebdev@stacker.news'} amount={processedEvent.price} onSuccess={handlePaymentSuccess} onError={handlePaymentError} />} {paidResource && !decryptedContent && <PaymentButton
lnAddress={'bitcoinplebdev@stacker.news'}
amount={processedEvent.price}
onSuccess={handlePaymentSuccess}
onError={handlePaymentError}
userId={user.id} // Pass the user ID
resourceId={processedEvent.id} // Pass the course/resource ID
/>}
<ZapDisplay zapAmount={zapAmount} event={processedEvent} zapsLoading={zapsLoading} /> <ZapDisplay zapAmount={zapAmount} event={processedEvent} zapsLoading={zapsLoading} />
</div> </div>
</div> </div>