148 lines
3.6 KiB
Dart
148 lines
3.6 KiB
Dart
|
|
// 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();
|
||
|
|
}
|
||
|
|
}
|