283 lines
8.9 KiB
Dart
283 lines
8.9 KiB
Dart
/// Addresses Page
|
|
///
|
|
/// Displays list of saved addresses with management options.
|
|
/// Features:
|
|
/// - List of saved addresses
|
|
/// - Default address indicator
|
|
/// - Edit/delete actions
|
|
/// - Set as default functionality
|
|
/// - Add new address
|
|
library;
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
|
import 'package:go_router/go_router.dart';
|
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|
import 'package:worker/core/constants/ui_constants.dart';
|
|
import 'package:worker/core/theme/colors.dart';
|
|
import 'package:worker/features/account/presentation/widgets/address_card.dart';
|
|
|
|
/// Addresses Page
|
|
///
|
|
/// Page for managing saved delivery addresses.
|
|
class AddressesPage extends HookConsumerWidget {
|
|
const AddressesPage({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context, WidgetRef ref) {
|
|
// Mock addresses data
|
|
final addresses = useState<List<Map<String, dynamic>>>([
|
|
{
|
|
'id': '1',
|
|
'name': 'Hoàng Minh Hiệp',
|
|
'phone': '0347302911',
|
|
'address':
|
|
'123 Đường Võ Văn Ngân, Phường Linh Chiểu, Thành phố Thủ Đức, TP.HCM',
|
|
'isDefault': true,
|
|
},
|
|
{
|
|
'id': '2',
|
|
'name': 'Hoàng Minh Hiệp',
|
|
'phone': '0347302911',
|
|
'address': '456 Đường Nguyễn Thị Minh Khai, Quận 3, TP.HCM',
|
|
'isDefault': false,
|
|
},
|
|
{
|
|
'id': '3',
|
|
'name': 'Công ty TNHH ABC',
|
|
'phone': '0283445566',
|
|
'address': '789 Đường Lê Văn Sỹ, Quận Phú Nhuận, TP.HCM',
|
|
'isDefault': false,
|
|
},
|
|
]);
|
|
|
|
return Scaffold(
|
|
backgroundColor: const Color(0xFFF4F6F8),
|
|
appBar: AppBar(
|
|
backgroundColor: Colors.white,
|
|
elevation: 0,
|
|
leading: IconButton(
|
|
icon: const Icon(Icons.arrow_back, color: Colors.black),
|
|
onPressed: () => context.pop(),
|
|
),
|
|
title: const Text(
|
|
'Địa chỉ đã lưu',
|
|
style: TextStyle(
|
|
color: Colors.black,
|
|
fontSize: 18,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
centerTitle: false,
|
|
actions: [
|
|
IconButton(
|
|
icon: const Icon(Icons.add, color: Colors.black),
|
|
onPressed: () {
|
|
_showAddAddress(context);
|
|
},
|
|
),
|
|
const SizedBox(width: AppSpacing.sm),
|
|
],
|
|
),
|
|
body: Column(
|
|
children: [
|
|
// Address List
|
|
Expanded(
|
|
child: addresses.value.isEmpty
|
|
? _buildEmptyState(context)
|
|
: ListView.separated(
|
|
padding: const EdgeInsets.all(AppSpacing.md),
|
|
itemCount: addresses.value.length,
|
|
separatorBuilder: (context, index) =>
|
|
const SizedBox(height: AppSpacing.md),
|
|
itemBuilder: (context, index) {
|
|
final address = addresses.value[index];
|
|
return AddressCard(
|
|
name: address['name'] as String,
|
|
phone: address['phone'] as String,
|
|
address: address['address'] as String,
|
|
isDefault: address['isDefault'] as bool,
|
|
onEdit: () {
|
|
_showEditAddress(context, address);
|
|
},
|
|
onDelete: () {
|
|
_showDeleteConfirmation(context, addresses, index);
|
|
},
|
|
onSetDefault: () {
|
|
_setDefaultAddress(addresses, index);
|
|
},
|
|
);
|
|
},
|
|
),
|
|
),
|
|
|
|
// Add New Address Button
|
|
Padding(
|
|
padding: const EdgeInsets.all(AppSpacing.md),
|
|
child: SizedBox(
|
|
width: double.infinity,
|
|
child: ElevatedButton.icon(
|
|
onPressed: () {
|
|
_showAddAddress(context);
|
|
},
|
|
icon: const Icon(Icons.add, size: 20),
|
|
label: const Text(
|
|
'Thêm địa chỉ mới',
|
|
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600),
|
|
),
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: AppColors.primaryBlue,
|
|
foregroundColor: Colors.white,
|
|
padding: const EdgeInsets.symmetric(vertical: 14),
|
|
elevation: 0,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(AppRadius.button),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
/// Build empty state
|
|
Widget _buildEmptyState(BuildContext context) {
|
|
return Center(
|
|
child: Column(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
Icon(
|
|
Icons.location_off,
|
|
size: 64,
|
|
color: AppColors.grey500.withValues(alpha: 0.5),
|
|
),
|
|
const SizedBox(height: 16),
|
|
const Text(
|
|
'Chưa có địa chỉ nào',
|
|
style: TextStyle(
|
|
fontSize: 16,
|
|
fontWeight: FontWeight.w600,
|
|
color: AppColors.grey500,
|
|
),
|
|
),
|
|
const SizedBox(height: 8),
|
|
const Text(
|
|
'Thêm địa chỉ để nhận hàng nhanh hơn',
|
|
style: TextStyle(fontSize: 14, color: AppColors.grey500),
|
|
),
|
|
const SizedBox(height: 24),
|
|
ElevatedButton.icon(
|
|
onPressed: () {
|
|
_showAddAddress(context);
|
|
},
|
|
icon: const Icon(Icons.add, size: 20),
|
|
label: const Text(
|
|
'Thêm địa chỉ mới',
|
|
style: TextStyle(fontSize: 14, fontWeight: FontWeight.w600),
|
|
),
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: AppColors.primaryBlue,
|
|
foregroundColor: Colors.white,
|
|
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
|
|
elevation: 0,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(AppRadius.button),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
/// Set address as default
|
|
void _setDefaultAddress(
|
|
ValueNotifier<List<Map<String, dynamic>>> addresses,
|
|
int index,
|
|
) {
|
|
final updatedAddresses = addresses.value.map((address) {
|
|
return {...address, 'isDefault': false};
|
|
}).toList();
|
|
|
|
updatedAddresses[index]['isDefault'] = true;
|
|
addresses.value = updatedAddresses;
|
|
}
|
|
|
|
/// Show add address dialog (TODO: implement form page)
|
|
void _showAddAddress(BuildContext context) {
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
const SnackBar(
|
|
content: Text('Chức năng thêm địa chỉ mới sẽ được phát triển'),
|
|
duration: Duration(seconds: 2),
|
|
),
|
|
);
|
|
}
|
|
|
|
/// Show edit address dialog (TODO: implement form page)
|
|
void _showEditAddress(BuildContext context, Map<String, dynamic> address) {
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
SnackBar(
|
|
content: Text('Chỉnh sửa địa chỉ: ${address['name']}'),
|
|
duration: const Duration(seconds: 2),
|
|
),
|
|
);
|
|
}
|
|
|
|
/// Show delete confirmation dialog
|
|
void _showDeleteConfirmation(
|
|
BuildContext context,
|
|
ValueNotifier<List<Map<String, dynamic>>> addresses,
|
|
int index,
|
|
) {
|
|
showDialog<void>(
|
|
context: context,
|
|
builder: (context) => AlertDialog(
|
|
title: const Text('Xóa địa chỉ'),
|
|
content: const Text('Bạn có chắc chắn muốn xóa địa chỉ này?'),
|
|
actions: [
|
|
TextButton(
|
|
onPressed: () => Navigator.pop(context),
|
|
child: const Text('Hủy'),
|
|
),
|
|
TextButton(
|
|
onPressed: () {
|
|
Navigator.pop(context);
|
|
_deleteAddress(context, addresses, index);
|
|
},
|
|
style: TextButton.styleFrom(foregroundColor: AppColors.danger),
|
|
child: const Text('Xóa'),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
/// Delete address
|
|
void _deleteAddress(
|
|
BuildContext context,
|
|
ValueNotifier<List<Map<String, dynamic>>> addresses,
|
|
int index,
|
|
) {
|
|
final deletedAddress = addresses.value[index];
|
|
final updatedAddresses = List<Map<String, dynamic>>.from(addresses.value);
|
|
updatedAddresses.removeAt(index);
|
|
|
|
// If deleted address was default and there are other addresses,
|
|
// set the first one as default
|
|
if (deletedAddress['isDefault'] == true && updatedAddresses.isNotEmpty) {
|
|
updatedAddresses[0]['isDefault'] = true;
|
|
}
|
|
|
|
addresses.value = updatedAddresses;
|
|
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
const SnackBar(
|
|
content: Text('Đã xóa địa chỉ'),
|
|
duration: Duration(seconds: 2),
|
|
),
|
|
);
|
|
}
|
|
}
|