import 'package:flutter/material.dart'; import '../services/api.dart'; class AddressListScreen extends StatefulWidget { const AddressListScreen({super.key}); @override State createState() => _AddressListScreenState(); } class _AddressListScreenState extends State { List _addresses = []; bool _isLoading = true; String? _error; @override void initState() { super.initState(); _loadAddresses(); } Future _loadAddresses() async { setState(() { _isLoading = true; _error = null; }); try { final addresses = await Api.getDeliveryAddresses(); if (mounted) { setState(() { _addresses = addresses; _isLoading = false; }); } } catch (e) { debugPrint('Error loading addresses: $e'); if (mounted) { setState(() { _error = e.toString(); _isLoading = false; }); } } } Future _deleteAddress(DeliveryAddress address) async { final confirm = await showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Delete Address'), content: Text('Are you sure you want to delete "${address.label}"?'), actions: [ TextButton( onPressed: () => Navigator.pop(context, false), child: const Text('Cancel'), ), TextButton( onPressed: () => Navigator.pop(context, true), child: const Text('Delete'), ), ], ), ); if (confirm != true) return; try { await Api.deleteDeliveryAddress(address.addressId); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: const Text('Address deleted', style: TextStyle(color: Colors.black)), backgroundColor: const Color(0xFF90EE90), behavior: SnackBarBehavior.floating, margin: const EdgeInsets.only(bottom: 80, left: 16, right: 16), ), ); _loadAddresses(); } } catch (e) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Failed to delete: $e', style: const TextStyle(color: Colors.black)), backgroundColor: const Color(0xFF90EE90), behavior: SnackBarBehavior.floating, margin: const EdgeInsets.only(bottom: 80, left: 16, right: 16), ), ); } } } Future _setDefaultAddress(DeliveryAddress address) async { try { await Api.setDefaultDeliveryAddress(address.addressId); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('"${address.label}" set as default', style: const TextStyle(color: Colors.black)), backgroundColor: const Color(0xFF90EE90), behavior: SnackBarBehavior.floating, margin: const EdgeInsets.only(bottom: 80, left: 16, right: 16), ), ); _loadAddresses(); } } catch (e) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Failed to set default: $e', style: const TextStyle(color: Colors.black)), backgroundColor: const Color(0xFF90EE90), behavior: SnackBarBehavior.floating, margin: const EdgeInsets.only(bottom: 80, left: 16, right: 16), ), ); } } } void _navigateToAddAddress() async { final result = await Navigator.pushNamed(context, '/address-edit'); if (result == true && mounted) { _loadAddresses(); } } void _navigateToEditAddress(DeliveryAddress address) async { final result = await Navigator.pushNamed( context, '/address-edit', arguments: address, ); if (result == true && mounted) { _loadAddresses(); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Delivery Addresses'), actions: [ IconButton( icon: const Icon(Icons.add), onPressed: _navigateToAddAddress, tooltip: 'Add Address', ), ], ), body: _buildBody(), ); } Widget _buildBody() { if (_isLoading) { return const Center(child: CircularProgressIndicator()); } if (_error != null) { return Center( child: Padding( padding: const EdgeInsets.all(24), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.error_outline, size: 48, color: Theme.of(context).colorScheme.error, ), const SizedBox(height: 16), Text( 'Failed to load addresses', style: Theme.of(context).textTheme.titleMedium, ), const SizedBox(height: 8), Text( _error!, textAlign: TextAlign.center, style: Theme.of(context).textTheme.bodySmall, ), const SizedBox(height: 24), FilledButton.icon( onPressed: _loadAddresses, icon: const Icon(Icons.refresh), label: const Text('Retry'), ), ], ), ), ); } if (_addresses.isEmpty) { return Center( child: Padding( padding: const EdgeInsets.all(24), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.location_off_outlined, size: 64, color: Theme.of(context).colorScheme.onSurfaceVariant, ), const SizedBox(height: 16), Text( 'No addresses yet', style: Theme.of(context).textTheme.titleMedium, ), const SizedBox(height: 8), Text( 'Add a delivery address to get started', style: Theme.of(context).textTheme.bodySmall?.copyWith( color: Theme.of(context).colorScheme.onSurfaceVariant, ), ), const SizedBox(height: 24), FilledButton.icon( onPressed: _navigateToAddAddress, icon: const Icon(Icons.add), label: const Text('Add Address'), ), ], ), ), ); } return RefreshIndicator( onRefresh: _loadAddresses, child: ListView.builder( padding: const EdgeInsets.symmetric(vertical: 8), itemCount: _addresses.length, itemBuilder: (context, index) { final address = _addresses[index]; return _AddressCard( address: address, onTap: () => _navigateToEditAddress(address), onDelete: () => _deleteAddress(address), onSetDefault: address.isDefault ? null : () => _setDefaultAddress(address), ); }, ), ); } } class _AddressCard extends StatelessWidget { final DeliveryAddress address; final VoidCallback onTap; final VoidCallback onDelete; final VoidCallback? onSetDefault; const _AddressCard({ required this.address, required this.onTap, required this.onDelete, this.onSetDefault, }); @override Widget build(BuildContext context) { return Card( margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 6), child: InkWell( onTap: onTap, borderRadius: BorderRadius.circular(12), child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon( _getLabelIcon(address.label), size: 20, color: Theme.of(context).colorScheme.primary, ), const SizedBox(width: 8), Expanded( child: Text( address.label, style: Theme.of(context).textTheme.titleMedium?.copyWith( fontWeight: FontWeight.w600, ), ), ), if (address.isDefault) Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), decoration: BoxDecoration( color: Theme.of(context).colorScheme.primaryContainer, borderRadius: BorderRadius.circular(12), ), child: Text( 'Default', style: TextStyle( fontSize: 12, color: Theme.of(context).colorScheme.onPrimaryContainer, ), ), ), ], ), const SizedBox(height: 8), Text( address.line1, style: Theme.of(context).textTheme.bodyMedium, ), if (address.line2.isNotEmpty) Text( address.line2, style: Theme.of(context).textTheme.bodyMedium, ), Text( '${address.city}, ${address.stateAbbr} ${address.zipCode}', style: Theme.of(context).textTheme.bodyMedium?.copyWith( color: Theme.of(context).colorScheme.onSurfaceVariant, ), ), const SizedBox(height: 12), Row( mainAxisAlignment: MainAxisAlignment.end, children: [ if (onSetDefault != null) TextButton( onPressed: onSetDefault, child: const Text('Set as Default'), ), const SizedBox(width: 8), IconButton( icon: Icon( Icons.delete_outline, color: Theme.of(context).colorScheme.error, ), onPressed: onDelete, tooltip: 'Delete', ), ], ), ], ), ), ), ); } IconData _getLabelIcon(String label) { final lower = label.toLowerCase(); if (lower.contains('home')) return Icons.home; if (lower.contains('work') || lower.contains('office')) return Icons.business; return Icons.location_on; } }