import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:intl/intl.dart'; import '../../../core/models/marketplace.dart'; import '../providers/client_providers.dart'; class BookingScreen extends ConsumerStatefulWidget { final String vehicleId; final MarketplaceVehicle? vehicle; const BookingScreen({ super.key, required this.vehicleId, this.vehicle, }); @override ConsumerState createState() => _BookingScreenState(); } class _BookingScreenState extends ConsumerState { final _formKey = GlobalKey(); final _firstNameCtrl = TextEditingController(); final _lastNameCtrl = TextEditingController(); final _emailCtrl = TextEditingController(); final _phoneCtrl = TextEditingController(); final _notesCtrl = TextEditingController(); bool _loading = false; String? _error; @override void dispose() { _firstNameCtrl.dispose(); _lastNameCtrl.dispose(); _emailCtrl.dispose(); _phoneCtrl.dispose(); _notesCtrl.dispose(); super.dispose(); } Future _submit() async { if (!_formKey.currentState!.validate()) return; final params = ref.read(searchParamsProvider); if (!params.hasDateRange) { setState(() => _error = 'Please select dates before booking.'); return; } final vehicle = widget.vehicle; if (vehicle == null) { setState(() => _error = 'Vehicle information missing.'); return; } setState(() { _loading = true; _error = null; }); try { final reservationId = await ref.read(marketplaceServiceProvider).createReservation( vehicleId: vehicle.id, companySlug: vehicle.companySlug, firstName: _firstNameCtrl.text.trim(), lastName: _lastNameCtrl.text.trim(), email: _emailCtrl.text.trim(), phone: _phoneCtrl.text.trim().isEmpty ? null : _phoneCtrl.text.trim(), startDate: params.startDate!, endDate: params.endDate!, notes: _notesCtrl.text.trim().isEmpty ? null : _notesCtrl.text.trim(), ); if (mounted) _showSuccess(reservationId, vehicle, params); } catch (e) { setState(() => _error = 'Booking failed. Please check your details and try again.'); } finally { if (mounted) setState(() => _loading = false); } } void _showSuccess( String reservationId, MarketplaceVehicle v, SearchParams params) { final fmt = DateFormat('MMM d, yyyy'); final days = params.endDate!.difference(params.startDate!).inDays; final total = v.dailyRateCents * days / 100; showDialog( context: context, barrierDismissible: false, builder: (_) => AlertDialog( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), content: Column( mainAxisSize: MainAxisSize.min, children: [ const SizedBox(height: 8), Container( padding: const EdgeInsets.all(16), decoration: const BoxDecoration( color: Color(0xFFDEF7EC), shape: BoxShape.circle, ), child: const Icon(Icons.check, color: Color(0xFF057A55), size: 32), ), const SizedBox(height: 16), const Text('Booking Confirmed!', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold)), const SizedBox(height: 8), Text( v.displayName, style: const TextStyle( color: Color(0xFF6B7280), fontSize: 14), ), const SizedBox(height: 12), Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: const Color(0xFFF9FAFB), borderRadius: BorderRadius.circular(10), ), child: Column( children: [ _ConfirmRow( label: 'Dates', value: '${fmt.format(params.startDate!)} โ†’ ${fmt.format(params.endDate!)}'), const SizedBox(height: 6), _ConfirmRow( label: 'Duration', value: '$days days'), const SizedBox(height: 6), _ConfirmRow( label: 'Total', value: '\$${total.toStringAsFixed(2)}'), const SizedBox(height: 6), _ConfirmRow( label: 'Reference', value: reservationId.substring(0, 8).toUpperCase(), ), ], ), ), const SizedBox(height: 8), const Text( 'A confirmation has been sent\nto your email.', textAlign: TextAlign.center, style: TextStyle( fontSize: 12, color: Color(0xFF9CA3AF)), ), ], ), actions: [ SizedBox( width: double.infinity, child: ElevatedButton( onPressed: () { Navigator.pop(context); context.go('/client'); }, child: const Text('Back to Search'), ), ), ], ), ); } @override Widget build(BuildContext context) { final vehicle = widget.vehicle; final params = ref.watch(searchParamsProvider); final hasDates = params.hasDateRange; final days = hasDates ? params.endDate!.difference(params.startDate!).inDays : 0; final fmt = DateFormat('MMM d, yyyy'); final total = vehicle != null && hasDates ? vehicle.dailyRateCents * days / 100 : null; return Scaffold( appBar: AppBar(title: const Text('Complete Booking')), body: Form( key: _formKey, child: ListView( padding: const EdgeInsets.all(16), children: [ // Vehicle summary if (vehicle != null) Card( margin: const EdgeInsets.only(bottom: 16), child: Padding( padding: const EdgeInsets.all(14), child: Row( children: [ const Icon(Icons.directions_car, color: Color(0xFF1A56DB), size: 28), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(vehicle.displayName, style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 15)), Text(vehicle.company.brand.displayName, style: const TextStyle( color: Color(0xFF6B7280), fontSize: 12)), ], ), ), if (total != null) Text( '\$${total.toStringAsFixed(0)}', style: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: Color(0xFF1A56DB), ), ), ], ), ), ), // Date summary if (hasDates) Container( margin: const EdgeInsets.only(bottom: 16), padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: const Color(0xFFEBF5FF), borderRadius: BorderRadius.circular(10), border: Border.all(color: const Color(0xFFBFDBFE)), ), child: Row( children: [ const Icon(Icons.calendar_today, color: Color(0xFF1A56DB), size: 16), const SizedBox(width: 10), Text( '${fmt.format(params.startDate!)} โ†’ ${fmt.format(params.endDate!)} ยท $days day${days == 1 ? '' : 's'}', style: const TextStyle( color: Color(0xFF1A56DB), fontWeight: FontWeight.w600, fontSize: 13, ), ), ], ), ) else Container( margin: const EdgeInsets.only(bottom: 16), padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: const Color(0xFFFDF6B2), borderRadius: BorderRadius.circular(10), ), child: const Row( children: [ Icon(Icons.warning_amber, color: Color(0xFFB45309), size: 16), SizedBox(width: 8), Text( 'No dates selected โ€” go back and pick dates', style: TextStyle( color: Color(0xFF92400E), fontSize: 13), ), ], ), ), if (_error != null) ...[ Container( padding: const EdgeInsets.all(12), margin: const EdgeInsets.only(bottom: 16), decoration: BoxDecoration( color: const Color(0xFFFDE8E8), borderRadius: BorderRadius.circular(10), ), child: Text(_error!, style: const TextStyle(color: Color(0xFF9B1C1C))), ), ], // Personal info const _SectionLabel('Your Information'), Row( children: [ Expanded( child: TextFormField( controller: _firstNameCtrl, textCapitalization: TextCapitalization.words, textInputAction: TextInputAction.next, decoration: const InputDecoration(labelText: 'First Name'), validator: (v) => v == null || v.trim().isEmpty ? 'Required' : null, ), ), const SizedBox(width: 12), Expanded( child: TextFormField( controller: _lastNameCtrl, textCapitalization: TextCapitalization.words, textInputAction: TextInputAction.next, decoration: const InputDecoration(labelText: 'Last Name'), validator: (v) => v == null || v.trim().isEmpty ? 'Required' : null, ), ), ], ), const SizedBox(height: 14), TextFormField( controller: _emailCtrl, keyboardType: TextInputType.emailAddress, textInputAction: TextInputAction.next, decoration: const InputDecoration( labelText: 'Email', prefixIcon: Icon(Icons.email_outlined), ), validator: (v) => (v == null || !v.contains('@')) ? 'Enter a valid email' : null, ), const SizedBox(height: 14), TextFormField( controller: _phoneCtrl, keyboardType: TextInputType.phone, textInputAction: TextInputAction.next, decoration: const InputDecoration( labelText: 'Phone (optional)', prefixIcon: Icon(Icons.phone_outlined), ), ), const SizedBox(height: 14), TextFormField( controller: _notesCtrl, maxLines: 2, textInputAction: TextInputAction.done, decoration: const InputDecoration( labelText: 'Notes (optional)', prefixIcon: Icon(Icons.notes_outlined), alignLabelWithHint: true, ), ), const SizedBox(height: 28), ElevatedButton( onPressed: (_loading || !hasDates) ? null : _submit, style: ElevatedButton.styleFrom( minimumSize: const Size.fromHeight(52)), child: _loading ? const SizedBox( height: 22, width: 22, child: CircularProgressIndicator( strokeWidth: 2, valueColor: AlwaysStoppedAnimation(Colors.white)), ) : const Text('Confirm Booking', style: TextStyle(fontSize: 16)), ), const SizedBox(height: 24), ], ), ), ); } } class _SectionLabel extends StatelessWidget { final String text; const _SectionLabel(this.text); @override Widget build(BuildContext context) => Padding( padding: const EdgeInsets.only(bottom: 12), child: Text(text, style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 15, color: Color(0xFF374151))), ); } class _ConfirmRow extends StatelessWidget { final String label; final String value; const _ConfirmRow({required this.label, required this.value}); @override Widget build(BuildContext context) => Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(label, style: const TextStyle( fontSize: 13, color: Color(0xFF6B7280))), Text(value, style: const TextStyle( fontSize: 13, fontWeight: FontWeight.w600)), ], ); }