import 'package:flutter/material.dart'; import '../../../../common/extension/extension.dart'; import '../../../../common/theme/theme.dart'; import '../../../../domain/wallet/wallet.dart'; import '../../wallet/wallet_ui.dart'; import '../reward_ui.dart'; /// Detail voucher milik customer. Untuk memakai voucher, customer /// menunjukkan layar ini ke kasir; POS belum bisa menandai voucher terpakai. class RedemptionDetailSheet extends StatelessWidget { const RedemptionDetailSheet({super.key, required this.redemption}); final VoucherRedemption redemption; static Future show(BuildContext context, VoucherRedemption redemption) { return showModalBottomSheet( context: context, isScrollControlled: true, backgroundColor: AppColor.white, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(20)), ), builder: (_) => RedemptionDetailSheet(redemption: redemption), ); } @override Widget build(BuildContext context) { final faceValue = voucherFaceValueLabel( redemption.voucherType, redemption.faceValue, ); return ConstrainedBox( constraints: BoxConstraints( maxHeight: MediaQuery.sizeOf(context).height * 0.85, ), child: SafeArea( top: false, child: SingleChildScrollView( padding: const EdgeInsets.fromLTRB(20, 12, 20, 20), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Center( child: Container( width: 40, height: 4, decoration: BoxDecoration( color: AppColor.border, borderRadius: BorderRadius.circular(2), ), ), ), const SizedBox(height: 20), _buildHeader(), const SizedBox(height: 20), _buildStatusContent(), const SizedBox(height: 20), if (redemption.createdAt != null) _InfoRow( label: 'Ditukar pada', value: formatWibDateTime(redemption.createdAt!), ), if (redemption.status == VoucherRedemptionStatus.completed && redemption.codeExpiresAt != null) _InfoRow( label: 'Berlaku sampai', value: formatWibDateTime(redemption.codeExpiresAt!), ), _InfoRow( label: 'EnakPoint ditukar', value: redemption.pointCost.thousandFormat, ), if (faceValue != null) _InfoRow(label: 'Nilai voucher', value: faceValue), ], ), ), ), ); } Widget _buildHeader() { final status = redemption.status; return Row( children: [ Container( width: 56, height: 56, alignment: Alignment.center, decoration: BoxDecoration( color: AppColor.primary.withOpacity(0.06), borderRadius: BorderRadius.circular(14), ), child: VoucherImage(url: redemption.voucherImageUrl, size: 40), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( voucherTypeLabel( redemption.voucherType, redemption.faceValue, ).toUpperCase(), style: AppStyle.xs.copyWith( color: AppColor.textSecondary, fontWeight: FontWeight.w700, letterSpacing: 0.6, ), ), const SizedBox(height: 2), Text( redemption.voucherName, style: AppStyle.xl.copyWith(fontWeight: FontWeight.w700), ), ], ), ), if (status != VoucherRedemptionStatus.unknown) ...[ const SizedBox(width: 8), VoucherRedemptionStatusBadge(status: status), ], ], ); } Widget _buildStatusContent() { switch (redemption.status) { case VoucherRedemptionStatus.completed: return redemption.code == null ? const VoucherNoCodeNote() : VoucherCodeBox(code: redemption.code!); case VoucherRedemptionStatus.pending: return const _Note( icon: Icons.hourglass_top_rounded, color: AppColor.warning, message: 'Voucher sedang diproses. EnakPoint sudah terpotong; cek lagi ' 'nanti.', ); case VoucherRedemptionStatus.failed: return const _Note( icon: Icons.undo_rounded, color: AppColor.error, message: 'Gagal, EnakPoint sudah dikembalikan.', ); case VoucherRedemptionStatus.unknown: return const SizedBox.shrink(); } } } class _Note extends StatelessWidget { const _Note({required this.icon, required this.color, required this.message}); final IconData icon; final Color color; final String message; @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.all(14), decoration: BoxDecoration( color: AppColor.background, borderRadius: BorderRadius.circular(AppValue.borderRadius), ), child: Row( children: [ Icon(icon, size: 20, color: color), const SizedBox(width: 10), Expanded( child: Text( message, style: AppStyle.sm.copyWith(color: AppColor.textSecondary), ), ), ], ), ); } } class _InfoRow extends StatelessWidget { const _InfoRow({required this.label, required this.value}); final String label; final String value; @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.symmetric(vertical: 6), child: Row( children: [ Text( label, style: AppStyle.sm.copyWith(color: AppColor.textSecondary), ), const Spacer(), Text(value, style: AppStyle.sm.copyWith(fontWeight: FontWeight.w600)), ], ), ); } }