feat: syn product
This commit is contained in:
@@ -3,7 +3,6 @@ import 'dart:developer';
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:enaklo_pos/data/datasources/order_remote_datasource.dart';
|
||||
import 'package:enaklo_pos/presentation/home/models/product_quantity.dart';
|
||||
import 'package:enaklo_pos/core/extensions/string_ext.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'add_order_items_event.dart';
|
||||
@@ -12,24 +11,26 @@ part 'add_order_items_bloc.freezed.dart';
|
||||
|
||||
class AddOrderItemsBloc extends Bloc<AddOrderItemsEvent, AddOrderItemsState> {
|
||||
final OrderRemoteDatasource orderRemoteDatasource;
|
||||
|
||||
|
||||
AddOrderItemsBloc(
|
||||
this.orderRemoteDatasource,
|
||||
) : super(const _Initial()) {
|
||||
on<_AddOrderItems>((event, emit) async {
|
||||
emit(const _Loading());
|
||||
|
||||
|
||||
try {
|
||||
// Convert ProductQuantity list to the format expected by the API
|
||||
final orderItems = event.items.map((item) => {
|
||||
'id_product': item.product.productId,
|
||||
'quantity': item.quantity,
|
||||
'price': item.product.price!.toIntegerFromText,
|
||||
'notes': item.notes,
|
||||
}).toList();
|
||||
final orderItems = event.items
|
||||
.map((item) => {
|
||||
'id_product': item.product.id,
|
||||
'quantity': item.quantity,
|
||||
'price': item.product.price,
|
||||
'notes': item.notes,
|
||||
})
|
||||
.toList();
|
||||
|
||||
log("Adding order items: ${orderItems.toString()}");
|
||||
|
||||
|
||||
final result = await orderRemoteDatasource.addOrderItems(
|
||||
event.orderId,
|
||||
orderItems,
|
||||
@@ -45,4 +46,4 @@ class AddOrderItemsBloc extends Bloc<AddOrderItemsEvent, AddOrderItemsState> {
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ import 'dart:developer';
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
import 'package:enaklo_pos/core/extensions/string_ext.dart';
|
||||
import 'package:enaklo_pos/data/datasources/auth_local_datasource.dart';
|
||||
import 'package:enaklo_pos/data/datasources/order_remote_datasource.dart';
|
||||
import 'package:enaklo_pos/data/datasources/product_local_datasource.dart';
|
||||
@@ -33,8 +32,7 @@ class OrderBloc extends Bloc<OrderEvent, OrderState> {
|
||||
final subTotal = event.items.fold<int>(
|
||||
0,
|
||||
(previousValue, element) =>
|
||||
previousValue +
|
||||
(element.product.price!.toIntegerFromText * element.quantity));
|
||||
previousValue + (element.product.price! * element.quantity));
|
||||
// final total = subTotal + event.tax + event.serviceCharge - event.discount;
|
||||
|
||||
final totalItem = event.items.fold<int>(
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:enaklo_pos/data/datasources/product_remote_datasource.dart';
|
||||
import 'package:enaklo_pos/data/models/response/product_response_model.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'product_loader_event.dart';
|
||||
part 'product_loader_state.dart';
|
||||
part 'product_loader_bloc.freezed.dart';
|
||||
|
||||
class ProductLoaderBloc extends Bloc<ProductLoaderEvent, ProductLoaderState> {
|
||||
final ProductRemoteDatasource _productRemoteDatasource;
|
||||
ProductLoaderBloc(this._productRemoteDatasource)
|
||||
: super(ProductLoaderState.initial()) {
|
||||
on<_GetProduct>((event, emit) async {
|
||||
emit(const _Loading());
|
||||
final result = await _productRemoteDatasource.getProducts();
|
||||
result.fold(
|
||||
(l) => emit(_Error(l)),
|
||||
(r) => emit(_Loaded(r.data?.products ?? [])),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,790 @@
|
||||
// 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 'product_loader_bloc.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(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 _$ProductLoaderEvent {
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() getProduct,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? getProduct,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? getProduct,
|
||||
required TResult orElse(),
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_GetProduct value) getProduct,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_GetProduct value)? getProduct,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_GetProduct value)? getProduct,
|
||||
required TResult orElse(),
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $ProductLoaderEventCopyWith<$Res> {
|
||||
factory $ProductLoaderEventCopyWith(
|
||||
ProductLoaderEvent value, $Res Function(ProductLoaderEvent) then) =
|
||||
_$ProductLoaderEventCopyWithImpl<$Res, ProductLoaderEvent>;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$ProductLoaderEventCopyWithImpl<$Res, $Val extends ProductLoaderEvent>
|
||||
implements $ProductLoaderEventCopyWith<$Res> {
|
||||
_$ProductLoaderEventCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of ProductLoaderEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$GetProductImplCopyWith<$Res> {
|
||||
factory _$$GetProductImplCopyWith(
|
||||
_$GetProductImpl value, $Res Function(_$GetProductImpl) then) =
|
||||
__$$GetProductImplCopyWithImpl<$Res>;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$GetProductImplCopyWithImpl<$Res>
|
||||
extends _$ProductLoaderEventCopyWithImpl<$Res, _$GetProductImpl>
|
||||
implements _$$GetProductImplCopyWith<$Res> {
|
||||
__$$GetProductImplCopyWithImpl(
|
||||
_$GetProductImpl _value, $Res Function(_$GetProductImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of ProductLoaderEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$GetProductImpl implements _GetProduct {
|
||||
const _$GetProductImpl();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ProductLoaderEvent.getProduct()';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is _$GetProductImpl);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => runtimeType.hashCode;
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() getProduct,
|
||||
}) {
|
||||
return getProduct();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? getProduct,
|
||||
}) {
|
||||
return getProduct?.call();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? getProduct,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (getProduct != null) {
|
||||
return getProduct();
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_GetProduct value) getProduct,
|
||||
}) {
|
||||
return getProduct(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_GetProduct value)? getProduct,
|
||||
}) {
|
||||
return getProduct?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_GetProduct value)? getProduct,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (getProduct != null) {
|
||||
return getProduct(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _GetProduct implements ProductLoaderEvent {
|
||||
const factory _GetProduct() = _$GetProductImpl;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$ProductLoaderState {
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() initial,
|
||||
required TResult Function() loading,
|
||||
required TResult Function(List<Product> products) loaded,
|
||||
required TResult Function(String message) error,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? initial,
|
||||
TResult? Function()? loading,
|
||||
TResult? Function(List<Product> products)? loaded,
|
||||
TResult? Function(String message)? error,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? initial,
|
||||
TResult Function()? loading,
|
||||
TResult Function(List<Product> products)? loaded,
|
||||
TResult Function(String message)? error,
|
||||
required TResult orElse(),
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_Initial value) initial,
|
||||
required TResult Function(_Loading value) loading,
|
||||
required TResult Function(_Loaded value) loaded,
|
||||
required TResult Function(_Error value) error,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_Initial value)? initial,
|
||||
TResult? Function(_Loading value)? loading,
|
||||
TResult? Function(_Loaded value)? loaded,
|
||||
TResult? Function(_Error value)? error,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_Initial value)? initial,
|
||||
TResult Function(_Loading value)? loading,
|
||||
TResult Function(_Loaded value)? loaded,
|
||||
TResult Function(_Error value)? error,
|
||||
required TResult orElse(),
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $ProductLoaderStateCopyWith<$Res> {
|
||||
factory $ProductLoaderStateCopyWith(
|
||||
ProductLoaderState value, $Res Function(ProductLoaderState) then) =
|
||||
_$ProductLoaderStateCopyWithImpl<$Res, ProductLoaderState>;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$ProductLoaderStateCopyWithImpl<$Res, $Val extends ProductLoaderState>
|
||||
implements $ProductLoaderStateCopyWith<$Res> {
|
||||
_$ProductLoaderStateCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of ProductLoaderState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$InitialImplCopyWith<$Res> {
|
||||
factory _$$InitialImplCopyWith(
|
||||
_$InitialImpl value, $Res Function(_$InitialImpl) then) =
|
||||
__$$InitialImplCopyWithImpl<$Res>;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$InitialImplCopyWithImpl<$Res>
|
||||
extends _$ProductLoaderStateCopyWithImpl<$Res, _$InitialImpl>
|
||||
implements _$$InitialImplCopyWith<$Res> {
|
||||
__$$InitialImplCopyWithImpl(
|
||||
_$InitialImpl _value, $Res Function(_$InitialImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of ProductLoaderState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$InitialImpl implements _Initial {
|
||||
const _$InitialImpl();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ProductLoaderState.initial()';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is _$InitialImpl);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => runtimeType.hashCode;
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() initial,
|
||||
required TResult Function() loading,
|
||||
required TResult Function(List<Product> products) loaded,
|
||||
required TResult Function(String message) error,
|
||||
}) {
|
||||
return initial();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? initial,
|
||||
TResult? Function()? loading,
|
||||
TResult? Function(List<Product> products)? loaded,
|
||||
TResult? Function(String message)? error,
|
||||
}) {
|
||||
return initial?.call();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? initial,
|
||||
TResult Function()? loading,
|
||||
TResult Function(List<Product> products)? loaded,
|
||||
TResult Function(String message)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (initial != null) {
|
||||
return initial();
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_Initial value) initial,
|
||||
required TResult Function(_Loading value) loading,
|
||||
required TResult Function(_Loaded value) loaded,
|
||||
required TResult Function(_Error value) error,
|
||||
}) {
|
||||
return initial(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_Initial value)? initial,
|
||||
TResult? Function(_Loading value)? loading,
|
||||
TResult? Function(_Loaded value)? loaded,
|
||||
TResult? Function(_Error value)? error,
|
||||
}) {
|
||||
return initial?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_Initial value)? initial,
|
||||
TResult Function(_Loading value)? loading,
|
||||
TResult Function(_Loaded value)? loaded,
|
||||
TResult Function(_Error value)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (initial != null) {
|
||||
return initial(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _Initial implements ProductLoaderState {
|
||||
const factory _Initial() = _$InitialImpl;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$LoadingImplCopyWith<$Res> {
|
||||
factory _$$LoadingImplCopyWith(
|
||||
_$LoadingImpl value, $Res Function(_$LoadingImpl) then) =
|
||||
__$$LoadingImplCopyWithImpl<$Res>;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$LoadingImplCopyWithImpl<$Res>
|
||||
extends _$ProductLoaderStateCopyWithImpl<$Res, _$LoadingImpl>
|
||||
implements _$$LoadingImplCopyWith<$Res> {
|
||||
__$$LoadingImplCopyWithImpl(
|
||||
_$LoadingImpl _value, $Res Function(_$LoadingImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of ProductLoaderState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$LoadingImpl implements _Loading {
|
||||
const _$LoadingImpl();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ProductLoaderState.loading()';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is _$LoadingImpl);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => runtimeType.hashCode;
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() initial,
|
||||
required TResult Function() loading,
|
||||
required TResult Function(List<Product> products) loaded,
|
||||
required TResult Function(String message) error,
|
||||
}) {
|
||||
return loading();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? initial,
|
||||
TResult? Function()? loading,
|
||||
TResult? Function(List<Product> products)? loaded,
|
||||
TResult? Function(String message)? error,
|
||||
}) {
|
||||
return loading?.call();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? initial,
|
||||
TResult Function()? loading,
|
||||
TResult Function(List<Product> products)? loaded,
|
||||
TResult Function(String message)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (loading != null) {
|
||||
return loading();
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_Initial value) initial,
|
||||
required TResult Function(_Loading value) loading,
|
||||
required TResult Function(_Loaded value) loaded,
|
||||
required TResult Function(_Error value) error,
|
||||
}) {
|
||||
return loading(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_Initial value)? initial,
|
||||
TResult? Function(_Loading value)? loading,
|
||||
TResult? Function(_Loaded value)? loaded,
|
||||
TResult? Function(_Error value)? error,
|
||||
}) {
|
||||
return loading?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_Initial value)? initial,
|
||||
TResult Function(_Loading value)? loading,
|
||||
TResult Function(_Loaded value)? loaded,
|
||||
TResult Function(_Error value)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (loading != null) {
|
||||
return loading(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _Loading implements ProductLoaderState {
|
||||
const factory _Loading() = _$LoadingImpl;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$LoadedImplCopyWith<$Res> {
|
||||
factory _$$LoadedImplCopyWith(
|
||||
_$LoadedImpl value, $Res Function(_$LoadedImpl) then) =
|
||||
__$$LoadedImplCopyWithImpl<$Res>;
|
||||
@useResult
|
||||
$Res call({List<Product> products});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$LoadedImplCopyWithImpl<$Res>
|
||||
extends _$ProductLoaderStateCopyWithImpl<$Res, _$LoadedImpl>
|
||||
implements _$$LoadedImplCopyWith<$Res> {
|
||||
__$$LoadedImplCopyWithImpl(
|
||||
_$LoadedImpl _value, $Res Function(_$LoadedImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of ProductLoaderState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? products = null,
|
||||
}) {
|
||||
return _then(_$LoadedImpl(
|
||||
null == products
|
||||
? _value._products
|
||||
: products // ignore: cast_nullable_to_non_nullable
|
||||
as List<Product>,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$LoadedImpl implements _Loaded {
|
||||
const _$LoadedImpl(final List<Product> products) : _products = products;
|
||||
|
||||
final List<Product> _products;
|
||||
@override
|
||||
List<Product> get products {
|
||||
if (_products is EqualUnmodifiableListView) return _products;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_products);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ProductLoaderState.loaded(products: $products)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$LoadedImpl &&
|
||||
const DeepCollectionEquality().equals(other._products, _products));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(runtimeType, const DeepCollectionEquality().hash(_products));
|
||||
|
||||
/// Create a copy of ProductLoaderState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$LoadedImplCopyWith<_$LoadedImpl> get copyWith =>
|
||||
__$$LoadedImplCopyWithImpl<_$LoadedImpl>(this, _$identity);
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() initial,
|
||||
required TResult Function() loading,
|
||||
required TResult Function(List<Product> products) loaded,
|
||||
required TResult Function(String message) error,
|
||||
}) {
|
||||
return loaded(products);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? initial,
|
||||
TResult? Function()? loading,
|
||||
TResult? Function(List<Product> products)? loaded,
|
||||
TResult? Function(String message)? error,
|
||||
}) {
|
||||
return loaded?.call(products);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? initial,
|
||||
TResult Function()? loading,
|
||||
TResult Function(List<Product> products)? loaded,
|
||||
TResult Function(String message)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (loaded != null) {
|
||||
return loaded(products);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_Initial value) initial,
|
||||
required TResult Function(_Loading value) loading,
|
||||
required TResult Function(_Loaded value) loaded,
|
||||
required TResult Function(_Error value) error,
|
||||
}) {
|
||||
return loaded(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_Initial value)? initial,
|
||||
TResult? Function(_Loading value)? loading,
|
||||
TResult? Function(_Loaded value)? loaded,
|
||||
TResult? Function(_Error value)? error,
|
||||
}) {
|
||||
return loaded?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_Initial value)? initial,
|
||||
TResult Function(_Loading value)? loading,
|
||||
TResult Function(_Loaded value)? loaded,
|
||||
TResult Function(_Error value)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (loaded != null) {
|
||||
return loaded(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _Loaded implements ProductLoaderState {
|
||||
const factory _Loaded(final List<Product> products) = _$LoadedImpl;
|
||||
|
||||
List<Product> get products;
|
||||
|
||||
/// Create a copy of ProductLoaderState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$LoadedImplCopyWith<_$LoadedImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$ErrorImplCopyWith<$Res> {
|
||||
factory _$$ErrorImplCopyWith(
|
||||
_$ErrorImpl value, $Res Function(_$ErrorImpl) then) =
|
||||
__$$ErrorImplCopyWithImpl<$Res>;
|
||||
@useResult
|
||||
$Res call({String message});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$ErrorImplCopyWithImpl<$Res>
|
||||
extends _$ProductLoaderStateCopyWithImpl<$Res, _$ErrorImpl>
|
||||
implements _$$ErrorImplCopyWith<$Res> {
|
||||
__$$ErrorImplCopyWithImpl(
|
||||
_$ErrorImpl _value, $Res Function(_$ErrorImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of ProductLoaderState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? message = null,
|
||||
}) {
|
||||
return _then(_$ErrorImpl(
|
||||
null == message
|
||||
? _value.message
|
||||
: message // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$ErrorImpl implements _Error {
|
||||
const _$ErrorImpl(this.message);
|
||||
|
||||
@override
|
||||
final String message;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ProductLoaderState.error(message: $message)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$ErrorImpl &&
|
||||
(identical(other.message, message) || other.message == message));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, message);
|
||||
|
||||
/// Create a copy of ProductLoaderState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$ErrorImplCopyWith<_$ErrorImpl> get copyWith =>
|
||||
__$$ErrorImplCopyWithImpl<_$ErrorImpl>(this, _$identity);
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() initial,
|
||||
required TResult Function() loading,
|
||||
required TResult Function(List<Product> products) loaded,
|
||||
required TResult Function(String message) error,
|
||||
}) {
|
||||
return error(message);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? initial,
|
||||
TResult? Function()? loading,
|
||||
TResult? Function(List<Product> products)? loaded,
|
||||
TResult? Function(String message)? error,
|
||||
}) {
|
||||
return error?.call(message);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? initial,
|
||||
TResult Function()? loading,
|
||||
TResult Function(List<Product> products)? loaded,
|
||||
TResult Function(String message)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (error != null) {
|
||||
return error(message);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_Initial value) initial,
|
||||
required TResult Function(_Loading value) loading,
|
||||
required TResult Function(_Loaded value) loaded,
|
||||
required TResult Function(_Error value) error,
|
||||
}) {
|
||||
return error(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_Initial value)? initial,
|
||||
TResult? Function(_Loading value)? loading,
|
||||
TResult? Function(_Loaded value)? loaded,
|
||||
TResult? Function(_Error value)? error,
|
||||
}) {
|
||||
return error?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_Initial value)? initial,
|
||||
TResult Function(_Loading value)? loading,
|
||||
TResult Function(_Loaded value)? loaded,
|
||||
TResult Function(_Error value)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (error != null) {
|
||||
return error(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _Error implements ProductLoaderState {
|
||||
const factory _Error(final String message) = _$ErrorImpl;
|
||||
|
||||
String get message;
|
||||
|
||||
/// Create a copy of ProductLoaderState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$ErrorImplCopyWith<_$ErrorImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
part of 'product_loader_bloc.dart';
|
||||
|
||||
@freezed
|
||||
class ProductLoaderEvent with _$ProductLoaderEvent {
|
||||
const factory ProductLoaderEvent.getProduct() = _GetProduct;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
part of 'product_loader_bloc.dart';
|
||||
|
||||
@freezed
|
||||
class ProductLoaderState with _$ProductLoaderState {
|
||||
const factory ProductLoaderState.initial() = _Initial;
|
||||
const factory ProductLoaderState.loading() = _Loading;
|
||||
const factory ProductLoaderState.loaded(List<Product> products) = _Loaded;
|
||||
const factory ProductLoaderState.error(String message) = _Error;
|
||||
}
|
||||
@@ -39,7 +39,7 @@ class ProductQuantity {
|
||||
|
||||
return {
|
||||
'id_order': orderId,
|
||||
'id_product': product.productId,
|
||||
'id_product': product.id,
|
||||
'quantity': quantity,
|
||||
'price': product.price,
|
||||
'notes': notes,
|
||||
@@ -47,11 +47,11 @@ class ProductQuantity {
|
||||
}
|
||||
|
||||
Map<String, dynamic> toServerMap(int? orderId) {
|
||||
log("toServerMap: ${product.productId}");
|
||||
log("toServerMap: ${product.id}");
|
||||
|
||||
return {
|
||||
'id_order': orderId ?? 0,
|
||||
'id_product': product.productId,
|
||||
'id_product': product.id,
|
||||
'quantity': quantity,
|
||||
'price': product.price,
|
||||
'notes': notes,
|
||||
|
||||
@@ -254,8 +254,7 @@ class _ConfirmPaymentPageState extends State<ConfirmPaymentPage> {
|
||||
0,
|
||||
(previousValue, element) =>
|
||||
previousValue +
|
||||
(element.product.price!
|
||||
.toIntegerFromText *
|
||||
(element.product.price! *
|
||||
element.quantity),
|
||||
));
|
||||
return Text(
|
||||
@@ -315,8 +314,7 @@ class _ConfirmPaymentPageState extends State<ConfirmPaymentPage> {
|
||||
0,
|
||||
(previousValue, element) =>
|
||||
previousValue +
|
||||
(element.product.price!
|
||||
.toIntegerFromText *
|
||||
(element.product.price! *
|
||||
element.quantity),
|
||||
));
|
||||
|
||||
@@ -373,8 +371,7 @@ class _ConfirmPaymentPageState extends State<ConfirmPaymentPage> {
|
||||
0,
|
||||
(previousValue, element) =>
|
||||
previousValue +
|
||||
(element.product.price!
|
||||
.toIntegerFromText *
|
||||
(element.product.price! *
|
||||
element.quantity),
|
||||
),
|
||||
);
|
||||
@@ -457,8 +454,7 @@ class _ConfirmPaymentPageState extends State<ConfirmPaymentPage> {
|
||||
0,
|
||||
(previousValue, element) =>
|
||||
previousValue +
|
||||
(element.product.price!
|
||||
.toIntegerFromText *
|
||||
(element.product.price! *
|
||||
element.quantity),
|
||||
),
|
||||
);
|
||||
@@ -509,8 +505,7 @@ class _ConfirmPaymentPageState extends State<ConfirmPaymentPage> {
|
||||
0,
|
||||
(previousValue, element) =>
|
||||
previousValue +
|
||||
(element.product.price!
|
||||
.toIntegerFromText *
|
||||
(element.product.price! *
|
||||
element.quantity),
|
||||
),
|
||||
);
|
||||
@@ -1262,8 +1257,7 @@ class _ConfirmPaymentPageState extends State<ConfirmPaymentPage> {
|
||||
0,
|
||||
(previousValue, element) =>
|
||||
previousValue +
|
||||
(element.product.price!
|
||||
.toIntegerFromText *
|
||||
(element.product.price! *
|
||||
element.quantity),
|
||||
),
|
||||
);
|
||||
@@ -1566,10 +1560,8 @@ class _ConfirmPaymentPageState extends State<ConfirmPaymentPage> {
|
||||
0,
|
||||
(sum, item) =>
|
||||
sum +
|
||||
(int.tryParse(item
|
||||
.product
|
||||
.price ??
|
||||
'0') ??
|
||||
(item.product
|
||||
.price ??
|
||||
0) *
|
||||
item.quantity),
|
||||
);
|
||||
|
||||
@@ -282,8 +282,7 @@ class _ConfirmPaymentPageState extends State<ConfirmPaymentPage> {
|
||||
0,
|
||||
(previousValue, element) =>
|
||||
previousValue +
|
||||
(element.product.price!
|
||||
.toIntegerFromText *
|
||||
(element.product.price! *
|
||||
element.quantity),
|
||||
));
|
||||
return Text(
|
||||
@@ -340,8 +339,7 @@ class _ConfirmPaymentPageState extends State<ConfirmPaymentPage> {
|
||||
0,
|
||||
(previousValue, element) =>
|
||||
previousValue +
|
||||
(element.product.price!
|
||||
.toIntegerFromText *
|
||||
(element.product.price! *
|
||||
element.quantity),
|
||||
),
|
||||
);
|
||||
@@ -417,8 +415,7 @@ class _ConfirmPaymentPageState extends State<ConfirmPaymentPage> {
|
||||
0,
|
||||
(previousValue, element) =>
|
||||
previousValue +
|
||||
(element.product.price!
|
||||
.toIntegerFromText *
|
||||
(element.product.price! *
|
||||
element.quantity),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
// ignore_for_file: public_member_api_docs, sort_constructors_first
|
||||
import 'package:enaklo_pos/presentation/home/bloc/product_loader/product_loader_bloc.dart';
|
||||
import 'package:enaklo_pos/presentation/home/widgets/home_right_title.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
import 'package:enaklo_pos/core/extensions/build_context_ext.dart';
|
||||
import 'package:enaklo_pos/core/extensions/int_ext.dart';
|
||||
import 'package:enaklo_pos/core/extensions/string_ext.dart';
|
||||
import 'package:enaklo_pos/data/models/response/table_model.dart';
|
||||
import 'package:enaklo_pos/presentation/home/bloc/local_product/local_product_bloc.dart';
|
||||
import 'package:enaklo_pos/presentation/home/pages/confirm_payment_page.dart';
|
||||
import 'package:enaklo_pos/data/datasources/product_local_datasource.dart';
|
||||
import 'package:enaklo_pos/presentation/setting/bloc/sync_product/sync_product_bloc.dart';
|
||||
import 'package:enaklo_pos/data/models/response/product_response_model.dart';
|
||||
|
||||
import '../../../core/assets/assets.gen.dart';
|
||||
@@ -49,12 +46,15 @@ class _HomePageState extends State<HomePage> {
|
||||
|
||||
void _syncAndLoadProducts() {
|
||||
// Trigger sync from API first
|
||||
context.read<SyncProductBloc>().add(const SyncProductEvent.syncProduct());
|
||||
// context.read<SyncProductBloc>().add(const SyncProductEvent.syncProduct());
|
||||
|
||||
// Also load local products initially in case sync fails or takes time
|
||||
// context
|
||||
// .read<LocalProductBloc>()
|
||||
// .add(const LocalProductEvent.getLocalProduct());
|
||||
context
|
||||
.read<LocalProductBloc>()
|
||||
.add(const LocalProductEvent.getLocalProduct());
|
||||
.read<ProductLoaderBloc>()
|
||||
.add(const ProductLoaderEvent.getProduct());
|
||||
|
||||
// Initialize checkout with tax and service charge settings
|
||||
context.read<CheckoutBloc>().add(const CheckoutEvent.started());
|
||||
@@ -83,7 +83,7 @@ class _HomePageState extends State<HomePage> {
|
||||
List<Product> products, int categoryId) {
|
||||
final filteredBySearch = _filterProducts(products);
|
||||
return filteredBySearch
|
||||
.where((element) => element.category?.id == categoryId)
|
||||
.where((element) => element.price == categoryId)
|
||||
.toList();
|
||||
}
|
||||
|
||||
@@ -93,451 +93,420 @@ class _HomePageState extends State<HomePage> {
|
||||
tag: 'confirmation_screen',
|
||||
child: Scaffold(
|
||||
backgroundColor: AppColors.white,
|
||||
body: BlocListener<SyncProductBloc, SyncProductState>(
|
||||
listener: (context, state) {
|
||||
state.maybeWhen(
|
||||
orElse: () {},
|
||||
error: (message) {
|
||||
// If sync fails, still try to load local products
|
||||
context
|
||||
.read<LocalProductBloc>()
|
||||
.add(const LocalProductEvent.getLocalProduct());
|
||||
},
|
||||
loaded: (productResponseModel) async {
|
||||
// Store context reference before async operations
|
||||
final localProductBloc = context.read<LocalProductBloc>();
|
||||
|
||||
// Save synced products to local database
|
||||
await ProductLocalDatasource.instance.deleteAllProducts();
|
||||
await ProductLocalDatasource.instance.insertProducts(
|
||||
productResponseModel.data!,
|
||||
);
|
||||
// Then load local products to display
|
||||
localProductBloc.add(const LocalProductEvent.getLocalProduct());
|
||||
},
|
||||
);
|
||||
},
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 3,
|
||||
child: Align(
|
||||
alignment: AlignmentDirectional.topStart,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
HomeTitle(
|
||||
controller: searchController,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
searchQuery = value;
|
||||
});
|
||||
},
|
||||
),
|
||||
BlocBuilder<LocalProductBloc, LocalProductState>(
|
||||
builder: (context, state) {
|
||||
return Expanded(
|
||||
child: CustomTabBarV2(
|
||||
tabTitles: const [
|
||||
'Semua',
|
||||
'Makanan',
|
||||
'Minuman',
|
||||
'Paket'
|
||||
],
|
||||
tabViews: [
|
||||
// All Products Tab
|
||||
SizedBox(
|
||||
child: state.maybeWhen(orElse: () {
|
||||
body: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 3,
|
||||
child: Align(
|
||||
alignment: AlignmentDirectional.topStart,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
HomeTitle(
|
||||
controller: searchController,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
searchQuery = value;
|
||||
});
|
||||
},
|
||||
),
|
||||
BlocBuilder<ProductLoaderBloc, ProductLoaderState>(
|
||||
builder: (context, state) {
|
||||
return Expanded(
|
||||
child: CustomTabBarV2(
|
||||
tabTitles: const [
|
||||
'Semua',
|
||||
'Makanan',
|
||||
'Minuman',
|
||||
'Paket'
|
||||
],
|
||||
tabViews: [
|
||||
// All Products Tab
|
||||
SizedBox(
|
||||
child: state.maybeWhen(orElse: () {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
}, loading: () {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
}, loaded: (products) {
|
||||
final filteredProducts =
|
||||
_filterProducts(products);
|
||||
if (filteredProducts.isEmpty) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
child: Text('No Items Found'),
|
||||
);
|
||||
}, loading: () {
|
||||
}
|
||||
return GridView.builder(
|
||||
itemCount: filteredProducts.length,
|
||||
padding: const EdgeInsets.all(16),
|
||||
gridDelegate:
|
||||
SliverGridDelegateWithMaxCrossAxisExtent(
|
||||
maxCrossAxisExtent: 180,
|
||||
mainAxisSpacing: 30,
|
||||
crossAxisSpacing: 30,
|
||||
childAspectRatio: 180 / 240,
|
||||
),
|
||||
itemBuilder: (context, index) =>
|
||||
ProductCard(
|
||||
data: filteredProducts[index],
|
||||
onCartButton: () {},
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
// Makanan Tab
|
||||
SizedBox(
|
||||
child: state.maybeWhen(orElse: () {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
}, loading: () {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
}, loaded: (products) {
|
||||
if (products.isEmpty) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
child: Text('No Items'),
|
||||
);
|
||||
}, loaded: (products) {
|
||||
final filteredProducts =
|
||||
_filterProducts(products);
|
||||
if (filteredProducts.isEmpty) {
|
||||
return const Center(
|
||||
child: Text('No Items Found'),
|
||||
);
|
||||
}
|
||||
return GridView.builder(
|
||||
itemCount: filteredProducts.length,
|
||||
padding: const EdgeInsets.all(16),
|
||||
gridDelegate:
|
||||
SliverGridDelegateWithMaxCrossAxisExtent(
|
||||
maxCrossAxisExtent: 180,
|
||||
mainAxisSpacing: 30,
|
||||
crossAxisSpacing: 30,
|
||||
childAspectRatio: 180 / 240,
|
||||
),
|
||||
itemBuilder: (context, index) =>
|
||||
ProductCard(
|
||||
data: filteredProducts[index],
|
||||
onCartButton: () {},
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
// Makanan Tab
|
||||
SizedBox(
|
||||
child: state.maybeWhen(orElse: () {
|
||||
}
|
||||
final filteredProducts =
|
||||
_filterProductsByCategory(products, 1);
|
||||
return filteredProducts.isEmpty
|
||||
? const _IsEmpty()
|
||||
: GridView.builder(
|
||||
itemCount: filteredProducts.length,
|
||||
padding: const EdgeInsets.all(16),
|
||||
gridDelegate:
|
||||
SliverGridDelegateWithMaxCrossAxisExtent(
|
||||
maxCrossAxisExtent:
|
||||
200, // Lebar maksimal tiap item (bisa kamu ubah)
|
||||
mainAxisSpacing: 30,
|
||||
crossAxisSpacing: 30,
|
||||
childAspectRatio: 0.85,
|
||||
),
|
||||
itemBuilder: (context, index) =>
|
||||
ProductCard(
|
||||
data: filteredProducts[index],
|
||||
onCartButton: () {},
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
// Minuman Tab
|
||||
SizedBox(
|
||||
child: state.maybeWhen(orElse: () {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
}, loading: () {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
}, loaded: (products) {
|
||||
if (products.isEmpty) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
child: Text('No Items'),
|
||||
);
|
||||
}, loading: () {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
}, loaded: (products) {
|
||||
if (products.isEmpty) {
|
||||
return const Center(
|
||||
child: Text('No Items'),
|
||||
);
|
||||
}
|
||||
final filteredProducts =
|
||||
_filterProductsByCategory(products, 1);
|
||||
return filteredProducts.isEmpty
|
||||
? const _IsEmpty()
|
||||
: GridView.builder(
|
||||
itemCount: filteredProducts.length,
|
||||
padding: const EdgeInsets.all(16),
|
||||
gridDelegate:
|
||||
SliverGridDelegateWithMaxCrossAxisExtent(
|
||||
maxCrossAxisExtent:
|
||||
200, // Lebar maksimal tiap item (bisa kamu ubah)
|
||||
mainAxisSpacing: 30,
|
||||
crossAxisSpacing: 30,
|
||||
childAspectRatio: 0.85,
|
||||
),
|
||||
itemBuilder: (context, index) =>
|
||||
ProductCard(
|
||||
}
|
||||
final filteredProducts =
|
||||
_filterProductsByCategory(products, 2);
|
||||
return filteredProducts.isEmpty
|
||||
? const _IsEmpty()
|
||||
: GridView.builder(
|
||||
itemCount: filteredProducts.length,
|
||||
padding: const EdgeInsets.all(16),
|
||||
gridDelegate:
|
||||
SliverGridDelegateWithMaxCrossAxisExtent(
|
||||
maxCrossAxisExtent:
|
||||
200, // Lebar maksimal tiap item (bisa kamu ubah)
|
||||
mainAxisSpacing: 30,
|
||||
crossAxisSpacing: 30,
|
||||
childAspectRatio: 0.85,
|
||||
),
|
||||
itemBuilder: (context, index) {
|
||||
return ProductCard(
|
||||
data: filteredProducts[index],
|
||||
onCartButton: () {},
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
// Minuman Tab
|
||||
SizedBox(
|
||||
child: state.maybeWhen(orElse: () {
|
||||
);
|
||||
},
|
||||
);
|
||||
}),
|
||||
),
|
||||
// Snack Tab
|
||||
SizedBox(
|
||||
child: state.maybeWhen(orElse: () {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
}, loading: () {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
}, loaded: (products) {
|
||||
if (products.isEmpty) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
child: Text('No Items'),
|
||||
);
|
||||
}, loading: () {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
}, loaded: (products) {
|
||||
if (products.isEmpty) {
|
||||
return const Center(
|
||||
child: Text('No Items'),
|
||||
);
|
||||
}
|
||||
final filteredProducts =
|
||||
_filterProductsByCategory(products, 2);
|
||||
return filteredProducts.isEmpty
|
||||
? const _IsEmpty()
|
||||
: GridView.builder(
|
||||
itemCount: filteredProducts.length,
|
||||
padding: const EdgeInsets.all(16),
|
||||
gridDelegate:
|
||||
SliverGridDelegateWithMaxCrossAxisExtent(
|
||||
maxCrossAxisExtent:
|
||||
200, // Lebar maksimal tiap item (bisa kamu ubah)
|
||||
mainAxisSpacing: 30,
|
||||
crossAxisSpacing: 30,
|
||||
childAspectRatio: 0.85,
|
||||
),
|
||||
itemBuilder: (context, index) {
|
||||
return ProductCard(
|
||||
data: filteredProducts[index],
|
||||
onCartButton: () {},
|
||||
);
|
||||
},
|
||||
);
|
||||
}),
|
||||
),
|
||||
// Snack Tab
|
||||
SizedBox(
|
||||
child: state.maybeWhen(orElse: () {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
}, loading: () {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
}, loaded: (products) {
|
||||
if (products.isEmpty) {
|
||||
return const Center(
|
||||
child: Text('No Items'),
|
||||
);
|
||||
}
|
||||
final filteredProducts =
|
||||
_filterProductsByCategory(products, 3);
|
||||
return filteredProducts.isEmpty
|
||||
? const _IsEmpty()
|
||||
: GridView.builder(
|
||||
itemCount: filteredProducts.length,
|
||||
padding: const EdgeInsets.all(16),
|
||||
gridDelegate:
|
||||
SliverGridDelegateWithMaxCrossAxisExtent(
|
||||
maxCrossAxisExtent:
|
||||
200, // Lebar maksimal tiap item (bisa kamu ubah)
|
||||
mainAxisSpacing: 30,
|
||||
crossAxisSpacing: 30,
|
||||
childAspectRatio: 0.85,
|
||||
),
|
||||
itemBuilder: (context, index) {
|
||||
return ProductCard(
|
||||
data: filteredProducts[index],
|
||||
onCartButton: () {},
|
||||
);
|
||||
},
|
||||
);
|
||||
}),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
}
|
||||
final filteredProducts =
|
||||
_filterProductsByCategory(products, 3);
|
||||
return filteredProducts.isEmpty
|
||||
? const _IsEmpty()
|
||||
: GridView.builder(
|
||||
itemCount: filteredProducts.length,
|
||||
padding: const EdgeInsets.all(16),
|
||||
gridDelegate:
|
||||
SliverGridDelegateWithMaxCrossAxisExtent(
|
||||
maxCrossAxisExtent:
|
||||
200, // Lebar maksimal tiap item (bisa kamu ubah)
|
||||
mainAxisSpacing: 30,
|
||||
crossAxisSpacing: 30,
|
||||
childAspectRatio: 0.85,
|
||||
),
|
||||
itemBuilder: (context, index) {
|
||||
return ProductCard(
|
||||
data: filteredProducts[index],
|
||||
onCartButton: () {},
|
||||
);
|
||||
},
|
||||
);
|
||||
}),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Align(
|
||||
alignment: Alignment.topCenter,
|
||||
child: Material(
|
||||
color: Colors.white,
|
||||
child: Column(
|
||||
children: [
|
||||
HomeRightTitle(
|
||||
table: widget.table,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16.0)
|
||||
.copyWith(bottom: 0, top: 27),
|
||||
child: Column(
|
||||
children: [
|
||||
const Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Item',
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Align(
|
||||
alignment: Alignment.topCenter,
|
||||
child: Material(
|
||||
color: Colors.white,
|
||||
child: Column(
|
||||
children: [
|
||||
HomeRightTitle(
|
||||
table: widget.table,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16.0)
|
||||
.copyWith(bottom: 0, top: 27),
|
||||
child: Column(
|
||||
children: [
|
||||
const Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Item',
|
||||
style: TextStyle(
|
||||
color: AppColors.primary,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 130,
|
||||
),
|
||||
SizedBox(
|
||||
width: 50.0,
|
||||
child: Text(
|
||||
'Qty',
|
||||
style: TextStyle(
|
||||
color: AppColors.primary,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 130,
|
||||
),
|
||||
SizedBox(
|
||||
width: 50.0,
|
||||
child: Text(
|
||||
'Qty',
|
||||
style: TextStyle(
|
||||
color: AppColors.primary,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
child: Text(
|
||||
'Price',
|
||||
style: TextStyle(
|
||||
color: AppColors.primary,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
child: Text(
|
||||
'Price',
|
||||
style: TextStyle(
|
||||
color: AppColors.primary,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SpaceHeight(8),
|
||||
const Divider(),
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(16.0).copyWith(top: 0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
BlocBuilder<CheckoutBloc, CheckoutState>(
|
||||
builder: (context, state) {
|
||||
return state.maybeWhen(
|
||||
orElse: () => const Center(
|
||||
child: Text('No Items'),
|
||||
),
|
||||
),
|
||||
],
|
||||
loaded: (products,
|
||||
discountModel,
|
||||
discount,
|
||||
discountAmount,
|
||||
tax,
|
||||
serviceCharge,
|
||||
totalQuantity,
|
||||
totalPrice,
|
||||
draftName,
|
||||
orderType) {
|
||||
if (products.isEmpty) {
|
||||
return const Center(
|
||||
child: Text('No Items'),
|
||||
);
|
||||
}
|
||||
return ListView.separated(
|
||||
shrinkWrap: true,
|
||||
physics:
|
||||
const NeverScrollableScrollPhysics(),
|
||||
itemBuilder: (context, index) =>
|
||||
OrderMenu(data: products[index]),
|
||||
separatorBuilder: (context, index) =>
|
||||
const SpaceHeight(1.0),
|
||||
itemCount: products.length,
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
const SpaceHeight(8),
|
||||
const Divider(),
|
||||
const SpaceHeight(8.0),
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
padding:
|
||||
const EdgeInsets.all(16.0).copyWith(top: 0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16.0).copyWith(top: 0),
|
||||
child: Column(
|
||||
children: [
|
||||
const Divider(),
|
||||
const SpaceHeight(16.0),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const Text(
|
||||
'Pajak',
|
||||
style: TextStyle(
|
||||
color: AppColors.black,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
BlocBuilder<CheckoutBloc, CheckoutState>(
|
||||
builder: (context, state) {
|
||||
return state.maybeWhen(
|
||||
orElse: () => const Center(
|
||||
child: Text('No Items'),
|
||||
final tax = state.maybeWhen(
|
||||
orElse: () => 0,
|
||||
loaded: (products,
|
||||
discountModel,
|
||||
discount,
|
||||
discountAmount,
|
||||
tax,
|
||||
serviceCharge,
|
||||
totalQuantity,
|
||||
totalPrice,
|
||||
draftName,
|
||||
orderType) {
|
||||
if (products.isEmpty) {
|
||||
return 0;
|
||||
}
|
||||
return tax;
|
||||
});
|
||||
return Text(
|
||||
'$tax %',
|
||||
style: const TextStyle(
|
||||
color: AppColors.primary,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
loaded: (products,
|
||||
discountModel,
|
||||
discount,
|
||||
discountAmount,
|
||||
tax,
|
||||
serviceCharge,
|
||||
totalQuantity,
|
||||
totalPrice,
|
||||
draftName,
|
||||
orderType) {
|
||||
if (products.isEmpty) {
|
||||
return const Center(
|
||||
child: Text('No Items'),
|
||||
);
|
||||
}
|
||||
return ListView.separated(
|
||||
shrinkWrap: true,
|
||||
physics:
|
||||
const NeverScrollableScrollPhysics(),
|
||||
itemBuilder: (context, index) =>
|
||||
OrderMenu(data: products[index]),
|
||||
separatorBuilder: (context, index) =>
|
||||
const SpaceHeight(1.0),
|
||||
itemCount: products.length,
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
const SpaceHeight(8.0),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16.0).copyWith(top: 0),
|
||||
child: Column(
|
||||
children: [
|
||||
const Divider(),
|
||||
const SpaceHeight(16.0),
|
||||
Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const Text(
|
||||
'Pajak',
|
||||
style: TextStyle(
|
||||
color: AppColors.black,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
BlocBuilder<CheckoutBloc, CheckoutState>(
|
||||
builder: (context, state) {
|
||||
final tax = state.maybeWhen(
|
||||
orElse: () => 0,
|
||||
loaded: (products,
|
||||
discountModel,
|
||||
discount,
|
||||
discountAmount,
|
||||
tax,
|
||||
serviceCharge,
|
||||
totalQuantity,
|
||||
totalPrice,
|
||||
draftName,
|
||||
orderType) {
|
||||
if (products.isEmpty) {
|
||||
return 0;
|
||||
}
|
||||
return tax;
|
||||
});
|
||||
return Text(
|
||||
'$tax %',
|
||||
style: const TextStyle(
|
||||
color: AppColors.primary,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
const SpaceHeight(16.0),
|
||||
Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const Text(
|
||||
'Sub total',
|
||||
style: TextStyle(
|
||||
color: AppColors.black,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
BlocBuilder<CheckoutBloc, CheckoutState>(
|
||||
builder: (context, state) {
|
||||
final price = state.maybeWhen(
|
||||
orElse: () => 0,
|
||||
loaded: (products,
|
||||
discountModel,
|
||||
discount,
|
||||
discountAmount,
|
||||
tax,
|
||||
serviceCharge,
|
||||
totalQuantity,
|
||||
totalPrice,
|
||||
draftName,
|
||||
orderType) {
|
||||
if (products.isEmpty) {
|
||||
return 0;
|
||||
}
|
||||
return products
|
||||
.map((e) =>
|
||||
e.product.price!
|
||||
.toIntegerFromText *
|
||||
e.quantity)
|
||||
.reduce((value, element) =>
|
||||
value + element);
|
||||
});
|
||||
|
||||
return Text(
|
||||
price.currencyFormatRp,
|
||||
style: const TextStyle(
|
||||
color: AppColors.primary,
|
||||
fontWeight: FontWeight.w900,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
SpaceHeight(16.0),
|
||||
Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: Expanded(
|
||||
child: Button.filled(
|
||||
borderRadius: 12,
|
||||
elevation: 1,
|
||||
onPressed: () {
|
||||
context.push(ConfirmPaymentPage(
|
||||
isTable: widget.isTable,
|
||||
table: widget.table,
|
||||
));
|
||||
},
|
||||
label: 'Lanjutkan Pembayaran',
|
||||
const SpaceHeight(16.0),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const Text(
|
||||
'Sub total',
|
||||
style: TextStyle(
|
||||
color: AppColors.black,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
BlocBuilder<CheckoutBloc, CheckoutState>(
|
||||
builder: (context, state) {
|
||||
final price = state.maybeWhen(
|
||||
orElse: () => 0,
|
||||
loaded: (products,
|
||||
discountModel,
|
||||
discount,
|
||||
discountAmount,
|
||||
tax,
|
||||
serviceCharge,
|
||||
totalQuantity,
|
||||
totalPrice,
|
||||
draftName,
|
||||
orderType) {
|
||||
if (products.isEmpty) {
|
||||
return 0;
|
||||
}
|
||||
return products
|
||||
.map((e) =>
|
||||
e.product.price! * e.quantity)
|
||||
.reduce((value, element) =>
|
||||
value + element);
|
||||
});
|
||||
|
||||
return Text(
|
||||
price.currencyFormatRp,
|
||||
style: const TextStyle(
|
||||
color: AppColors.primary,
|
||||
fontWeight: FontWeight.w900,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
SpaceHeight(16.0),
|
||||
Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: Expanded(
|
||||
child: Button.filled(
|
||||
borderRadius: 12,
|
||||
elevation: 1,
|
||||
onPressed: () {
|
||||
context.push(ConfirmPaymentPage(
|
||||
isTable: widget.isTable,
|
||||
table: widget.table,
|
||||
));
|
||||
},
|
||||
label: 'Lanjutkan Pembayaran',
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -3,7 +3,6 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:enaklo_pos/core/constants/variables.dart';
|
||||
import 'package:enaklo_pos/core/extensions/int_ext.dart';
|
||||
import 'package:enaklo_pos/core/extensions/string_ext.dart';
|
||||
import 'package:enaklo_pos/presentation/home/bloc/checkout/checkout_bloc.dart';
|
||||
import 'package:enaklo_pos/presentation/home/models/product_quantity.dart';
|
||||
|
||||
@@ -52,7 +51,7 @@ class _OrderMenuState extends State<OrderMenu> {
|
||||
child: ListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
leading: ClipRRect(
|
||||
borderRadius: BorderRadius.all(Radius.circular(50.0)),
|
||||
borderRadius: BorderRadius.all(Radius.circular(8.0)),
|
||||
child:
|
||||
// Icon(
|
||||
// Icons.fastfood,
|
||||
@@ -60,14 +59,23 @@ class _OrderMenuState extends State<OrderMenu> {
|
||||
// color: AppColors.primary,
|
||||
// ),
|
||||
CachedNetworkImage(
|
||||
imageUrl: widget.data.product.image!.contains('http')
|
||||
? widget.data.product.image!
|
||||
: '${Variables.baseUrl}/${widget.data.product.image}',
|
||||
imageUrl: widget.data.product.name!.contains('http')
|
||||
? widget.data.product.name!
|
||||
: '${Variables.baseUrl}/${widget.data.product.name}',
|
||||
width: 50.0,
|
||||
height: 50.0,
|
||||
fit: BoxFit.cover,
|
||||
errorWidget: (context, url, error) =>
|
||||
const Icon(Icons.error),
|
||||
errorWidget: (context, url, error) => Container(
|
||||
width: 50.0,
|
||||
height: 50.0,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.disabled.withOpacity(0.4),
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.image,
|
||||
color: AppColors.grey,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
title: Row(
|
||||
@@ -86,8 +94,7 @@ class _OrderMenuState extends State<OrderMenu> {
|
||||
subtitle: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(widget.data.product.price!.toIntegerFromText
|
||||
.currencyFormatRp),
|
||||
Text(widget.data.product.price!.currencyFormatRp),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -139,8 +146,7 @@ class _OrderMenuState extends State<OrderMenu> {
|
||||
SizedBox(
|
||||
width: 80.0,
|
||||
child: Text(
|
||||
(widget.data.product.price!.toIntegerFromText *
|
||||
widget.data.quantity)
|
||||
(widget.data.product.price! * widget.data.quantity)
|
||||
.currencyFormatRp,
|
||||
textAlign: TextAlign.right,
|
||||
style: const TextStyle(
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:enaklo_pos/core/extensions/int_ext.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:enaklo_pos/core/constants/variables.dart';
|
||||
import 'package:enaklo_pos/core/extensions/int_ext.dart';
|
||||
import 'package:enaklo_pos/core/extensions/string_ext.dart';
|
||||
import 'package:enaklo_pos/data/models/response/product_response_model.dart';
|
||||
import 'package:enaklo_pos/presentation/home/bloc/checkout/checkout_bloc.dart';
|
||||
|
||||
@@ -43,9 +42,9 @@ class ProductCard extends StatelessWidget {
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.all(Radius.circular(8.0)),
|
||||
child: CachedNetworkImage(
|
||||
imageUrl: data.image!.contains('http')
|
||||
? data.image!
|
||||
: '${Variables.baseUrl}/${data.image}',
|
||||
imageUrl: data.name!.contains('http')
|
||||
? data.name!
|
||||
: '${Variables.baseUrl}/${data.name}',
|
||||
fit: BoxFit.cover,
|
||||
width: double.infinity,
|
||||
height: 120,
|
||||
@@ -76,7 +75,7 @@ class ProductCard extends StatelessWidget {
|
||||
Align(
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
data.category?.name ?? '-',
|
||||
'-',
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
color: AppColors.grey,
|
||||
@@ -90,7 +89,7 @@ class ProductCard extends StatelessWidget {
|
||||
Align(
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
data.price!.toIntegerFromText.currencyFormatRp,
|
||||
data.price!.currencyFormatRp,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 12,
|
||||
|
||||
Reference in New Issue
Block a user