diff --git a/src/app/(protected)/dashboard/org/my-event/[my-eventId]/page.jsx b/src/app/(protected)/dashboard/org/my-event/[my-eventId]/page.jsx
index 9f9c711..b39aacc 100644
--- a/src/app/(protected)/dashboard/org/my-event/[my-eventId]/page.jsx
+++ b/src/app/(protected)/dashboard/org/my-event/[my-eventId]/page.jsx
@@ -28,7 +28,8 @@ import {
Minus,
Plus,
Megaphone,
- Tag
+ Tag,
+ Landmark
} from "lucide-react";
import toast from "react-hot-toast";
import { getImageUrl, getErrorMessage } from "../../../../../../lib/utils";
@@ -46,6 +47,7 @@ import useTempBookingStore from "@/store/tempBookingStore";
function BookForAttendeeModal({ isOpen, onClose, event, eventId, onSuccess, onManualPaymentRequired }) {
const router = useRouter();
const [loading, setLoading] = useState(false);
+ const [paymentMethod, setPaymentMethod] = useState('paystack');
const [formData, setFormData] = useState({
firstname: '',
lastname: '',
@@ -112,14 +114,14 @@ function BookForAttendeeModal({ isOpen, onClose, event, eventId, onSuccess, onMa
]
};
if (isPaidEvent) {
- payload.payment_method = 'paystack';
+ payload.payment_method = paymentMethod;
}
const response = await api.post('/tickets/organizer/book-for-attendee/', payload);
const result = response.data;
// Paid event: store booking with base subtotal so checkout page adds platform + Paystack fees
- if (isPaidEvent && result.booking_id != null && result.payment_url != null) {
+ if (isPaidEvent && result.booking_id != null) {
const price = selectedCategory?.price ?? 0;
const subtotal = price * formData.quantity;
const items = [{
@@ -139,6 +141,7 @@ function BookForAttendeeModal({ isOpen, onClose, event, eventId, onSuccess, onMa
payment_url: result.payment_url || null,
payment_reference: result.payment_reference || null,
tickets: result.tickets || [],
+ payment_method: paymentMethod,
created_at: new Date().toISOString(),
organizer_booking: {
returnUrl: window.location.pathname,
@@ -150,7 +153,10 @@ function BookForAttendeeModal({ isOpen, onClose, event, eventId, onSuccess, onMa
onSuccess?.();
onClose();
toast.success('Proceeding to checkout...');
- router.push(`/checkout/payment/${result.booking_id}`);
+ const checkoutUrl = paymentMethod === 'manual_bank_transfer'
+ ? `/checkout/payment/${result.booking_id}?method=bank_transfer`
+ : `/checkout/payment/${result.booking_id}`;
+ router.push(checkoutUrl);
return;
}
@@ -287,6 +293,40 @@ function BookForAttendeeModal({ isOpen, onClose, event, eventId, onSuccess, onMa
+ {/* Payment Method Selection */}
+ {isPaidEvent && (
+
+
+
+ Payment Method
+
+
+
+
+
+
+ )}
+
{/* Ticket Selection Card */}
diff --git a/src/app/(protected)/dashboard/user/events/[event_id]/page.jsx b/src/app/(protected)/dashboard/user/events/[event_id]/page.jsx
index bf4fd3b..d028914 100644
--- a/src/app/(protected)/dashboard/user/events/[event_id]/page.jsx
+++ b/src/app/(protected)/dashboard/user/events/[event_id]/page.jsx
@@ -377,13 +377,18 @@ const EventDetailsPage = () => {
if (validReferral) clearReferral();
- toast.success("Booking created! Redirecting to checkout...", { id: toastId });
- router.push(`/checkout/payment/${bookingId}`);
+ if (checkoutPaymentMethod === "manual_bank_transfer") {
+ toast.success("Booking created! Please complete the bank transfer.", { id: toastId });
+ router.push(`/checkout/payment/${bookingId}?method=bank_transfer`);
+ } else {
+ toast.success("Booking created! Redirecting to checkout...", { id: toastId });
+ router.push(`/checkout/payment/${bookingId}`);
+ }
return;
}
// Fallback: If there's a direct payment URL, redirect to it
- if (response.data.payment_url) {
+ if (response.data.payment_url && checkoutPaymentMethod !== "manual_bank_transfer") {
toast.success("Redirecting to payment...", { id: toastId });
window.location.href = response.data.payment_url;
return;
diff --git a/src/app/checkout/payment/[booking_id]/page.jsx b/src/app/checkout/payment/[booking_id]/page.jsx
index df4cd08..d4a247e 100644
--- a/src/app/checkout/payment/[booking_id]/page.jsx
+++ b/src/app/checkout/payment/[booking_id]/page.jsx
@@ -49,6 +49,14 @@ export default function CheckoutPaymentPage() {
const [error, setError] = useState(null);
const [activeTab, setActiveTab] = useState("paystack");
+ // Sync active tab with URL parameters for direct redirection (e.g. from organizer dashboard)
+ useEffect(() => {
+ const method = searchParams.get('method');
+ if (method === 'bank_transfer') {
+ setActiveTab('manual_bank_transfer');
+ }
+ }, [searchParams]);
+
useEffect(() => {
const fetchBookingData = async () => {
if (!booking_id) {
diff --git a/src/app/events/[event_id]/EventDetailsClient.jsx b/src/app/events/[event_id]/EventDetailsClient.jsx
index 25b4476..66ccaf2 100644
--- a/src/app/events/[event_id]/EventDetailsClient.jsx
+++ b/src/app/events/[event_id]/EventDetailsClient.jsx
@@ -8,7 +8,7 @@ import { Button } from "@/components/ui/button";
import { Card, CardContent, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input";
-import { Loader2, MapPin, Calendar, Clock, Ticket, Info, Share2, Copy, Check, X, Maximize2, Plus, Minus, ShoppingCart } from "lucide-react";
+import { Loader2, MapPin, Calendar, Clock, Ticket, Info, Share2, Copy, Check, X, Maximize2, Plus, Minus, ShoppingCart, CreditCard, Landmark, Landmark as Bank } from "lucide-react";
import { motion, AnimatePresence } from "framer-motion";
import toast from "react-hot-toast";
import useAuthStore from "@/store/authStore";
@@ -35,6 +35,7 @@ const EventDetailsClient = ({ event_id, initialEvent }) => {
const [event, setEvent] = useState(initialEvent || null);
const [loading, setLoading] = useState(!initialEvent);
const [bookingLoading, setBookingLoading] = useState(false);
+ const [paymentMethod, setPaymentMethod] = useState("paystack"); // 'paystack' or 'manual_bank_transfer'
//Getting booking id for tracking tickets
const [bookingID,setBookingID] = useState(null)
@@ -183,13 +184,15 @@ const EventDetailsClient = ({ event_id, initialEvent }) => {
}
});
- // Paystack calculates fee on total amount INCLUDING platform service fee
- const paystackFee = subtotal > 0 ? calculatePaystackFee(subtotal + PLATFORM_FEE) : 0;
- const platformFee = subtotal > 0 ? PLATFORM_FEE + paystackFee : 0;
+ // Base platform service fee
+ const baseServiceFee = subtotal > 0 ? PLATFORM_FEE : 0;
+ // Paystack processing fee only applies if Paystack is the selected method
+ const paystackFee = (subtotal > 0 && paymentMethod === "paystack") ? calculatePaystackFee(subtotal + PLATFORM_FEE) : 0;
+ const platformFee = baseServiceFee + paystackFee;
const total = subtotal + platformFee;
- return { selectedItems, subtotal, platformFee, total, totalQuantity };
- }, [ticketSelections, categories]);
+ return { selectedItems, subtotal, platformFee, total, totalQuantity, paystackFee };
+ }, [ticketSelections, categories, paymentMethod]);
// Handle quantity change for a category
const handleQuantityChange = (categoryId, delta) => {
@@ -276,6 +279,7 @@ const EventDetailsClient = ({ event_id, initialEvent }) => {
const payload = {
event_id: eventIdToUse,
items: items,
+ payment_method: paymentMethod,
// Scoped referral source for event:TO-56363
...(eventIdToUse === "event:TO-56363" && {
referral: refUsername, // Pass referee username as 'referral' to backend
@@ -314,22 +318,15 @@ const EventDetailsClient = ({ event_id, initialEvent }) => {
};
localStorage.setItem(`booking_${bookingId}`, JSON.stringify(bookingDataForCheckout));
- toast.success("Booking created! Redirecting to payment...", { id: toastId });
- router.push(`/checkout/payment/${bookingId}`);
- return;
- }
-
- // Fallback for cases where booking_id isn't directly returned but payment_url is
- if (response.data.payment_url) {
- toast.success("Redirecting to payment...", { id: toastId });
- window.location.href = response.data.payment_url;
+ if (paymentMethod === "manual_bank_transfer") {
+ toast.success("Booking created! Please complete the bank transfer.", { id: toastId });
+ router.push(`/checkout/payment/${bookingId}?method=bank_transfer`);
+ } else {
+ toast.success("Booking created! Redirecting to payment...", { id: toastId });
+ router.push(`/checkout/payment/${bookingId}`);
+ }
return;
}
-
- toast.success("Ticket booked successfully!", { id: toastId });
- if (typeof window !== "undefined") window.dispatchEvent(new CustomEvent("tickets-updated"));
- router.push("/dashboard/user/my-tickets");
-
} catch (error) {
console.error("Booking error:", error);
let errorMessage = error.response?.data?.error || "Failed to book ticket";
@@ -410,7 +407,7 @@ const EventDetailsClient = ({ event_id, initialEvent }) => {
-
+
{/* Referral Badge */}
{refUsername && (
diff --git a/src/components/organizer/BulkBookForAttendeeModal.jsx b/src/components/organizer/BulkBookForAttendeeModal.jsx
index 9808194..7dae6d9 100644
--- a/src/components/organizer/BulkBookForAttendeeModal.jsx
+++ b/src/components/organizer/BulkBookForAttendeeModal.jsx
@@ -410,12 +410,17 @@ export default function BulkBookForAttendeeModal({
items,
total_quantity: result.ticket_count ?? ticketCount,
subtotal,
- payment_method: "manual_bank_transfer",
- total_manual_amount: result.total_amount || (subtotal + 80),
+ payment_url: result.payment_url || null, // Only for online payments
payment_reference: result.payment_reference || null,
+ payment_method: paymentMethod, // Use the selected payment method
+ total_manual_amount: result.total_amount || (subtotal + 80), // Only for manual transfer, assuming 80 is platform fee
tickets: result.tickets || [],
created_at: new Date().toISOString(),
- organizer_booking: { returnUrl: window.location.pathname },
+ organizer_booking: {
+ returnUrl: window.location.pathname,
+ attendeeEmail: attendees[0]?.email,
+ attendeeName: `${attendees[0]?.firstname} ${attendees[0]?.lastname}`,
+ },
};
localStorage.setItem(
`booking_${result.booking_id}`,
@@ -463,7 +468,7 @@ export default function BulkBookForAttendeeModal({
return;
}
- // Free event
+ // Handle Free Event (Booking is immediate and doesn't require payment routing)
toast.success(
`Successfully booked ${result.ticket_count} ticket(s) for ${result.unique_attendees ?? result.attendees?.length ?? ticketCount} attendee(s)`,
);