322 lines
15 KiB
JavaScript
322 lines
15 KiB
JavaScript
import React, {useState, useEffect} from "react";
|
|
import { Button } from "./ui/button";
|
|
import { Input } from "./ui/input";
|
|
import QRCode from "react-qr-code";
|
|
import { Dialog, DialogContent, DialogHeader, DialogTitle} from "./ui/dialog";
|
|
import { Toast } from './Toast';
|
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "./ui/card";
|
|
import { FileX, Copy, CheckCircle2, AlertCircle, X } from "lucide-react";
|
|
import Loader from "./ui/loader";
|
|
const API_URL = 'https://host-api.cs1.hz.siliconpin.com/v1/users/';
|
|
export default function MakePayment(){
|
|
const [initialOrderData, setInitialOrderData] = useState(null);
|
|
const [isLoading, setIsLoading] = useState(true);
|
|
const [error, setError] = useState(null);
|
|
const [showQRModal, setShowQRModal] = useState(false);
|
|
const [showHelpMessage, setShowHelpMessage] = useState(false);
|
|
const [transactionId, setTransactionId] = useState('');
|
|
const [orderIdInput, setOrderIdInput] = useState('');
|
|
const [upiPaymentLink, setUpiPaymentLink] = useState("");
|
|
const [copied, setCopied] = useState(false);
|
|
const [getOrderId, setGetOrderId] = useState();
|
|
const [saveUpiResponse, setSaveUpiResponse] = useState({ message: '', visible: false, isSuccess: false });
|
|
|
|
useEffect(() => {
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|
const orderId = urlParams.get('orderId');
|
|
|
|
if (!orderId) {
|
|
setError('Order ID is missing from URL');
|
|
setIsLoading(false);
|
|
return;
|
|
}
|
|
setGetOrderId(orderId);
|
|
const getInitialOrderData = () => {
|
|
setIsLoading(true);
|
|
const formData = new FormData();
|
|
formData.append('order_id', orderId);
|
|
|
|
fetch(`${API_URL}?query=get-initiated_payment`, {
|
|
method: 'POST',
|
|
body: formData,
|
|
credentials: 'include'
|
|
})
|
|
.then(response => {
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
return response.json();
|
|
})
|
|
.then(data => {
|
|
if (!data.success) {
|
|
throw new Error(data.message || 'Failed to initialize payment');
|
|
}
|
|
setInitialOrderData(data);
|
|
setError(null);
|
|
|
|
// Generate UPI payment link when data is loaded
|
|
if (data.payment_data?.amount) {
|
|
const amount = data.payment_data.amount;
|
|
const upiLink = generateUPILink(amount, data.txn_id);
|
|
setUpiPaymentLink(upiLink);
|
|
}
|
|
})
|
|
.catch(error => {
|
|
setError(error.message || 'Payment failed. Please try again.');
|
|
console.error('An error occurred:', error);
|
|
})
|
|
.finally(() => {
|
|
setIsLoading(false);
|
|
});
|
|
};
|
|
|
|
getInitialOrderData();
|
|
}, []);
|
|
|
|
function generateUPILink(amount, transactionId) {
|
|
// Replace these with your actual merchant details
|
|
const merchantUPI = "7001601485@okbizaxis";
|
|
const merchantName = "SiliconPin";
|
|
const currency = "INR";
|
|
|
|
// Encode parameters for URL
|
|
const encodedMerchantName = encodeURIComponent(merchantName);
|
|
const transactionNote = encodeURIComponent(`Payment for order #${transactionId}`);
|
|
|
|
// Construct UPI payment link
|
|
return `upi://pay?pa=${merchantUPI}&pn=${encodedMerchantName}&am=${amount}&cu=${currency}&tn=${transactionNote}`;
|
|
}
|
|
// waiting payment update
|
|
// Payment update not recieved if
|
|
function redirectToPayU() {
|
|
if (!initialOrderData?.payment_data || !initialOrderData.payment_url) {
|
|
console.error('Payment data not loaded yet');
|
|
alert('Payment information is not ready. Please wait.');
|
|
return;
|
|
}
|
|
|
|
// Create a form dynamically
|
|
const form = document.createElement('form');
|
|
form.method = 'POST';
|
|
form.action = initialOrderData.payment_url;
|
|
form.style.display = 'none';
|
|
|
|
Object.entries(initialOrderData.payment_data).forEach(([key, value]) => {
|
|
const input = document.createElement('input');
|
|
input.type = 'text';
|
|
input.name = key;
|
|
input.value = value;
|
|
form.appendChild(input);
|
|
console.log(`Adding field: ${key}=${value}`);
|
|
});
|
|
|
|
document.body.appendChild(form);
|
|
form.submit();
|
|
}
|
|
|
|
useEffect(() => {
|
|
let timer;
|
|
if (showQRModal) {
|
|
setShowHelpMessage(false);
|
|
timer = setTimeout(() => {
|
|
setShowHelpMessage(true);
|
|
}, 2000);
|
|
}
|
|
return () => clearTimeout(timer); // Cleanup on unmount or when modal closes
|
|
}, [showQRModal]);
|
|
|
|
function handleQRPaymentClick() {
|
|
if (!upiPaymentLink) {
|
|
alert('Payment information is not ready. Please wait.');
|
|
return;
|
|
}
|
|
setShowQRModal(true);
|
|
}
|
|
|
|
const handleCopy = () => {
|
|
navigator.clipboard.writeText(getOrderId)
|
|
.then(() => {
|
|
setCopied(true);
|
|
setTimeout(() => setCopied(false), 1000); // Reset after 1 second
|
|
})
|
|
.catch(err => {
|
|
console.error('Failed to copy text: ', err);
|
|
});
|
|
};
|
|
const handlePayPalPayment = () => {
|
|
const rawInrAmount = initialOrderData.payment_data?.amount || 0;
|
|
const exchangeRate = 80;
|
|
const convertedUSD = rawInrAmount / exchangeRate;
|
|
const usdAmount = Math.max(convertedUSD, 1).toFixed(2);
|
|
const paypalUrl = `https://www.paypal.com/paypalme/dwdconsultancy/${usdAmount}`;
|
|
window.open(paypalUrl, '_blank');
|
|
};
|
|
|
|
const handleSaveUPIPayment = async () => {
|
|
try {
|
|
const response = await fetch(`${API_URL}?query=save-upi-payment`, {
|
|
method: 'POST',
|
|
credentials: 'include',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({
|
|
orderId: orderIdInput,
|
|
transactionId: transactionId
|
|
})
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
if (data.success === true) {
|
|
setSaveUpiResponse({
|
|
message: `Transaction ID ${transactionId} saved. We'll contact you shortly.`,
|
|
visible: true,
|
|
isSuccess: true
|
|
});
|
|
setShowHelpMessage(false);
|
|
}
|
|
} catch (error) {
|
|
console.error('Error:', error);
|
|
setSaveUpiResponse({
|
|
message: 'Failed to save payment details. Please try again.',
|
|
visible: true,
|
|
isSuccess: false
|
|
});
|
|
}
|
|
};
|
|
|
|
|
|
if (isLoading) {
|
|
return <Loader />;
|
|
}
|
|
|
|
if(!initialOrderData){
|
|
return (
|
|
<div className="flex flex-col items-center justify-center flex-grow py-10 text-center px-4 text-gray-600 mt-20">
|
|
<FileX className="mb-4 text-gray-500" size={100} />
|
|
<p className="text-lg"> No bill was found. <a className="text-[#6d9e37] font-medium hover:underline" href="/profile"> Click here </a> to go to your profile.</p>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
if (error) {
|
|
return <div className="flex items-center justify-center min-h-screen">
|
|
<div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
|
|
<strong>Error:</strong> {error}
|
|
</div>
|
|
</div>;
|
|
}
|
|
|
|
return (
|
|
<div className="flex flex-col items-center justify-center min-h-screen p-4">
|
|
<Card className="max-w-md w-full bg-white p-6 rounded-lg shadow-md">
|
|
<h1 className="text-2xl font-bold mb-4">Complete Your Payment</h1>
|
|
|
|
{initialOrderData && (
|
|
<div className="mb-6 p-4 bg-gray-50 rounded-lg">
|
|
<div className="flex justify-between mb-2">
|
|
<span className="font-bold">Order ID:</span>
|
|
<span>{initialOrderData.txn_id}</span>
|
|
</div>
|
|
<div className="flex justify-between">
|
|
<span className="font-bold">Amount:</span>
|
|
<span>₹{initialOrderData.payment_data?.amount}</span>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
<div className="flex flex-col">
|
|
<span className=""><strong>Pay Using:</strong></span>
|
|
<hr className="border-b border-b-[#6d9e37] mb-4" />
|
|
|
|
<Button className="" onClick={handleQRPaymentClick}>UPI QR Code</Button>
|
|
<span className="text-center mt-2 text-gray-400 text-xs">Banking Service by DWD Consultancy Services (0% Processing Fee)</span>
|
|
|
|
<div className="flex items-center my-2">
|
|
<div className="flex-grow border-t border-gray-500"></div>
|
|
<span className="mx-2 text-gray-500 font-semibold">OR</span>
|
|
<div className="flex-grow border-t border-gray-500"></div>
|
|
</div>
|
|
|
|
<Button className="text-[#414042] font-bold border-[2px] border-[#00ad7d] hover:bg-[#00ad7d]/80" onClick={redirectToPayU} variant="outline">
|
|
Pay with
|
|
<img className="w-[50px]" src="/assets/payu-logo.svg" alt="" />
|
|
</Button>
|
|
<Button
|
|
variant="outline"
|
|
className="mt-4 text-[#414042] font-bold border-[2px] border-b-[#003087] border-r-[#003087] border-t-[#009CDE] border-l-[#009CDE] hover:bg-gradient-to-r hover:from-[#009CDE] hover:to-[#003087]"
|
|
onClick={handlePayPalPayment}
|
|
>
|
|
Pay with
|
|
<img className="w-[50px]" src="/assets/paypal-logo-white.svg" alt="PayPal" />
|
|
</Button>
|
|
{/* <span className="text-center mt-2 text-gray-400 text-xs">2% Payment Gateway Charge</span> */}
|
|
|
|
{/* Add this divider and PayPal button */}
|
|
{/* <div className="flex items-center my-2">
|
|
<div className="flex-grow border-t border-gray-500"></div>
|
|
<span className="mx-2 text-gray-500 font-semibold">OR</span>
|
|
<div className="flex-grow border-t border-gray-500"></div>
|
|
</div> */}
|
|
|
|
|
|
{/* <span className="text-center mt-2 text-gray-400 text-xs">3.5% Payment Processing Fee</span> */}
|
|
</div>
|
|
</Card>
|
|
|
|
{/* QR Code Modal */}
|
|
<Dialog open={showQRModal} onOpenChange={(open) => {setShowQRModal(open); if (!open) {setShowHelpMessage(false);}}}>
|
|
<DialogContent className="sm:max-w-md">
|
|
<DialogHeader>
|
|
<DialogTitle>Scan QR Code to Pay</DialogTitle>
|
|
</DialogHeader>
|
|
<div className="flex flex-col items-center space-y-4">
|
|
<div className="p-4 bg-white rounded-lg border border-gray-200">
|
|
<QRCode value={upiPaymentLink} size={256} level="H" bgColor="#ffffff" fgColor="#000000" />
|
|
</div>
|
|
<p className="text-sm text-gray-500 text-center">
|
|
Scan this QR code with any UPI app to complete your payment
|
|
</p>
|
|
<Button variant="outline" onClick={handleCopy} className="text-sm" >{copied ? 'Copied!' : getOrderId} {!copied && <Copy size={15} />}</Button>
|
|
|
|
{showHelpMessage && (
|
|
<div className="w-full mt-4 p-4 bg-yellow-50 rounded-lg border border-yellow-200">
|
|
<p className="text-sm text-yellow-800 mb-3">
|
|
If you haven't received payment confirmation, please share your Order Id & transaction ID with us.
|
|
</p>
|
|
<Input type="text" value={orderIdInput} onChange={(e) => setOrderIdInput(e.target.value)} placeholder="Enter your Order ID" className="w-full p-2 border border-gray-300 rounded-md text-sm mb-2" />
|
|
<Input type="text" value={transactionId} onChange={(e) => setTransactionId(e.target.value)} placeholder="Enter your transaction ID" className="w-full p-2 border border-gray-300 rounded-md text-sm mb-2" />
|
|
<Button onClick={handleSaveUPIPayment} className="w-full text-sm">Save Transaction ID</Button>
|
|
</div>
|
|
)}
|
|
{saveUpiResponse.visible && (
|
|
<div className={`fixed bottom-0 z-50 flex items-center justify-center`}>
|
|
<div className={`relative p-6 rounded-lg shadow-lg max-w-xs md:max-w-md w-full ${saveUpiResponse.isSuccess ? 'bg-green-50 border border-green-200 text-green-800' : 'bg-red-50 border border-red-200 text-red-800'} animate-fade-in-up`}>
|
|
<button
|
|
onClick={() => setSaveUpiResponse(prev => ({...prev, visible: false}))}
|
|
className={`absolute top-3 right-3 p-1 rounded-full ${saveUpiResponse.isSuccess ? 'hover:bg-green-100 text-green-500' : 'hover:bg-red-100 text-red-500'} transition-colors`}>
|
|
<X className="w-4 h-4" />
|
|
</button>
|
|
|
|
<div className="flex flex-col items-center text-center gap-4">
|
|
<div className="flex items-center gap-3">
|
|
{saveUpiResponse.isSuccess ? (
|
|
<CheckCircle2 className="w-6 h-6 text-green-500" />
|
|
) : (
|
|
<AlertCircle className="w-6 h-6 text-red-500" />
|
|
)}
|
|
<p className="text-base font-medium">{saveUpiResponse.message}</p>
|
|
</div>
|
|
<Button variant="outline" size="sm" onClick={() => window.location.href = '/'} className={saveUpiResponse.isSuccess ? 'border-green-300' : 'border-red-300'}>Back to Home</Button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</DialogContent>
|
|
</Dialog>
|
|
</div>
|
|
);
|
|
}
|
|
// Transaction ID ${transactionId} saved. We'll contact you shortly. |