Merge branch 'hemant' of http://git.wdipl.com/CityCards/CityCards-Website
This commit is contained in:
@@ -27,6 +27,7 @@ export function PaymentCancelPage({
|
||||
useEffect(() => {
|
||||
localStorage.removeItem('pendingBookingId');
|
||||
sessionStorage.removeItem('pendingBookingId');
|
||||
document.cookie = 'pendingBookingId=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;';
|
||||
}, []);
|
||||
|
||||
return (
|
||||
|
||||
@@ -289,6 +289,13 @@ export function PaymentDetailsPage({
|
||||
|
||||
const { checkoutPageUrl } = payResponse;
|
||||
|
||||
|
||||
const setCookie = (name: string, value: string, days = 1) => {
|
||||
const expires = new Date();
|
||||
expires.setTime(expires.getTime() + days * 24 * 60 * 60 * 1000);
|
||||
document.cookie = `${name}=${value};expires=${expires.toUTCString()};path=/;SameSite=Lax`;
|
||||
};
|
||||
setCookie('pendingBookingId', bookingId);
|
||||
localStorage.setItem('pendingBookingId', bookingId);
|
||||
sessionStorage.setItem('pendingBookingId', bookingId);
|
||||
|
||||
@@ -317,7 +324,7 @@ export function PaymentDetailsPage({
|
||||
<div className="min-h-screen bg-[#fafafa] font-poppins">
|
||||
<Navbar
|
||||
activeCity="Melbourne"
|
||||
onCityChange={() => {}}
|
||||
onCityChange={() => { }}
|
||||
onSignInClick={onSignInClick}
|
||||
onSignOutClick={onSignOutClick}
|
||||
onPassesClick={onPassesClick}
|
||||
@@ -373,22 +380,20 @@ export function PaymentDetailsPage({
|
||||
<div className="flex gap-2 mb-6">
|
||||
<button
|
||||
onClick={() => setSelectedTab('myself')}
|
||||
className={`flex-1 flex items-center justify-center gap-2 py-3 rounded-xl font-poppins text-sm font-medium transition-all duration-200 ${
|
||||
selectedTab === 'myself'
|
||||
className={`flex-1 flex items-center justify-center gap-2 py-3 rounded-xl font-poppins text-sm font-medium transition-all duration-200 ${selectedTab === 'myself'
|
||||
? 'bg-[#F95F62] text-white shadow-md shadow-[#F95F62]/20'
|
||||
: 'bg-gray-100 text-[#555] hover:bg-gray-200'
|
||||
}`}
|
||||
}`}
|
||||
>
|
||||
<User className="w-4 h-4" />
|
||||
<span>For myself</span>
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setSelectedTab('gift')}
|
||||
className={`flex-1 flex items-center justify-center gap-2 py-3 rounded-xl font-poppins text-sm font-medium transition-all duration-200 ${
|
||||
selectedTab === 'gift'
|
||||
className={`flex-1 flex items-center justify-center gap-2 py-3 rounded-xl font-poppins text-sm font-medium transition-all duration-200 ${selectedTab === 'gift'
|
||||
? 'bg-[#F95F62] text-white shadow-md shadow-[#F95F62]/20'
|
||||
: 'bg-gray-100 text-[#555] hover:bg-gray-200'
|
||||
}`}
|
||||
}`}
|
||||
>
|
||||
<Gift className="w-4 h-4" />
|
||||
<span>To gift Someone</span>
|
||||
@@ -423,12 +428,12 @@ export function PaymentDetailsPage({
|
||||
<h2 className="font-poppins text-xl leading-snug font-semibold text-[#2a2a2a]">Personal Information</h2>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<Field label="First Name" value={formData.firstName} onChange={() => {}} prefilled disabled />
|
||||
<Field label="Last Name" value={formData.lastName} onChange={() => {}} prefilled disabled />
|
||||
<Field label="First Name" value={formData.firstName} onChange={() => { }} prefilled disabled />
|
||||
<Field label="Last Name" value={formData.lastName} onChange={() => { }} prefilled disabled />
|
||||
</div>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<Field label="Email Address" value={formData.email} onChange={() => {}} type="email" prefilled disabled />
|
||||
<Field label="Phone Number" value={formData.phone} onChange={() => {}} type="tel" prefilled disabled />
|
||||
<Field label="Email Address" value={formData.email} onChange={() => { }} type="email" prefilled disabled />
|
||||
<Field label="Phone Number" value={formData.phone} onChange={() => { }} type="tel" prefilled disabled />
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
@@ -524,15 +529,15 @@ export function PaymentDetailsPage({
|
||||
<h2 className="font-poppins text-xl leading-snug font-semibold text-[#2a2a2a]">Billing Address</h2>
|
||||
</div>
|
||||
<div className="space-y-4">
|
||||
<Field label="Address 1" value={formData.address1} onChange={() => {}} prefilled disabled />
|
||||
<Field label="Address 2" value={formData.address2} onChange={() => {}} prefilled disabled />
|
||||
<Field label="Address 1" value={formData.address1} onChange={() => { }} prefilled disabled />
|
||||
<Field label="Address 2" value={formData.address2} onChange={() => { }} prefilled disabled />
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<Field label="City / Suburb" value={formData.city} onChange={() => {}} prefilled disabled />
|
||||
<Field label="State" value="Victoria" onChange={() => {}} prefilled disabled />
|
||||
<Field label="City / Suburb" value={formData.city} onChange={() => { }} prefilled disabled />
|
||||
<Field label="State" value="Victoria" onChange={() => { }} prefilled disabled />
|
||||
</div>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<Field label="Postcode" value={formData.postalCode} onChange={() => {}} inputMode="numeric" prefilled disabled />
|
||||
<Field label="Country" value={formData.country} onChange={() => {}} prefilled disabled />
|
||||
<Field label="Postcode" value={formData.postalCode} onChange={() => { }} inputMode="numeric" prefilled disabled />
|
||||
<Field label="Country" value={formData.country} onChange={() => { }} prefilled disabled />
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
@@ -551,11 +556,10 @@ export function PaymentDetailsPage({
|
||||
<div className="px-6 py-5 border-b border-gray-100">
|
||||
<div className="flex items-start gap-4">
|
||||
<div
|
||||
className={`w-16 h-10 rounded-lg flex-shrink-0 flex items-center justify-center ${
|
||||
bookingDetails?.cardMode?.toLowerCase() === 'flexi'
|
||||
className={`w-16 h-10 rounded-lg flex-shrink-0 flex items-center justify-center ${bookingDetails?.cardMode?.toLowerCase() === 'flexi'
|
||||
? 'bg-gradient-to-br from-[#f95faf] to-[#F95F62]'
|
||||
: 'bg-gradient-to-br from-[#F95F62] to-[#c94245]'
|
||||
}`}
|
||||
}`}
|
||||
>
|
||||
<span className="font-poppins text-[10px] font-semibold text-white">{bookingDetails?.cardMode}</span>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useNavigate, useSearchParams } from 'react-router-dom';
|
||||
import { CheckCircle, XCircle, Loader2 } from 'lucide-react';
|
||||
import { CheckCircle, XCircle, Loader2, AlertCircle } from 'lucide-react';
|
||||
import { useConfirmCardPaymentMutation } from '../Redux/services/cards.service';
|
||||
import { toast } from 'sonner';
|
||||
import Navbar from '../components/Navbar';
|
||||
@@ -15,6 +15,14 @@ interface PaymentSuccessPageProps {
|
||||
user?: { email: string; name: string } | null;
|
||||
}
|
||||
|
||||
// Helper to get cookie value
|
||||
const getCookie = (name: string): string | null => {
|
||||
const value = `; ${document.cookie}`;
|
||||
const parts = value.split(`; ${name}=`);
|
||||
if (parts.length === 2) return parts.pop()?.split(';').shift() || null;
|
||||
return null;
|
||||
};
|
||||
|
||||
export function PaymentSuccessPage({
|
||||
onHomeClick,
|
||||
onPassesClick,
|
||||
@@ -25,34 +33,38 @@ export function PaymentSuccessPage({
|
||||
}: PaymentSuccessPageProps) {
|
||||
const [searchParams] = useSearchParams();
|
||||
const [confirmPayment, { isLoading }] = useConfirmCardPaymentMutation();
|
||||
const [status, setStatus] = useState<'loading' | 'success' | 'error'>('loading');
|
||||
const [status, setStatus] = useState<'loading' | 'success' | 'error' | 'manual'>('loading');
|
||||
const [errorMsg, setErrorMsg] = useState<string>('');
|
||||
const [manualBookingId, setManualBookingId] = useState('');
|
||||
const navigate = useNavigate();
|
||||
|
||||
useEffect(() => {
|
||||
const confirm = async () => {
|
||||
// Try multiple sources to get bookingId
|
||||
let bookingId = localStorage.getItem('pendingBookingId');
|
||||
const retrieveBookingId = async () => {
|
||||
// Try all possible sources
|
||||
let bookingId = getCookie('pendingBookingId');
|
||||
if (!bookingId) bookingId = localStorage.getItem('pendingBookingId');
|
||||
if (!bookingId) bookingId = sessionStorage.getItem('pendingBookingId');
|
||||
if (!bookingId) bookingId = searchParams.get('bookingId'); // URL query param
|
||||
if (!bookingId) bookingId = searchParams.get('bookingId');
|
||||
|
||||
console.log('Retrieved bookingId:', bookingId);
|
||||
console.log('Retrieved bookingId from sources:', {
|
||||
cookie: getCookie('pendingBookingId'),
|
||||
localStorage: localStorage.getItem('pendingBookingId'),
|
||||
sessionStorage: sessionStorage.getItem('pendingBookingId'),
|
||||
queryParam: searchParams.get('bookingId'),
|
||||
final: bookingId,
|
||||
});
|
||||
|
||||
if (!bookingId) {
|
||||
setStatus('error');
|
||||
setErrorMsg(
|
||||
'Booking ID not found. Please contact support with your order details. ' +
|
||||
'If you just completed payment, your order may still be processing.'
|
||||
);
|
||||
setStatus('manual'); // show manual entry form
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// ✅ Call confirm API with only bookingId
|
||||
await confirmPayment(bookingId).unwrap();
|
||||
setStatus('success');
|
||||
toast.success('Payment confirmed! Your order is complete.');
|
||||
// Clean up storage
|
||||
// Clean up
|
||||
document.cookie = 'pendingBookingId=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;';
|
||||
localStorage.removeItem('pendingBookingId');
|
||||
sessionStorage.removeItem('pendingBookingId');
|
||||
} catch (err: any) {
|
||||
@@ -60,15 +72,34 @@ export function PaymentSuccessPage({
|
||||
setStatus('error');
|
||||
setErrorMsg(err?.data?.message || 'Failed to confirm payment. Please contact support.');
|
||||
toast.error('Confirmation failed');
|
||||
// Clean up to avoid retry loops
|
||||
localStorage.removeItem('pendingBookingId');
|
||||
sessionStorage.removeItem('pendingBookingId');
|
||||
}
|
||||
};
|
||||
|
||||
confirm();
|
||||
retrieveBookingId();
|
||||
}, [confirmPayment, searchParams]);
|
||||
|
||||
const handleManualConfirm = async () => {
|
||||
if (!manualBookingId.trim()) {
|
||||
toast.error('Please enter your Booking ID');
|
||||
return;
|
||||
}
|
||||
setStatus('loading');
|
||||
try {
|
||||
await confirmPayment(manualBookingId).unwrap();
|
||||
setStatus('success');
|
||||
toast.success('Payment confirmed! Your order is complete.');
|
||||
// Clean up
|
||||
document.cookie = 'pendingBookingId=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;';
|
||||
localStorage.removeItem('pendingBookingId');
|
||||
sessionStorage.removeItem('pendingBookingId');
|
||||
} catch (err: any) {
|
||||
console.error('Manual confirmation error:', err);
|
||||
setStatus('error');
|
||||
setErrorMsg(err?.data?.message || 'Failed to confirm payment. Please contact support.');
|
||||
toast.error('Confirmation failed');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-[#fafafa] font-poppins">
|
||||
<Navbar
|
||||
@@ -135,6 +166,40 @@ export function PaymentSuccessPage({
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
|
||||
{status === 'manual' && (
|
||||
<>
|
||||
<AlertCircle className="w-16 h-16 text-yellow-500 mx-auto mb-4" />
|
||||
<h2 className="text-2xl font-semibold text-[#2a2a2a]">Booking ID Not Found</h2>
|
||||
<p className="text-[#555] mt-2">
|
||||
We couldn't automatically retrieve your booking ID. Please enter it below to confirm your payment.
|
||||
<br />
|
||||
<span className="text-sm text-gray-400">(Check your email or order history for the Booking ID)</span>
|
||||
</p>
|
||||
<div className="mt-4">
|
||||
<input
|
||||
type="text"
|
||||
value={manualBookingId}
|
||||
onChange={(e) => setManualBookingId(e.target.value)}
|
||||
placeholder="Enter Booking ID"
|
||||
className="w-full border rounded-xl px-4 py-3 font-poppins text-base outline-none focus:border-[#F95F62]"
|
||||
/>
|
||||
<button
|
||||
onClick={handleManualConfirm}
|
||||
disabled={isLoading}
|
||||
className="mt-4 w-full px-6 py-3 bg-[#F95F62] text-white rounded-xl font-medium hover:bg-[#e8545a] transition disabled:opacity-50"
|
||||
>
|
||||
{isLoading ? 'Confirming...' : 'Confirm Payment'}
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
onClick={onHomeClick}
|
||||
className="mt-3 text-sm text-gray-500 hover:text-gray-700"
|
||||
>
|
||||
Return to Home
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user