From b8eefcbac09d84db50e86d1b97b306c3e0f02e64 Mon Sep 17 00:00:00 2001 From: efrilm Date: Mon, 27 Oct 2025 15:27:21 +0700 Subject: [PATCH] checkout page --- .../order/order_form/order_form_bloc.dart | 34 + .../order_form/order_form_bloc.freezed.dart | 832 ++++++++++++++++++ .../order/order_form/order_form_event.dart | 11 + .../order/order_form/order_form_state.dart | 12 + lib/common/extension/string_extension.dart | 15 + lib/injection.config.dart | 3 + lib/presentation/app_widget.dart | 4 + .../components/page/page_title.dart | 2 +- .../pages/checkout/checkout_page.dart | 8 +- .../widgets/checkout_right_panel.dart | 388 ++++++-- lib/presentation/router/app_router.gr.dart | 2 +- 11 files changed, 1234 insertions(+), 77 deletions(-) create mode 100644 lib/application/order/order_form/order_form_bloc.dart create mode 100644 lib/application/order/order_form/order_form_bloc.freezed.dart create mode 100644 lib/application/order/order_form/order_form_event.dart create mode 100644 lib/application/order/order_form/order_form_state.dart diff --git a/lib/application/order/order_form/order_form_bloc.dart b/lib/application/order/order_form/order_form_bloc.dart new file mode 100644 index 0000000..a7bba80 --- /dev/null +++ b/lib/application/order/order_form/order_form_bloc.dart @@ -0,0 +1,34 @@ +import 'package:bloc/bloc.dart'; +import 'package:flutter/foundation.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:injectable/injectable.dart'; + +import '../../../domain/customer/customer.dart'; +import '../../../domain/payment_method/payment_method.dart'; +part 'order_form_event.dart'; +part 'order_form_state.dart'; +part 'order_form_bloc.freezed.dart'; + +@injectable +class OrderFormBloc extends Bloc { + OrderFormBloc() : super(OrderFormState.initial()) { + on(_onOrderFormBloc); + } + + Future _onOrderFormBloc( + OrderFormEvent event, + Emitter emit, + ) { + return event.map( + customerNameChanged: (e) async { + emit(state.copyWith(customerName: e.customerName)); + }, + paymentMethodChanged: (e) async { + emit(state.copyWith(paymentMethod: e.payment)); + }, + customerChanged: (e) async { + emit(state.copyWith(customer: e.customer)); + }, + ); + } +} diff --git a/lib/application/order/order_form/order_form_bloc.freezed.dart b/lib/application/order/order_form/order_form_bloc.freezed.dart new file mode 100644 index 0000000..2b6d63d --- /dev/null +++ b/lib/application/order/order_form/order_form_bloc.freezed.dart @@ -0,0 +1,832 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'order_form_bloc.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models', +); + +/// @nodoc +mixin _$OrderFormEvent { + @optionalTypeArgs + TResult when({ + required TResult Function(String customerName) customerNameChanged, + required TResult Function(PaymentMethod payment) paymentMethodChanged, + required TResult Function(Customer? customer) customerChanged, + }) => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function(String customerName)? customerNameChanged, + TResult? Function(PaymentMethod payment)? paymentMethodChanged, + TResult? Function(Customer? customer)? customerChanged, + }) => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(String customerName)? customerNameChanged, + TResult Function(PaymentMethod payment)? paymentMethodChanged, + TResult Function(Customer? customer)? customerChanged, + required TResult orElse(), + }) => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(_CustomerNameChanged value) customerNameChanged, + required TResult Function(_PaymentMethodChanged value) paymentMethodChanged, + required TResult Function(_CustomeChanged value) customerChanged, + }) => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_CustomerNameChanged value)? customerNameChanged, + TResult? Function(_PaymentMethodChanged value)? paymentMethodChanged, + TResult? Function(_CustomeChanged value)? customerChanged, + }) => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_CustomerNameChanged value)? customerNameChanged, + TResult Function(_PaymentMethodChanged value)? paymentMethodChanged, + TResult Function(_CustomeChanged value)? customerChanged, + required TResult orElse(), + }) => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $OrderFormEventCopyWith<$Res> { + factory $OrderFormEventCopyWith( + OrderFormEvent value, + $Res Function(OrderFormEvent) then, + ) = _$OrderFormEventCopyWithImpl<$Res, OrderFormEvent>; +} + +/// @nodoc +class _$OrderFormEventCopyWithImpl<$Res, $Val extends OrderFormEvent> + implements $OrderFormEventCopyWith<$Res> { + _$OrderFormEventCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of OrderFormEvent + /// with the given fields replaced by the non-null parameter values. +} + +/// @nodoc +abstract class _$$CustomerNameChangedImplCopyWith<$Res> { + factory _$$CustomerNameChangedImplCopyWith( + _$CustomerNameChangedImpl value, + $Res Function(_$CustomerNameChangedImpl) then, + ) = __$$CustomerNameChangedImplCopyWithImpl<$Res>; + @useResult + $Res call({String customerName}); +} + +/// @nodoc +class __$$CustomerNameChangedImplCopyWithImpl<$Res> + extends _$OrderFormEventCopyWithImpl<$Res, _$CustomerNameChangedImpl> + implements _$$CustomerNameChangedImplCopyWith<$Res> { + __$$CustomerNameChangedImplCopyWithImpl( + _$CustomerNameChangedImpl _value, + $Res Function(_$CustomerNameChangedImpl) _then, + ) : super(_value, _then); + + /// Create a copy of OrderFormEvent + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({Object? customerName = null}) { + return _then( + _$CustomerNameChangedImpl( + null == customerName + ? _value.customerName + : customerName // ignore: cast_nullable_to_non_nullable + as String, + ), + ); + } +} + +/// @nodoc + +class _$CustomerNameChangedImpl + with DiagnosticableTreeMixin + implements _CustomerNameChanged { + const _$CustomerNameChangedImpl(this.customerName); + + @override + final String customerName; + + @override + String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) { + return 'OrderFormEvent.customerNameChanged(customerName: $customerName)'; + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('type', 'OrderFormEvent.customerNameChanged')) + ..add(DiagnosticsProperty('customerName', customerName)); + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$CustomerNameChangedImpl && + (identical(other.customerName, customerName) || + other.customerName == customerName)); + } + + @override + int get hashCode => Object.hash(runtimeType, customerName); + + /// Create a copy of OrderFormEvent + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$CustomerNameChangedImplCopyWith<_$CustomerNameChangedImpl> get copyWith => + __$$CustomerNameChangedImplCopyWithImpl<_$CustomerNameChangedImpl>( + this, + _$identity, + ); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function(String customerName) customerNameChanged, + required TResult Function(PaymentMethod payment) paymentMethodChanged, + required TResult Function(Customer? customer) customerChanged, + }) { + return customerNameChanged(customerName); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function(String customerName)? customerNameChanged, + TResult? Function(PaymentMethod payment)? paymentMethodChanged, + TResult? Function(Customer? customer)? customerChanged, + }) { + return customerNameChanged?.call(customerName); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(String customerName)? customerNameChanged, + TResult Function(PaymentMethod payment)? paymentMethodChanged, + TResult Function(Customer? customer)? customerChanged, + required TResult orElse(), + }) { + if (customerNameChanged != null) { + return customerNameChanged(customerName); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_CustomerNameChanged value) customerNameChanged, + required TResult Function(_PaymentMethodChanged value) paymentMethodChanged, + required TResult Function(_CustomeChanged value) customerChanged, + }) { + return customerNameChanged(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_CustomerNameChanged value)? customerNameChanged, + TResult? Function(_PaymentMethodChanged value)? paymentMethodChanged, + TResult? Function(_CustomeChanged value)? customerChanged, + }) { + return customerNameChanged?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_CustomerNameChanged value)? customerNameChanged, + TResult Function(_PaymentMethodChanged value)? paymentMethodChanged, + TResult Function(_CustomeChanged value)? customerChanged, + required TResult orElse(), + }) { + if (customerNameChanged != null) { + return customerNameChanged(this); + } + return orElse(); + } +} + +abstract class _CustomerNameChanged implements OrderFormEvent { + const factory _CustomerNameChanged(final String customerName) = + _$CustomerNameChangedImpl; + + String get customerName; + + /// Create a copy of OrderFormEvent + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + _$$CustomerNameChangedImplCopyWith<_$CustomerNameChangedImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$PaymentMethodChangedImplCopyWith<$Res> { + factory _$$PaymentMethodChangedImplCopyWith( + _$PaymentMethodChangedImpl value, + $Res Function(_$PaymentMethodChangedImpl) then, + ) = __$$PaymentMethodChangedImplCopyWithImpl<$Res>; + @useResult + $Res call({PaymentMethod payment}); + + $PaymentMethodCopyWith<$Res> get payment; +} + +/// @nodoc +class __$$PaymentMethodChangedImplCopyWithImpl<$Res> + extends _$OrderFormEventCopyWithImpl<$Res, _$PaymentMethodChangedImpl> + implements _$$PaymentMethodChangedImplCopyWith<$Res> { + __$$PaymentMethodChangedImplCopyWithImpl( + _$PaymentMethodChangedImpl _value, + $Res Function(_$PaymentMethodChangedImpl) _then, + ) : super(_value, _then); + + /// Create a copy of OrderFormEvent + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({Object? payment = null}) { + return _then( + _$PaymentMethodChangedImpl( + null == payment + ? _value.payment + : payment // ignore: cast_nullable_to_non_nullable + as PaymentMethod, + ), + ); + } + + /// Create a copy of OrderFormEvent + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $PaymentMethodCopyWith<$Res> get payment { + return $PaymentMethodCopyWith<$Res>(_value.payment, (value) { + return _then(_value.copyWith(payment: value)); + }); + } +} + +/// @nodoc + +class _$PaymentMethodChangedImpl + with DiagnosticableTreeMixin + implements _PaymentMethodChanged { + const _$PaymentMethodChangedImpl(this.payment); + + @override + final PaymentMethod payment; + + @override + String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) { + return 'OrderFormEvent.paymentMethodChanged(payment: $payment)'; + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('type', 'OrderFormEvent.paymentMethodChanged')) + ..add(DiagnosticsProperty('payment', payment)); + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$PaymentMethodChangedImpl && + (identical(other.payment, payment) || other.payment == payment)); + } + + @override + int get hashCode => Object.hash(runtimeType, payment); + + /// Create a copy of OrderFormEvent + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$PaymentMethodChangedImplCopyWith<_$PaymentMethodChangedImpl> + get copyWith => + __$$PaymentMethodChangedImplCopyWithImpl<_$PaymentMethodChangedImpl>( + this, + _$identity, + ); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function(String customerName) customerNameChanged, + required TResult Function(PaymentMethod payment) paymentMethodChanged, + required TResult Function(Customer? customer) customerChanged, + }) { + return paymentMethodChanged(payment); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function(String customerName)? customerNameChanged, + TResult? Function(PaymentMethod payment)? paymentMethodChanged, + TResult? Function(Customer? customer)? customerChanged, + }) { + return paymentMethodChanged?.call(payment); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(String customerName)? customerNameChanged, + TResult Function(PaymentMethod payment)? paymentMethodChanged, + TResult Function(Customer? customer)? customerChanged, + required TResult orElse(), + }) { + if (paymentMethodChanged != null) { + return paymentMethodChanged(payment); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_CustomerNameChanged value) customerNameChanged, + required TResult Function(_PaymentMethodChanged value) paymentMethodChanged, + required TResult Function(_CustomeChanged value) customerChanged, + }) { + return paymentMethodChanged(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_CustomerNameChanged value)? customerNameChanged, + TResult? Function(_PaymentMethodChanged value)? paymentMethodChanged, + TResult? Function(_CustomeChanged value)? customerChanged, + }) { + return paymentMethodChanged?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_CustomerNameChanged value)? customerNameChanged, + TResult Function(_PaymentMethodChanged value)? paymentMethodChanged, + TResult Function(_CustomeChanged value)? customerChanged, + required TResult orElse(), + }) { + if (paymentMethodChanged != null) { + return paymentMethodChanged(this); + } + return orElse(); + } +} + +abstract class _PaymentMethodChanged implements OrderFormEvent { + const factory _PaymentMethodChanged(final PaymentMethod payment) = + _$PaymentMethodChangedImpl; + + PaymentMethod get payment; + + /// Create a copy of OrderFormEvent + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + _$$PaymentMethodChangedImplCopyWith<_$PaymentMethodChangedImpl> + get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$CustomeChangedImplCopyWith<$Res> { + factory _$$CustomeChangedImplCopyWith( + _$CustomeChangedImpl value, + $Res Function(_$CustomeChangedImpl) then, + ) = __$$CustomeChangedImplCopyWithImpl<$Res>; + @useResult + $Res call({Customer? customer}); + + $CustomerCopyWith<$Res>? get customer; +} + +/// @nodoc +class __$$CustomeChangedImplCopyWithImpl<$Res> + extends _$OrderFormEventCopyWithImpl<$Res, _$CustomeChangedImpl> + implements _$$CustomeChangedImplCopyWith<$Res> { + __$$CustomeChangedImplCopyWithImpl( + _$CustomeChangedImpl _value, + $Res Function(_$CustomeChangedImpl) _then, + ) : super(_value, _then); + + /// Create a copy of OrderFormEvent + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({Object? customer = freezed}) { + return _then( + _$CustomeChangedImpl( + freezed == customer + ? _value.customer + : customer // ignore: cast_nullable_to_non_nullable + as Customer?, + ), + ); + } + + /// Create a copy of OrderFormEvent + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $CustomerCopyWith<$Res>? get customer { + if (_value.customer == null) { + return null; + } + + return $CustomerCopyWith<$Res>(_value.customer!, (value) { + return _then(_value.copyWith(customer: value)); + }); + } +} + +/// @nodoc + +class _$CustomeChangedImpl + with DiagnosticableTreeMixin + implements _CustomeChanged { + const _$CustomeChangedImpl(this.customer); + + @override + final Customer? customer; + + @override + String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) { + return 'OrderFormEvent.customerChanged(customer: $customer)'; + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('type', 'OrderFormEvent.customerChanged')) + ..add(DiagnosticsProperty('customer', customer)); + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$CustomeChangedImpl && + (identical(other.customer, customer) || + other.customer == customer)); + } + + @override + int get hashCode => Object.hash(runtimeType, customer); + + /// Create a copy of OrderFormEvent + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$CustomeChangedImplCopyWith<_$CustomeChangedImpl> get copyWith => + __$$CustomeChangedImplCopyWithImpl<_$CustomeChangedImpl>( + this, + _$identity, + ); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function(String customerName) customerNameChanged, + required TResult Function(PaymentMethod payment) paymentMethodChanged, + required TResult Function(Customer? customer) customerChanged, + }) { + return customerChanged(customer); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function(String customerName)? customerNameChanged, + TResult? Function(PaymentMethod payment)? paymentMethodChanged, + TResult? Function(Customer? customer)? customerChanged, + }) { + return customerChanged?.call(customer); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(String customerName)? customerNameChanged, + TResult Function(PaymentMethod payment)? paymentMethodChanged, + TResult Function(Customer? customer)? customerChanged, + required TResult orElse(), + }) { + if (customerChanged != null) { + return customerChanged(customer); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_CustomerNameChanged value) customerNameChanged, + required TResult Function(_PaymentMethodChanged value) paymentMethodChanged, + required TResult Function(_CustomeChanged value) customerChanged, + }) { + return customerChanged(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_CustomerNameChanged value)? customerNameChanged, + TResult? Function(_PaymentMethodChanged value)? paymentMethodChanged, + TResult? Function(_CustomeChanged value)? customerChanged, + }) { + return customerChanged?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_CustomerNameChanged value)? customerNameChanged, + TResult Function(_PaymentMethodChanged value)? paymentMethodChanged, + TResult Function(_CustomeChanged value)? customerChanged, + required TResult orElse(), + }) { + if (customerChanged != null) { + return customerChanged(this); + } + return orElse(); + } +} + +abstract class _CustomeChanged implements OrderFormEvent { + const factory _CustomeChanged(final Customer? customer) = + _$CustomeChangedImpl; + + Customer? get customer; + + /// Create a copy of OrderFormEvent + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + _$$CustomeChangedImplCopyWith<_$CustomeChangedImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +mixin _$OrderFormState { + PaymentMethod? get paymentMethod => throw _privateConstructorUsedError; + String? get customerName => throw _privateConstructorUsedError; + Customer? get customer => throw _privateConstructorUsedError; + + /// Create a copy of OrderFormState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $OrderFormStateCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $OrderFormStateCopyWith<$Res> { + factory $OrderFormStateCopyWith( + OrderFormState value, + $Res Function(OrderFormState) then, + ) = _$OrderFormStateCopyWithImpl<$Res, OrderFormState>; + @useResult + $Res call({ + PaymentMethod? paymentMethod, + String? customerName, + Customer? customer, + }); + + $PaymentMethodCopyWith<$Res>? get paymentMethod; + $CustomerCopyWith<$Res>? get customer; +} + +/// @nodoc +class _$OrderFormStateCopyWithImpl<$Res, $Val extends OrderFormState> + implements $OrderFormStateCopyWith<$Res> { + _$OrderFormStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of OrderFormState + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? paymentMethod = freezed, + Object? customerName = freezed, + Object? customer = freezed, + }) { + return _then( + _value.copyWith( + paymentMethod: freezed == paymentMethod + ? _value.paymentMethod + : paymentMethod // ignore: cast_nullable_to_non_nullable + as PaymentMethod?, + customerName: freezed == customerName + ? _value.customerName + : customerName // ignore: cast_nullable_to_non_nullable + as String?, + customer: freezed == customer + ? _value.customer + : customer // ignore: cast_nullable_to_non_nullable + as Customer?, + ) + as $Val, + ); + } + + /// Create a copy of OrderFormState + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $PaymentMethodCopyWith<$Res>? get paymentMethod { + if (_value.paymentMethod == null) { + return null; + } + + return $PaymentMethodCopyWith<$Res>(_value.paymentMethod!, (value) { + return _then(_value.copyWith(paymentMethod: value) as $Val); + }); + } + + /// Create a copy of OrderFormState + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $CustomerCopyWith<$Res>? get customer { + if (_value.customer == null) { + return null; + } + + return $CustomerCopyWith<$Res>(_value.customer!, (value) { + return _then(_value.copyWith(customer: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$OrderFormStateImplCopyWith<$Res> + implements $OrderFormStateCopyWith<$Res> { + factory _$$OrderFormStateImplCopyWith( + _$OrderFormStateImpl value, + $Res Function(_$OrderFormStateImpl) then, + ) = __$$OrderFormStateImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({ + PaymentMethod? paymentMethod, + String? customerName, + Customer? customer, + }); + + @override + $PaymentMethodCopyWith<$Res>? get paymentMethod; + @override + $CustomerCopyWith<$Res>? get customer; +} + +/// @nodoc +class __$$OrderFormStateImplCopyWithImpl<$Res> + extends _$OrderFormStateCopyWithImpl<$Res, _$OrderFormStateImpl> + implements _$$OrderFormStateImplCopyWith<$Res> { + __$$OrderFormStateImplCopyWithImpl( + _$OrderFormStateImpl _value, + $Res Function(_$OrderFormStateImpl) _then, + ) : super(_value, _then); + + /// Create a copy of OrderFormState + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? paymentMethod = freezed, + Object? customerName = freezed, + Object? customer = freezed, + }) { + return _then( + _$OrderFormStateImpl( + paymentMethod: freezed == paymentMethod + ? _value.paymentMethod + : paymentMethod // ignore: cast_nullable_to_non_nullable + as PaymentMethod?, + customerName: freezed == customerName + ? _value.customerName + : customerName // ignore: cast_nullable_to_non_nullable + as String?, + customer: freezed == customer + ? _value.customer + : customer // ignore: cast_nullable_to_non_nullable + as Customer?, + ), + ); + } +} + +/// @nodoc + +class _$OrderFormStateImpl + with DiagnosticableTreeMixin + implements _OrderFormState { + _$OrderFormStateImpl({this.paymentMethod, this.customerName, this.customer}); + + @override + final PaymentMethod? paymentMethod; + @override + final String? customerName; + @override + final Customer? customer; + + @override + String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) { + return 'OrderFormState(paymentMethod: $paymentMethod, customerName: $customerName, customer: $customer)'; + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('type', 'OrderFormState')) + ..add(DiagnosticsProperty('paymentMethod', paymentMethod)) + ..add(DiagnosticsProperty('customerName', customerName)) + ..add(DiagnosticsProperty('customer', customer)); + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$OrderFormStateImpl && + (identical(other.paymentMethod, paymentMethod) || + other.paymentMethod == paymentMethod) && + (identical(other.customerName, customerName) || + other.customerName == customerName) && + (identical(other.customer, customer) || + other.customer == customer)); + } + + @override + int get hashCode => + Object.hash(runtimeType, paymentMethod, customerName, customer); + + /// Create a copy of OrderFormState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$OrderFormStateImplCopyWith<_$OrderFormStateImpl> get copyWith => + __$$OrderFormStateImplCopyWithImpl<_$OrderFormStateImpl>( + this, + _$identity, + ); +} + +abstract class _OrderFormState implements OrderFormState { + factory _OrderFormState({ + final PaymentMethod? paymentMethod, + final String? customerName, + final Customer? customer, + }) = _$OrderFormStateImpl; + + @override + PaymentMethod? get paymentMethod; + @override + String? get customerName; + @override + Customer? get customer; + + /// Create a copy of OrderFormState + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$OrderFormStateImplCopyWith<_$OrderFormStateImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/application/order/order_form/order_form_event.dart b/lib/application/order/order_form/order_form_event.dart new file mode 100644 index 0000000..7af21ca --- /dev/null +++ b/lib/application/order/order_form/order_form_event.dart @@ -0,0 +1,11 @@ +part of 'order_form_bloc.dart'; + +@freezed +class OrderFormEvent with _$OrderFormEvent { + const factory OrderFormEvent.customerNameChanged(String customerName) = + _CustomerNameChanged; + const factory OrderFormEvent.paymentMethodChanged(PaymentMethod payment) = + _PaymentMethodChanged; + const factory OrderFormEvent.customerChanged(Customer? customer) = + _CustomeChanged; +} diff --git a/lib/application/order/order_form/order_form_state.dart b/lib/application/order/order_form/order_form_state.dart new file mode 100644 index 0000000..9bd3856 --- /dev/null +++ b/lib/application/order/order_form/order_form_state.dart @@ -0,0 +1,12 @@ +part of 'order_form_bloc.dart'; + +@freezed +class OrderFormState with _$OrderFormState { + factory OrderFormState({ + PaymentMethod? paymentMethod, + String? customerName, + Customer? customer, + }) = _OrderFormState; + + factory OrderFormState.initial() => OrderFormState(); +} diff --git a/lib/common/extension/string_extension.dart b/lib/common/extension/string_extension.dart index 9bc5bfe..0b937b3 100644 --- a/lib/common/extension/string_extension.dart +++ b/lib/common/extension/string_extension.dart @@ -11,6 +11,21 @@ extension StringX on String { .join(' '); } + int get toIntegerFromText { + final cleanedText = replaceAll(RegExp(r'[^0-9]'), ''); + final parsedValue = int.tryParse(cleanedText) ?? 0; + return parsedValue; + } + + String get currencyFormatRpV2 { + final parsedValue = int.tryParse(this) ?? 0; + return NumberFormat.currency( + locale: 'id', + symbol: 'Rp ', + decimalDigits: 0, + ).format(parsedValue); + } + TableStatusType toTableStatusType() { switch (this) { case 'available': diff --git a/lib/injection.config.dart b/lib/injection.config.dart index ded1483..ea19122 100644 --- a/lib/injection.config.dart +++ b/lib/injection.config.dart @@ -18,6 +18,8 @@ import 'package:apskel_pos_flutter_v2/application/checkout/checkout_form/checkou as _i13; import 'package:apskel_pos_flutter_v2/application/customer/customer_loader/customer_loader_bloc.dart' as _i683; +import 'package:apskel_pos_flutter_v2/application/order/order_form/order_form_bloc.dart' + as _i702; import 'package:apskel_pos_flutter_v2/application/outlet/outlet_loader/outlet_loader_bloc.dart' as _i76; import 'package:apskel_pos_flutter_v2/application/payment_method/payment_method_loader/payment_method_loader_bloc.dart' @@ -113,6 +115,7 @@ extension GetItInjectableX on _i174.GetIt { preResolve: true, ); gh.factory<_i13.CheckoutFormBloc>(() => _i13.CheckoutFormBloc()); + gh.factory<_i702.OrderFormBloc>(() => _i702.OrderFormBloc()); gh.singleton<_i487.DatabaseHelper>(() => databaseDi.databaseHelper); gh.lazySingleton<_i361.Dio>(() => dioDi.dio); gh.lazySingleton<_i800.AppRouter>(() => autoRouteDi.appRouter); diff --git a/lib/presentation/app_widget.dart b/lib/presentation/app_widget.dart index 2aaac4c..b365032 100644 --- a/lib/presentation/app_widget.dart +++ b/lib/presentation/app_widget.dart @@ -4,6 +4,8 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import '../application/auth/auth_bloc.dart'; import '../application/category/category_loader/category_loader_bloc.dart'; import '../application/checkout/checkout_form/checkout_form_bloc.dart'; +import '../application/customer/customer_loader/customer_loader_bloc.dart'; +import '../application/order/order_form/order_form_bloc.dart'; import '../application/outlet/outlet_loader/outlet_loader_bloc.dart'; import '../application/payment_method/payment_method_loader/payment_method_loader_bloc.dart'; import '../application/product/product_loader/product_loader_bloc.dart'; @@ -37,6 +39,8 @@ class _AppWidgetState extends State { BlocProvider(create: (context) => getIt()), BlocProvider(create: (context) => getIt()), BlocProvider(create: (context) => getIt()), + BlocProvider(create: (context) => getIt()), + BlocProvider(create: (context) => getIt()), ], child: MaterialApp.router( debugShowCheckedModeBanner: false, diff --git a/lib/presentation/components/page/page_title.dart b/lib/presentation/components/page/page_title.dart index 66aa092..2f0e4bd 100644 --- a/lib/presentation/components/page/page_title.dart +++ b/lib/presentation/components/page/page_title.dart @@ -31,7 +31,7 @@ class PageTitle extends StatelessWidget { children: [ if (isBack) ...[ GestureDetector( - onTap: () => context.maybePop(), + onTap: () => context.router.maybePop(), child: Icon(Icons.arrow_back, color: AppColor.primary, size: 24), ), SpaceWidth(16), diff --git a/lib/presentation/pages/checkout/checkout_page.dart b/lib/presentation/pages/checkout/checkout_page.dart index 3f71f0c..5dbc45c 100644 --- a/lib/presentation/pages/checkout/checkout_page.dart +++ b/lib/presentation/pages/checkout/checkout_page.dart @@ -42,7 +42,13 @@ class CheckoutPage extends StatelessWidget implements AutoRouteWrapper { ), ), SpaceWidth(2), - Expanded(flex: 3, child: CheckoutRightPanel()), + Expanded( + flex: 3, + child: CheckoutRightPanel( + checkoutState: state, + price: price, + ), + ), ], ), ); diff --git a/lib/presentation/pages/checkout/widgets/checkout_right_panel.dart b/lib/presentation/pages/checkout/widgets/checkout_right_panel.dart index 9801ae3..d34d9a5 100644 --- a/lib/presentation/pages/checkout/widgets/checkout_right_panel.dart +++ b/lib/presentation/pages/checkout/widgets/checkout_right_panel.dart @@ -1,98 +1,338 @@ +import 'package:auto_route/auto_route.dart'; import 'package:flutter/widgets.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 '../../../../application/payment_method/payment_method_loader/payment_method_loader_bloc.dart'; +import '../../../../common/extension/extension.dart'; import '../../../../common/theme/theme.dart'; +import '../../../components/button/button.dart'; import '../../../components/card/payment_card.dart'; import '../../../components/error/payment_method_error_state_widget.dart'; +import '../../../components/field/field.dart'; import '../../../components/loader/loader_with_text.dart'; import '../../../components/page/page_title.dart'; import '../../../components/spaces/space.dart'; +import '../../../components/toast/flushbar.dart'; -class CheckoutRightPanel extends StatelessWidget { - const CheckoutRightPanel({super.key}); +class CheckoutRightPanel extends StatefulWidget { + final CheckoutFormState checkoutState; + final int price; + const CheckoutRightPanel({ + super.key, + required this.checkoutState, + required this.price, + }); + + @override + State createState() => _CheckoutRightPanelState(); +} + +class _CheckoutRightPanelState extends State { + TextEditingController customerController = TextEditingController(); + TextEditingController totalPriceController = TextEditingController(); + + int priceValue = 0; + int pasMoney1 = 0; + int pasMoney2 = 0; + int pasMoney3 = 0; + + initMoney() { + setState(() { + priceValue = widget.price; + pasMoney1 = widget.price; + pasMoney2 = pasMoney1 ~/ 50000 * 50000 + 50000; + pasMoney3 = pasMoney1 ~/ 50000 * 50000 + 100000; + totalPriceController.text = widget.price.currencyFormatRpV2; + }); + } + + @override + void initState() { + super.initState(); + initMoney(); + customerController.addListener(() { + context.read().add( + OrderFormEvent.customerNameChanged(customerController.text), + ); + }); + } @override Widget build(BuildContext context) { - return Column( - children: [ - PageTitle( - title: 'Pembayaran', - isBack: false, - subtitle: 'Silahkan lakukan pembayaran', - ), - Expanded( - child: SingleChildScrollView( - child: Column( - children: [ - // Container( - // padding: const EdgeInsets.all(16), - // decoration: BoxDecoration( - // color: AppColor.white, - // border: Border( - // bottom: BorderSide(color: AppColor.border, width: 1.0), - // ), - // ), - // child: CustomerAutocomplete( - // controller: customerController, - // selectedCustomer: selectedCustomer, - // onSelected: (customer) { - // setState(() { - // selectedCustomer = customer; - // }); - // }, - // ), - // ), - Container( - padding: const EdgeInsets.all(16), - width: double.infinity, - decoration: BoxDecoration( - color: AppColor.white, - border: Border( - bottom: BorderSide(color: AppColor.border, width: 1.0), - ), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Metode Pembayaran', - style: AppStyle.lg.copyWith( - fontWeight: FontWeight.w600, + return BlocBuilder( + builder: (context, orderState) { + return Column( + children: [ + PageTitle( + title: 'Pembayaran', + isBack: false, + subtitle: 'Silahkan lakukan pembayaran', + ), + Expanded( + child: SingleChildScrollView( + child: Column( + children: [ + Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: AppColor.white, + border: Border( + bottom: BorderSide( + color: AppColor.border, + width: 1.0, + ), ), ), - const SpaceHeight(12.0), - BlocBuilder< - PaymentMethodLoaderBloc, - PaymentMethodLoaderState - >( - builder: (context, state) { - if (state.isFetching) { - return Center(child: LoaderWithText()); - } - return state.failureOption.fold( - () => Wrap( - spacing: 12.0, - runSpacing: 8.0, - children: state.paymentMethods.map((item) { - return PaymentCard( - payment: item, - isSelected: true, - ); - }).toList(), - ), - (f) => PaymentMethodErrorStateWidget(failure: f), + child: CustomerAutocomplete( + controller: customerController, + selectedCustomer: orderState.customer, + onSelected: (customer) { + context.read().add( + OrderFormEvent.customerChanged(customer), ); }, ), - ], - ), + ), + Container( + padding: const EdgeInsets.all(16), + width: double.infinity, + decoration: BoxDecoration( + color: AppColor.white, + border: Border( + bottom: BorderSide( + color: AppColor.border, + width: 1.0, + ), + ), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Metode Pembayaran', + style: AppStyle.lg.copyWith( + fontWeight: FontWeight.w600, + ), + ), + const SpaceHeight(12.0), + BlocBuilder< + PaymentMethodLoaderBloc, + PaymentMethodLoaderState + >( + builder: (context, state) { + if (state.isFetching) { + return Center(child: LoaderWithText()); + } + return state.failureOption.fold( + () => Wrap( + spacing: 12.0, + runSpacing: 8.0, + children: state.paymentMethods.map((item) { + // Set default selected payment method if none selected or if current selection is not in the list + if (orderState.paymentMethod == null || + !state.paymentMethods.any( + (method) => + method.id == + orderState.paymentMethod?.id, + )) { + context.read().add( + OrderFormEvent.paymentMethodChanged( + state.paymentMethods.first, + ), + ); + } + + return PaymentCard( + payment: item, + isSelected: + orderState.paymentMethod == item, + onSelected: (_) { + context.read().add( + OrderFormEvent.paymentMethodChanged( + item, + ), + ); + }, + ); + }).toList(), + ), + (f) => + PaymentMethodErrorStateWidget(failure: f), + ); + }, + ), + ], + ), + ), + if (orderState.paymentMethod != null && + orderState.paymentMethod!.type == 'cash') + Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: AppColor.white, + border: Border( + bottom: BorderSide( + color: AppColor.border, + width: 1.0, + ), + ), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Total Bayar', + style: AppStyle.lg.copyWith( + fontWeight: FontWeight.w600, + ), + ), + const SpaceHeight(8.0), + AppTextFormField( + label: 'Total Bayar', + showLabel: false, + keyboardType: TextInputType.number, + controller: totalPriceController, + onChanged: (value) { + priceValue = value.toIntegerFromText; + final int newValue = value.toIntegerFromText; + totalPriceController.text = + newValue.currencyFormatRp; + totalPriceController + .selection = TextSelection.fromPosition( + TextPosition( + offset: totalPriceController.text.length, + ), + ); + }, + ), + const SpaceHeight(20.0), + SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row( + children: [ + AppElevatedButton.outlined( + width: 150.0, + onPressed: () { + totalPriceController.text = pasMoney1 + .toString() + .currencyFormatRpV2; + priceValue = pasMoney1; + }, + label: 'UANG PAS', + ), + const SpaceWidth(20.0), + AppElevatedButton.outlined( + width: 150.0, + onPressed: () { + totalPriceController.text = pasMoney2 + .toString() + .currencyFormatRpV2; + priceValue = pasMoney2; + }, + label: pasMoney2 + .toString() + .currencyFormatRpV2, + ), + const SpaceWidth(20.0), + AppElevatedButton.outlined( + width: 150.0, + onPressed: () { + totalPriceController.text = pasMoney3 + .toString() + .currencyFormatRpV2; + priceValue = pasMoney3; + }, + label: pasMoney3 + .toString() + .currencyFormatRpV2, + ), + ], + ), + ), + ], + ), + ), + ], ), - ], + ), ), - ), - ), - ], + Container( + padding: EdgeInsets.all(16), + decoration: BoxDecoration( + color: AppColor.white, + border: Border( + top: BorderSide(color: AppColor.border, width: 1.0), + ), + ), + child: Row( + children: [ + Expanded( + child: AppElevatedButton.outlined( + onPressed: () => context.router.maybePop(), + label: 'Batalkan', + ), + ), + SpaceWidth(12), + Expanded( + child: AppElevatedButton.filled( + onPressed: () { + if (customerController.text == '') { + AppFlushbar.showError( + context, + 'Pilih Pelanggan terlebih dahulu', + ); + return; + } + + // showDialog( + // context: context, + // builder: (dcontext) => SaveDialog( + // selectedTable: widget.table, + // customerName: customerController.text, + // items: items, + // orderType: orderType, + // customer: selectedCustomer, + // deliveryModel: delivery, + // ), + // ); + }, + label: 'Simpan', + ), + ), + SpaceWidth(12), + Expanded( + child: AppElevatedButton.filled( + onPressed: () { + if (customerController.text == '') { + AppFlushbar.showError( + context, + 'Pilih Pelanggan terlebih dahulu', + ); + return; + } + + // context.read().add( + // OrderFormEvent.createWithPayment( + // items: items, + // customerName: customerController.text, + // orderType: orderType, + // paymentMethod: selectedPaymentMethod!, + // table: widget.table, + // customer: selectedCustomer, + // ), + // ); + }, + label: 'Bayar', + ), + ), + ], + ), + ), + ], + ); + }, ); } } diff --git a/lib/presentation/router/app_router.gr.dart b/lib/presentation/router/app_router.gr.dart index a151859..b49096a 100644 --- a/lib/presentation/router/app_router.gr.dart +++ b/lib/presentation/router/app_router.gr.dart @@ -42,7 +42,7 @@ class CheckoutRoute extends _i11.PageRouteInfo { static _i11.PageInfo page = _i11.PageInfo( name, builder: (data) { - return const _i1.CheckoutPage(); + return _i11.WrappedRoute(child: const _i1.CheckoutPage()); }, ); }