Files
Eventify-frontend/lib/features/booking/providers/checkout_provider.dart

148 lines
3.6 KiB
Dart
Raw Normal View History

// lib/features/booking/providers/checkout_provider.dart
import 'package:flutter/foundation.dart';
import '../../../core/utils/error_utils.dart';
import '../models/booking_models.dart';
import '../services/booking_service.dart';
enum CheckoutStep { tickets, details, payment, confirmation }
class CheckoutProvider extends ChangeNotifier {
final BookingService _service = BookingService();
// Event being booked
int? eventId;
String eventName = '';
// Step tracking
CheckoutStep currentStep = CheckoutStep.tickets;
// Ticket selection
List<TicketMetaModel> availableTickets = [];
List<CartItemModel> cart = [];
// Shipping
ShippingDetails? shippingDetails;
// Coupon
String? couponCode;
// Status
bool loading = false;
String? error;
String? paymentId;
/// Initialize checkout for an event.
Future<void> initForEvent(int eventId, String eventName) async {
this.eventId = eventId;
this.eventName = eventName;
currentStep = CheckoutStep.tickets;
cart = [];
shippingDetails = null;
couponCode = null;
paymentId = null;
error = null;
loading = true;
notifyListeners();
try {
availableTickets = await _service.getTicketMeta(eventId);
} catch (e) {
error = userFriendlyError(e);
} finally {
loading = false;
notifyListeners();
}
}
/// Add or update cart item.
void setTicketQuantity(TicketMetaModel ticket, int qty) {
cart.removeWhere((c) => c.ticket.id == ticket.id);
if (qty > 0) {
cart.add(CartItemModel(ticket: ticket, quantity: qty));
}
notifyListeners();
}
double get subtotal => cart.fold(0, (sum, item) => sum + item.subtotal);
double get total => subtotal; // expand with discount/tax later
bool get hasItems => cart.isNotEmpty;
/// Move to next step.
void nextStep() {
if (currentStep == CheckoutStep.tickets && hasItems) {
currentStep = CheckoutStep.details;
} else if (currentStep == CheckoutStep.details && shippingDetails != null) {
currentStep = CheckoutStep.payment;
}
notifyListeners();
}
/// Move to previous step.
void previousStep() {
if (currentStep == CheckoutStep.payment) {
currentStep = CheckoutStep.details;
} else if (currentStep == CheckoutStep.details) {
currentStep = CheckoutStep.tickets;
}
notifyListeners();
}
/// Set shipping details from form.
void setShipping(ShippingDetails details) {
shippingDetails = details;
notifyListeners();
}
/// Process checkout on backend.
Future<Map<String, dynamic>> processCheckout() async {
loading = true;
error = null;
notifyListeners();
try {
final tickets = cart.map((c) => {
'ticket_meta_id': c.ticket.id,
'quantity': c.quantity,
}).toList();
final res = await _service.processCheckout(
eventId: eventId!,
tickets: tickets,
shippingDetails: shippingDetails?.toJson() ?? {},
couponCode: couponCode,
);
return res;
} catch (e) {
error = userFriendlyError(e);
rethrow;
} finally {
loading = false;
notifyListeners();
}
}
/// Mark payment as complete.
void markPaymentSuccess(String id) {
paymentId = id;
currentStep = CheckoutStep.confirmation;
notifyListeners();
}
/// Reset checkout state.
void reset() {
eventId = null;
eventName = '';
currentStep = CheckoutStep.tickets;
availableTickets = [];
cart = [];
shippingDetails = null;
couponCode = null;
paymentId = null;
error = null;
loading = false;
notifyListeners();
}
}