From 0693411cf707a74c9f28d2d6aa6e2fb7e0caaaa2 Mon Sep 17 00:00:00 2001 From: efrilm Date: Tue, 28 Oct 2025 17:10:47 +0700 Subject: [PATCH] confirm order save --- .../dialog/custom_modal_dialog.dart | 3 + .../order/order_save_confirm_dialog.dart | 240 ++++++++++++++++++ .../dialog/order/order_save_dialog.dart | 9 + 3 files changed, 252 insertions(+) create mode 100644 lib/presentation/components/dialog/order/order_save_confirm_dialog.dart diff --git a/lib/presentation/components/dialog/custom_modal_dialog.dart b/lib/presentation/components/dialog/custom_modal_dialog.dart index d3af021..89d7f2f 100644 --- a/lib/presentation/components/dialog/custom_modal_dialog.dart +++ b/lib/presentation/components/dialog/custom_modal_dialog.dart @@ -4,6 +4,7 @@ class CustomModalDialog extends StatelessWidget { final String title; final String? subtitle; final Widget child; + final Widget? bottom; final VoidCallback? onClose; final double? minWidth; final double? maxWidth; @@ -22,6 +23,7 @@ class CustomModalDialog extends StatelessWidget { this.minHeight, this.maxHeight, this.contentPadding, + this.bottom, }); @override @@ -96,6 +98,7 @@ class CustomModalDialog extends StatelessWidget { child: child, ), ), + if (bottom != null) bottom!, ], ), ), diff --git a/lib/presentation/components/dialog/order/order_save_confirm_dialog.dart b/lib/presentation/components/dialog/order/order_save_confirm_dialog.dart new file mode 100644 index 0000000..62ed42d --- /dev/null +++ b/lib/presentation/components/dialog/order/order_save_confirm_dialog.dart @@ -0,0 +1,240 @@ +import 'package:auto_route/auto_route.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +import '../../../../application/checkout/checkout_form/checkout_form_bloc.dart'; +import '../../../../application/order/order_form/order_form_bloc.dart'; +import '../../../../common/extension/extension.dart'; +import '../../../../common/theme/theme.dart'; +import '../../../../common/types/order_type.dart'; +import '../../button/button.dart'; +import '../../spaces/space.dart'; +import '../dialog.dart'; + +class OrderSaveConfirmDialog extends StatelessWidget { + final CheckoutFormState checkoutState; + const OrderSaveConfirmDialog({super.key, required this.checkoutState}); + + @override + Widget build(BuildContext context) { + return BlocBuilder( + builder: (context, state) { + return CustomModalDialog( + title: 'Konfirmasi Pesanan', + subtitle: 'Tindakan ini tidak dapat dibatalkan', + contentPadding: const EdgeInsets.symmetric( + horizontal: 16.0, + vertical: 24.0, + ), + minWidth: context.deviceWidth * 0.5, + minHeight: context.deviceHeight * 0.8, + bottom: Container( + padding: EdgeInsets.all(16), + child: Row( + children: [ + Expanded( + child: AppElevatedButton.outlined( + onPressed: () => context.maybePop(), + label: 'Batalkan', + ), + ), + SpaceWidth(12), + Expanded( + child: AppElevatedButton.filled( + isLoading: state.isCreating, + onPressed: state.isCreating + ? null + : () { + context.read().add( + OrderFormEvent.createOrder( + items: checkoutState.items, + orderType: checkoutState.orderType, + table: checkoutState.table, + ), + ); + }, + label: 'Konfirmasi', + ), + ), + ], + ), + ), + child: Column( + children: [ + Container( + width: double.infinity, + padding: EdgeInsets.all(16), + decoration: BoxDecoration( + color: AppColor.textSecondary.withOpacity(0.05), + borderRadius: BorderRadius.circular(12), + border: Border.all(color: AppColor.border), + ), + child: Text( + message(state.customerName ?? '-'), + style: AppStyle.md.copyWith(fontSize: 14, height: 1.4), + ), + ), + if (checkoutState.items.isNotEmpty) ...[ + SpaceHeight(16), + Container( + width: double.infinity, + decoration: BoxDecoration( + color: AppColor.primaryWithOpacity(0.05), + borderRadius: BorderRadius.circular(12), + border: Border.all(color: AppColor.primaryWithOpacity(0.2)), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.all(16), + child: Row( + children: [ + Container( + padding: EdgeInsets.all(6), + decoration: BoxDecoration( + color: AppColor.primary, + borderRadius: BorderRadius.circular(6), + ), + child: Icon( + Icons.list_alt_rounded, + color: AppColor.white, + size: 16, + ), + ), + SizedBox(width: 8), + Text( + 'Item yang akan dipesan:', + style: AppStyle.md.copyWith( + fontWeight: FontWeight.bold, + color: AppColor.primary, + ), + ), + ], + ), + ), + Container( + constraints: BoxConstraints(maxHeight: 120), + child: Scrollbar( + child: SingleChildScrollView( + padding: EdgeInsets.only( + left: 16, + right: 16, + bottom: 16, + ), + child: Column( + children: checkoutState.items.map((item) { + return Container( + margin: EdgeInsets.only(bottom: 6), + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(6), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.03), + blurRadius: 2, + offset: Offset(0, 1), + ), + ], + ), + child: Row( + children: [ + Container( + width: 6, + height: 6, + decoration: BoxDecoration( + color: AppColor.primary, + shape: BoxShape.circle, + ), + ), + SizedBox(width: 8), + Expanded( + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text( + item.product.name, + style: AppStyle.md.copyWith( + fontWeight: FontWeight.w600, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + Text( + '${item.quantity} qty', + style: AppStyle.sm.copyWith( + color: AppColor.textSecondary, + ), + ), + ], + ), + ), + Container( + padding: EdgeInsets.symmetric( + horizontal: 6, + vertical: 2, + ), + decoration: BoxDecoration( + color: AppColor.primaryWithOpacity( + 0.1, + ), + borderRadius: BorderRadius.circular( + 4, + ), + ), + child: Text( + ((item.product.price) * item.quantity) + .currencyFormatRpV2, + style: AppStyle.md.copyWith( + fontWeight: FontWeight.bold, + color: AppColor.primary, + ), + ), + ), + ], + ), + ); + }).toList(), + ), + ), + ), + ), + ], + ), + ), + ], + ], + ), + ); + }, + ); + } + + String message(String customerName) { + switch (checkoutState.orderType) { + case OrderType.dineIn: + return 'Konfirmasi untuk menyimpan pesanan Dine-In\n\n' + 'Pesanan untuk ${customerName.isNotEmpty ? customerName : "Pelanggan"} akan disimpan ke dalam sistem. ' + 'Pelanggan dapat langsung menikmati pesanan di meja yang telah disediakan. ' + 'Pastikan semua item pesanan sudah sesuai sebelum menyimpan.'; + + case OrderType.delivery: + return 'Konfirmasi untuk menyimpan pesanan Delivery\n\n' + 'Pesanan delivery untuk ${customerName.isNotEmpty ? customerName : "Pelanggan"} akan disimpan. ' + '${checkoutState.delivery != null ? "Pengiriman: ${checkoutState.delivery?.name ?? "-"}. " : ""}' + 'Tim delivery akan segera mempersiapkan pesanan.'; + + case OrderType.takeAway: + return 'Konfirmasi untuk menyimpan pesanan Take Away\n\n' + 'Pesanan take away untuk ${customerName.isNotEmpty ? customerName : "Pelanggan"} akan disimpan. ' + 'Dapur akan mulai mempersiapkan pesanan dan pelanggan dapat mengambil pesanan sesuai estimasi waktu yang diberikan.'; + + case OrderType.freeTable: + return 'Konfirmasi untuk menyimpan pesanan Free Table\n\n' + 'Pesanan free table untuk ${customerName.isNotEmpty ? customerName : "Pelanggan"} akan disimpan. ' + 'Meja akan direservasi dan pesanan akan dipersiapkan sesuai dengan waktu kedatangan pelanggan.'; + } + } +} diff --git a/lib/presentation/components/dialog/order/order_save_dialog.dart b/lib/presentation/components/dialog/order/order_save_dialog.dart index a9cc49a..6bb4694 100644 --- a/lib/presentation/components/dialog/order/order_save_dialog.dart +++ b/lib/presentation/components/dialog/order/order_save_dialog.dart @@ -8,6 +8,7 @@ import '../../../../domain/table/table.dart'; import '../../spaces/space.dart'; import '../dialog.dart'; import 'order_pay_later_dialog.dart'; +import 'order_save_confirm_dialog.dart'; class OrderSaveDialog extends StatelessWidget { final CheckoutFormState checkoutState; @@ -43,6 +44,14 @@ class OrderSaveDialog extends StatelessWidget { builder: (context) => OrderPayLaterDialog(tables: tables), ); }); + } else { + Future.delayed(Duration(milliseconds: 100), () { + showDialog( + context: context, + builder: (context) => + OrderSaveConfirmDialog(checkoutState: checkoutState), + ); + }); } }, ),