111 lines
4.0 KiB
Dart
111 lines
4.0 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import '../../../core/theme/app_colors.dart';
|
|
import '../../../core/theme/app_dimens.dart';
|
|
import '../../../core/utils/extensions.dart';
|
|
import '../../../core/utils/formatters.dart';
|
|
import '../../../core/widgets/status_pill.dart';
|
|
import '../../customer/widgets/customer_capture_sheet.dart';
|
|
import '../providers/cart_controller.dart';
|
|
|
|
/// Strip above the product grid showing who the sale belongs to.
|
|
class CustomerBar extends ConsumerWidget {
|
|
const CustomerBar({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context, WidgetRef ref) {
|
|
final customer = ref.watch(
|
|
cartControllerProvider.select((cart) => cart.customer),
|
|
);
|
|
|
|
return Container(
|
|
// A hard height clipped the subtitle once it wrapped. Minimum height
|
|
// keeps the strip its usual size but lets it grow if it must.
|
|
constraints: const BoxConstraints(
|
|
minHeight: AppSizes.customerBarHeight,
|
|
),
|
|
color: AppColors.surface,
|
|
padding: const EdgeInsets.symmetric(
|
|
horizontal: AppSpacing.xl,
|
|
vertical: AppSpacing.sm,
|
|
),
|
|
child: Row(children: [
|
|
CircleAvatar(
|
|
radius: 20,
|
|
backgroundColor: customer == null
|
|
? AppColors.border
|
|
: AppColors.primarySurface,
|
|
child: customer == null
|
|
? const Icon(Icons.directions_walk_rounded,
|
|
size: 20, color: AppColors.textSecondary)
|
|
: Text(
|
|
Formatters.initials(customer.name),
|
|
style: const TextStyle(
|
|
color: AppColors.primary,
|
|
fontSize: 14,
|
|
fontWeight: FontWeight.w700,
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(width: AppSpacing.md),
|
|
Flexible(
|
|
child: Column(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Row(mainAxisSize: MainAxisSize.min, children: [
|
|
Flexible(
|
|
child: Text(
|
|
customer?.name ?? 'Walk-in Customer',
|
|
style: context.text.titleMedium,
|
|
overflow: TextOverflow.ellipsis,
|
|
),
|
|
),
|
|
if (customer != null) ...[
|
|
const SizedBox(width: AppSpacing.sm),
|
|
StatusPill.tier(customer.tier, dense: true),
|
|
],
|
|
]),
|
|
if (customer != null)
|
|
Text(
|
|
'${Formatters.mobile(customer.mobile)} · '
|
|
'${customer.loyaltyPoints} pts',
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
style: context.text.bodySmall,
|
|
)
|
|
else
|
|
Text(
|
|
'No loyalty tracking for this sale',
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
style: context.text.bodySmall,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
const Spacer(),
|
|
if (customer != null)
|
|
TextButton.icon(
|
|
onPressed: () =>
|
|
ref.read(cartControllerProvider.notifier).attachCustomer(null),
|
|
icon: const Icon(Icons.person_off_outlined, size: 17),
|
|
label: const Text('Detach'),
|
|
style: TextButton.styleFrom(
|
|
foregroundColor: AppColors.textSecondary),
|
|
),
|
|
const SizedBox(width: AppSpacing.sm),
|
|
OutlinedButton.icon(
|
|
onPressed: () => showCustomerCaptureSheet(context),
|
|
icon: const Icon(Icons.sync_alt_rounded, size: 17),
|
|
label: Text(customer == null ? 'Add Customer' : 'Change'),
|
|
style: OutlinedButton.styleFrom(
|
|
minimumSize: const Size(0, 44),
|
|
padding: const EdgeInsets.symmetric(horizontal: AppSpacing.lg),
|
|
),
|
|
),
|
|
]),
|
|
);
|
|
}
|
|
}
|