dev #1
@ -60,12 +60,12 @@ class PrintDataoutputs {
|
|||||||
bytes += generator.row([
|
bytes += generator.row([
|
||||||
PosColumn(
|
PosColumn(
|
||||||
text:
|
text:
|
||||||
'${product.product.price!.toIntegerFromText.currencyFormatRp} x ${product.quantity}',
|
'${product.product.price!.currencyFormatRp} x ${product.quantity}',
|
||||||
width: 8,
|
width: 8,
|
||||||
styles: const PosStyles(align: PosAlign.left),
|
styles: const PosStyles(align: PosAlign.left),
|
||||||
),
|
),
|
||||||
PosColumn(
|
PosColumn(
|
||||||
text: '${product.product.price!.toIntegerFromText * product.quantity}'
|
text: '${product.product.price! * product.quantity}'
|
||||||
.toIntegerFromText
|
.toIntegerFromText
|
||||||
.currencyFormatRp,
|
.currencyFormatRp,
|
||||||
width: 4,
|
width: 4,
|
||||||
@ -328,8 +328,7 @@ class PrintDataoutputs {
|
|||||||
styles: const PosStyles(align: PosAlign.left),
|
styles: const PosStyles(align: PosAlign.left),
|
||||||
),
|
),
|
||||||
PosColumn(
|
PosColumn(
|
||||||
text: (product.product.price!.toIntegerFromText * product.quantity)
|
text: (product.product.price! * product.quantity).currencyFormatRp,
|
||||||
.currencyFormatRp,
|
|
||||||
width: 4,
|
width: 4,
|
||||||
styles: const PosStyles(align: PosAlign.right),
|
styles: const PosStyles(align: PosAlign.right),
|
||||||
),
|
),
|
||||||
@ -398,8 +397,7 @@ class PrintDataoutputs {
|
|||||||
styles: const PosStyles(align: PosAlign.left),
|
styles: const PosStyles(align: PosAlign.left),
|
||||||
),
|
),
|
||||||
PosColumn(
|
PosColumn(
|
||||||
text: (products[0].product.price!.toIntegerFromText *
|
text: (products[0].product.price! * products[0].quantity)
|
||||||
products[0].quantity)
|
|
||||||
.currencyFormatRp,
|
.currencyFormatRp,
|
||||||
width: 4,
|
width: 4,
|
||||||
styles: const PosStyles(align: PosAlign.right),
|
styles: const PosStyles(align: PosAlign.right),
|
||||||
@ -430,8 +428,7 @@ class PrintDataoutputs {
|
|||||||
styles: const PosStyles(align: PosAlign.left),
|
styles: const PosStyles(align: PosAlign.left),
|
||||||
),
|
),
|
||||||
PosColumn(
|
PosColumn(
|
||||||
text: (products[0].product.price!.toIntegerFromText *
|
text: (products[0].product.price! * products[0].quantity)
|
||||||
products[0].quantity)
|
|
||||||
.currencyFormatRp,
|
.currencyFormatRp,
|
||||||
width: 4,
|
width: 4,
|
||||||
styles: const PosStyles(align: PosAlign.right),
|
styles: const PosStyles(align: PosAlign.right),
|
||||||
@ -610,8 +607,8 @@ class PrintDataoutputs {
|
|||||||
styles: const PosStyles(bold: true, align: PosAlign.left),
|
styles: const PosStyles(bold: true, align: PosAlign.left),
|
||||||
),
|
),
|
||||||
PosColumn(
|
PosColumn(
|
||||||
text: '${product.product.price!.toIntegerFromText * product.quantity}'
|
text:
|
||||||
.currencyFormatRpV2,
|
'${product.product.price! * product.quantity}'.currencyFormatRpV2,
|
||||||
width: 4,
|
width: 4,
|
||||||
styles: const PosStyles(bold: true, align: PosAlign.right),
|
styles: const PosStyles(bold: true, align: PosAlign.right),
|
||||||
),
|
),
|
||||||
@ -626,8 +623,7 @@ class PrintDataoutputs {
|
|||||||
final subTotalPrice = products.fold<int>(
|
final subTotalPrice = products.fold<int>(
|
||||||
0,
|
0,
|
||||||
(previousValue, element) =>
|
(previousValue, element) =>
|
||||||
previousValue +
|
previousValue + (element.product.price! * element.quantity));
|
||||||
(element.product.price!.toIntegerFromText * element.quantity));
|
|
||||||
bytes += generator.row([
|
bytes += generator.row([
|
||||||
PosColumn(
|
PosColumn(
|
||||||
text: 'Subtotal $totalQuantity Product',
|
text: 'Subtotal $totalQuantity Product',
|
||||||
@ -995,27 +991,27 @@ class PrintDataoutputs {
|
|||||||
: '--------------------------------',
|
: '--------------------------------',
|
||||||
styles: const PosStyles(bold: false, align: PosAlign.center));
|
styles: const PosStyles(bold: false, align: PosAlign.center));
|
||||||
bytes += generator.feed(1);
|
bytes += generator.feed(1);
|
||||||
final kitchenProducts =
|
// final kitchenProducts =
|
||||||
products.where((p) => p.product.printerType == 'kitchen');
|
// products.where((p) => p.product.printerType == 'kitchen');
|
||||||
for (final product in kitchenProducts) {
|
// for (final product in kitchenProducts) {
|
||||||
bytes += generator.text('${product.quantity} x ${product.product.name}',
|
// bytes += generator.text('${product.quantity} x ${product.product.name}',
|
||||||
styles: const PosStyles(
|
// styles: const PosStyles(
|
||||||
align: PosAlign.left,
|
// align: PosAlign.left,
|
||||||
bold: false,
|
// bold: false,
|
||||||
height: PosTextSize.size2,
|
// height: PosTextSize.size2,
|
||||||
width: PosTextSize.size1,
|
// width: PosTextSize.size1,
|
||||||
));
|
// ));
|
||||||
if (product.notes.isNotEmpty) {
|
// if (product.notes.isNotEmpty) {
|
||||||
bytes += generator.text(' Notes: ${product.notes}',
|
// bytes += generator.text(' Notes: ${product.notes}',
|
||||||
styles: const PosStyles(
|
// styles: const PosStyles(
|
||||||
align: PosAlign.left,
|
// align: PosAlign.left,
|
||||||
bold: false,
|
// bold: false,
|
||||||
height: PosTextSize.size1,
|
// height: PosTextSize.size1,
|
||||||
width: PosTextSize.size1,
|
// width: PosTextSize.size1,
|
||||||
fontType: PosFontType.fontA,
|
// fontType: PosFontType.fontA,
|
||||||
));
|
// ));
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
bytes += generator.feed(1);
|
bytes += generator.feed(1);
|
||||||
bytes += generator.text(
|
bytes += generator.text(
|
||||||
@ -1109,26 +1105,26 @@ class PrintDataoutputs {
|
|||||||
: '--------------------------------',
|
: '--------------------------------',
|
||||||
styles: const PosStyles(bold: false, align: PosAlign.center));
|
styles: const PosStyles(bold: false, align: PosAlign.center));
|
||||||
bytes += generator.feed(1);
|
bytes += generator.feed(1);
|
||||||
final barProducts = products.where((p) => p.product.printerType == 'bar');
|
// final barProducts = products.where((p) => p.product.printerType == 'bar');
|
||||||
for (final product in barProducts) {
|
// for (final product in barProducts) {
|
||||||
bytes += generator.text('${product.quantity} x ${product.product.name}',
|
// bytes += generator.text('${product.quantity} x ${product.product.name}',
|
||||||
styles: const PosStyles(
|
// styles: const PosStyles(
|
||||||
align: PosAlign.left,
|
// align: PosAlign.left,
|
||||||
bold: false,
|
// bold: false,
|
||||||
height: PosTextSize.size2,
|
// height: PosTextSize.size2,
|
||||||
width: PosTextSize.size1,
|
// width: PosTextSize.size1,
|
||||||
));
|
// ));
|
||||||
if (product.notes.isNotEmpty) {
|
// if (product.notes.isNotEmpty) {
|
||||||
bytes += generator.text(' Notes: ${product.notes}',
|
// bytes += generator.text(' Notes: ${product.notes}',
|
||||||
styles: const PosStyles(
|
// styles: const PosStyles(
|
||||||
align: PosAlign.left,
|
// align: PosAlign.left,
|
||||||
bold: false,
|
// bold: false,
|
||||||
height: PosTextSize.size1,
|
// height: PosTextSize.size1,
|
||||||
width: PosTextSize.size1,
|
// width: PosTextSize.size1,
|
||||||
fontType: PosFontType.fontA,
|
// fontType: PosFontType.fontA,
|
||||||
));
|
// ));
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
bytes += generator.feed(1);
|
bytes += generator.feed(1);
|
||||||
bytes += generator.text(
|
bytes += generator.text(
|
||||||
|
|||||||
@ -308,7 +308,7 @@ class ProductLocalDatasource {
|
|||||||
tableProduct,
|
tableProduct,
|
||||||
product.toLocalMap(),
|
product.toLocalMap(),
|
||||||
where: 'product_id = ?',
|
where: 'product_id = ?',
|
||||||
whereArgs: [product.productId],
|
whereArgs: [product.id],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -319,7 +319,7 @@ class ProductLocalDatasource {
|
|||||||
for (var product in products) {
|
for (var product in products) {
|
||||||
await db.insert(tableProduct, product.toLocalMap(),
|
await db.insert(tableProduct, product.toLocalMap(),
|
||||||
conflictAlgorithm: ConflictAlgorithm.replace);
|
conflictAlgorithm: ConflictAlgorithm.replace);
|
||||||
log('inserted success id: ${product.productId} | name: ${product.name} | price: ${product.price} | Printer Type ${product.printerType}');
|
log('inserted success id: ${product.id} | name: ${product.name} | price: ${product.price} ');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
import 'dart:developer';
|
import 'dart:developer';
|
||||||
|
|
||||||
import 'package:dartz/dartz.dart';
|
import 'package:dartz/dartz.dart';
|
||||||
|
import 'package:dio/dio.dart';
|
||||||
|
import 'package:enaklo_pos/core/network/dio_client.dart';
|
||||||
import 'package:enaklo_pos/data/models/request/product_request_model.dart';
|
import 'package:enaklo_pos/data/models/request/product_request_model.dart';
|
||||||
import 'package:enaklo_pos/data/models/response/add_product_response_model.dart';
|
import 'package:enaklo_pos/data/models/response/add_product_response_model.dart';
|
||||||
import 'package:enaklo_pos/data/models/response/product_response_model.dart';
|
import 'package:enaklo_pos/data/models/response/product_response_model.dart';
|
||||||
@ -10,19 +12,34 @@ import '../../core/constants/variables.dart';
|
|||||||
import 'auth_local_datasource.dart';
|
import 'auth_local_datasource.dart';
|
||||||
|
|
||||||
class ProductRemoteDatasource {
|
class ProductRemoteDatasource {
|
||||||
|
final Dio dio = DioClient.instance;
|
||||||
|
|
||||||
Future<Either<String, ProductResponseModel>> getProducts() async {
|
Future<Either<String, ProductResponseModel>> getProducts() async {
|
||||||
final url = Uri.parse('${Variables.baseUrl}/api/products');
|
try {
|
||||||
final authData = await AuthLocalDataSource().getAuthData();
|
final authData = await AuthLocalDataSource().getAuthData();
|
||||||
final response = await http.get(url, headers: {
|
final url = '${Variables.baseUrl}/api/v1/products';
|
||||||
'Authorization': 'Bearer ${authData.token}',
|
|
||||||
'Accept': 'application/json',
|
final response = await dio.get(
|
||||||
});
|
url,
|
||||||
log("Status Code: ${response.statusCode}");
|
options: Options(
|
||||||
log("Body: ${response.body}");
|
headers: {
|
||||||
if (response.statusCode == 200) {
|
'Authorization': 'Bearer ${authData.token}',
|
||||||
return Right(ProductResponseModel.fromJson(response.body));
|
'Accept': 'application/json',
|
||||||
} else {
|
},
|
||||||
return const Left('Failed to get products');
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
return Right(ProductResponseModel.fromMap(response.data));
|
||||||
|
} else {
|
||||||
|
return const Left('Failed to get products');
|
||||||
|
}
|
||||||
|
} on DioException catch (e) {
|
||||||
|
log("Dio error: ${e.message}");
|
||||||
|
return Left(e.response?.data['message'] ?? 'Gagal mengambil produk');
|
||||||
|
} catch (e) {
|
||||||
|
log("Unexpected error: $e");
|
||||||
|
return const Left('Unexpected error occurred');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,7 +74,7 @@ class ProductRemoteDatasource {
|
|||||||
final Map<String, String> headers = {
|
final Map<String, String> headers = {
|
||||||
'Authorization': 'Bearer ${authData.token}',
|
'Authorization': 'Bearer ${authData.token}',
|
||||||
};
|
};
|
||||||
|
|
||||||
log("Update Product Request Data: ${productRequestModel.toMap()}");
|
log("Update Product Request Data: ${productRequestModel.toMap()}");
|
||||||
log("Update Product ID: ${productRequestModel.id}");
|
log("Update Product ID: ${productRequestModel.id}");
|
||||||
log("Update Product Name: ${productRequestModel.name}");
|
log("Update Product Name: ${productRequestModel.name}");
|
||||||
@ -67,7 +84,7 @@ class ProductRemoteDatasource {
|
|||||||
log("Update Product Is Best Seller: ${productRequestModel.isBestSeller}");
|
log("Update Product Is Best Seller: ${productRequestModel.isBestSeller}");
|
||||||
log("Update Product Printer Type: ${productRequestModel.printerType}");
|
log("Update Product Printer Type: ${productRequestModel.printerType}");
|
||||||
log("Update Product Has Image: ${productRequestModel.image != null}");
|
log("Update Product Has Image: ${productRequestModel.image != null}");
|
||||||
|
|
||||||
var request = http.MultipartRequest(
|
var request = http.MultipartRequest(
|
||||||
'POST', Uri.parse('${Variables.baseUrl}/api/products/edit'));
|
'POST', Uri.parse('${Variables.baseUrl}/api/products/edit'));
|
||||||
request.fields.addAll(productRequestModel.toMap());
|
request.fields.addAll(productRequestModel.toMap());
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import 'dart:developer';
|
|||||||
import 'package:image_picker/image_picker.dart';
|
import 'package:image_picker/image_picker.dart';
|
||||||
|
|
||||||
class ProductRequestModel {
|
class ProductRequestModel {
|
||||||
final int? id;
|
final String? id;
|
||||||
final String name;
|
final String name;
|
||||||
final int price;
|
final int price;
|
||||||
final int stock;
|
final int stock;
|
||||||
@ -32,11 +32,11 @@ class ProductRequestModel {
|
|||||||
'is_best_seller': isBestSeller.toString(),
|
'is_best_seller': isBestSeller.toString(),
|
||||||
'printer_type': printerType ?? '',
|
'printer_type': printerType ?? '',
|
||||||
};
|
};
|
||||||
|
|
||||||
if (id != null) {
|
if (id != null) {
|
||||||
map['id'] = id.toString();
|
map['id'] = id.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,17 +1,15 @@
|
|||||||
// ignore_for_file: public_member_api_docs, sort_constructors_first
|
// ignore_for_file: public_member_api_docs, sort_constructors_first
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
|
|
||||||
import 'package:enaklo_pos/presentation/home/pages/confirm_payment_page.dart';
|
|
||||||
|
|
||||||
class ProductResponseModel {
|
class ProductResponseModel {
|
||||||
final String? status;
|
final bool? success;
|
||||||
final List<Product>? data;
|
final ProductData? data;
|
||||||
|
final dynamic errors;
|
||||||
|
|
||||||
ProductResponseModel({
|
ProductResponseModel({
|
||||||
this.status,
|
this.success,
|
||||||
this.data,
|
this.data,
|
||||||
|
this.errors,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory ProductResponseModel.fromJson(String str) =>
|
factory ProductResponseModel.fromJson(String str) =>
|
||||||
@ -21,50 +19,86 @@ class ProductResponseModel {
|
|||||||
|
|
||||||
factory ProductResponseModel.fromMap(Map<String, dynamic> json) =>
|
factory ProductResponseModel.fromMap(Map<String, dynamic> json) =>
|
||||||
ProductResponseModel(
|
ProductResponseModel(
|
||||||
status: json["status"],
|
success: json["success"],
|
||||||
data: json["data"] == null
|
data: json["data"] == null ? null : ProductData.fromMap(json["data"]),
|
||||||
? []
|
errors: json["errors"],
|
||||||
: List<Product>.from(json["data"]!.map((x) => Product.fromMap(x))),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> toMap() => {
|
Map<String, dynamic> toMap() => {
|
||||||
"status": status,
|
"success": success,
|
||||||
"data":
|
"data": data?.toMap(),
|
||||||
data == null ? [] : List<dynamic>.from(data!.map((x) => x.toMap())),
|
"errors": errors,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
class ProductData {
|
||||||
|
final List<Product>? products;
|
||||||
|
final int? totalCount;
|
||||||
|
final int? page;
|
||||||
|
final int? limit;
|
||||||
|
final int? totalPages;
|
||||||
|
|
||||||
|
ProductData({
|
||||||
|
this.products,
|
||||||
|
this.totalCount,
|
||||||
|
this.page,
|
||||||
|
this.limit,
|
||||||
|
this.totalPages,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory ProductData.fromMap(Map<String, dynamic> json) => ProductData(
|
||||||
|
products: json["products"] == null
|
||||||
|
? []
|
||||||
|
: List<Product>.from(
|
||||||
|
json["products"].map((x) => Product.fromMap(x))),
|
||||||
|
totalCount: json["total_count"],
|
||||||
|
page: json["page"],
|
||||||
|
limit: json["limit"],
|
||||||
|
totalPages: json["total_pages"],
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> toMap() => {
|
||||||
|
"products": products == null
|
||||||
|
? []
|
||||||
|
: List<dynamic>.from(products!.map((x) => x.toMap())),
|
||||||
|
"total_count": totalCount,
|
||||||
|
"page": page,
|
||||||
|
"limit": limit,
|
||||||
|
"total_pages": totalPages,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
class Product {
|
class Product {
|
||||||
final int? id;
|
final String? id;
|
||||||
final int? productId;
|
final String? organizationId;
|
||||||
final int? categoryId;
|
final String? categoryId;
|
||||||
|
final String? sku;
|
||||||
final String? name;
|
final String? name;
|
||||||
final String? description;
|
final String? description;
|
||||||
final String? image;
|
final int? price;
|
||||||
final String? price;
|
final int? cost;
|
||||||
final int? stock;
|
final String? businessType;
|
||||||
final int? status;
|
final Map<String, dynamic>? metadata;
|
||||||
final int? isFavorite;
|
final bool? isActive;
|
||||||
final DateTime? createdAt;
|
final DateTime? createdAt;
|
||||||
final DateTime? updatedAt;
|
final DateTime? updatedAt;
|
||||||
final Category? category;
|
final List<ProductVariant>? variants;
|
||||||
final String? printerType;
|
|
||||||
|
|
||||||
Product({
|
Product({
|
||||||
this.id,
|
this.id,
|
||||||
this.productId,
|
this.organizationId,
|
||||||
this.categoryId,
|
this.categoryId,
|
||||||
|
this.sku,
|
||||||
this.name,
|
this.name,
|
||||||
this.description,
|
this.description,
|
||||||
this.image,
|
|
||||||
this.price,
|
this.price,
|
||||||
this.stock,
|
this.cost,
|
||||||
this.status,
|
this.businessType,
|
||||||
this.isFavorite,
|
this.metadata,
|
||||||
|
this.isActive,
|
||||||
this.createdAt,
|
this.createdAt,
|
||||||
this.updatedAt,
|
this.updatedAt,
|
||||||
this.category,
|
this.variants,
|
||||||
this.printerType,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
factory Product.fromJson(String str) => Product.fromMap(json.decode(str));
|
factory Product.fromJson(String str) => Product.fromMap(json.decode(str));
|
||||||
@ -72,91 +106,94 @@ class Product {
|
|||||||
String toJson() => json.encode(toMap());
|
String toJson() => json.encode(toMap());
|
||||||
|
|
||||||
factory Product.fromMap(Map<String, dynamic> json) => Product(
|
factory Product.fromMap(Map<String, dynamic> json) => Product(
|
||||||
id: json["id"] is String ? int.tryParse(json["id"]) : json["id"],
|
id: json["id"],
|
||||||
productId: json["product_id"] is String ? int.tryParse(json["product_id"]) : json["product_id"],
|
organizationId: json["organization_id"],
|
||||||
categoryId: json["category_id"] is String
|
categoryId: json["category_id"],
|
||||||
? int.tryParse(json["category_id"])
|
sku: json["sku"],
|
||||||
: json["category_id"],
|
|
||||||
name: json["name"],
|
name: json["name"],
|
||||||
description: json["description"],
|
description: json["description"],
|
||||||
image: json["image"],
|
price: json["price"],
|
||||||
// price: json["price"].substring(0, json["price"].length - 3),
|
cost: json["cost"],
|
||||||
price: json["price"].toString().replaceAll('.00', ''),
|
businessType: json["business_type"],
|
||||||
stock: json["stock"] is String ? int.tryParse(json["stock"]) : json["stock"],
|
metadata: json["metadata"] ?? {},
|
||||||
status: json["status"] is String ? int.tryParse(json["status"]) : json["status"],
|
isActive: json["is_active"],
|
||||||
isFavorite: json["is_favorite"] is String ? int.tryParse(json["is_favorite"]) : json["is_favorite"],
|
|
||||||
createdAt: json["created_at"] == null
|
createdAt: json["created_at"] == null
|
||||||
? null
|
? null
|
||||||
: DateTime.parse(json["created_at"]),
|
: DateTime.parse(json["created_at"]),
|
||||||
updatedAt: json["updated_at"] == null
|
updatedAt: json["updated_at"] == null
|
||||||
? null
|
? null
|
||||||
: DateTime.parse(json["updated_at"]),
|
: DateTime.parse(json["updated_at"]),
|
||||||
category: json["category"] == null
|
variants: json["variants"] == null
|
||||||
? null
|
? []
|
||||||
: Category.fromMap(json["category"]),
|
: List<ProductVariant>.from(
|
||||||
printerType: json["printer_type"] ?? 'bar',
|
json["variants"].map((x) => ProductVariant.fromMap(x))),
|
||||||
);
|
);
|
||||||
|
|
||||||
factory Product.fromOrderMap(Map<String, dynamic> json) => Product(
|
factory Product.fromOrderMap(Map<String, dynamic> json) => Product(
|
||||||
id: json["id_product"],
|
id: json["id_product"],
|
||||||
price: json["price"].toString(),
|
price: json["price"],
|
||||||
);
|
);
|
||||||
|
|
||||||
factory Product.fromLocalMap(Map<String, dynamic> json) => Product(
|
factory Product.fromLocalMap(Map<String, dynamic> json) => Product(
|
||||||
id: json["id"],
|
id: json["id"],
|
||||||
productId: json["product_id"],
|
organizationId: json["organization_id"],
|
||||||
categoryId: json["categoryId"],
|
categoryId: json["category_id"],
|
||||||
category: Category(
|
sku: json["sku"],
|
||||||
id: json["categoryId"],
|
|
||||||
name: json["categoryName"],
|
|
||||||
),
|
|
||||||
name: json["name"],
|
name: json["name"],
|
||||||
description: json["description"],
|
description: json["description"],
|
||||||
image: json["image"],
|
|
||||||
price: json["price"],
|
price: json["price"],
|
||||||
stock: json["stock"],
|
cost: json["cost"],
|
||||||
status: json["status"],
|
businessType: json["business_type"],
|
||||||
isFavorite: json["isFavorite"],
|
metadata: json["metadata"] ?? {},
|
||||||
createdAt: json["createdAt"] == null
|
isActive: json["is_active"],
|
||||||
|
createdAt: json["created_at"] == null
|
||||||
? null
|
? null
|
||||||
: DateTime.parse(json["createdAt"]),
|
: DateTime.parse(json["created_at"]),
|
||||||
updatedAt: json["updatedAt"] == null
|
updatedAt: json["updated_at"] == null
|
||||||
? null
|
? null
|
||||||
: DateTime.parse(json["updatedAt"]),
|
: DateTime.parse(json["updated_at"]),
|
||||||
printerType: json["printer_type"] ?? 'bar',
|
variants: json["variants"] == null
|
||||||
|
? []
|
||||||
|
: List<ProductVariant>.from(
|
||||||
|
json["variants"].map((x) => ProductVariant.fromMap(x))),
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> toLocalMap() => {
|
Map<String, dynamic> toLocalMap() => {
|
||||||
"product_id": id,
|
"id": id,
|
||||||
"categoryId": categoryId,
|
"organization_id": organizationId,
|
||||||
"categoryName": category?.name,
|
"category_id": categoryId,
|
||||||
|
"sku": sku,
|
||||||
"name": name,
|
"name": name,
|
||||||
"description": description,
|
"description": description,
|
||||||
"image": image,
|
"price": price,
|
||||||
"price": price?.replaceAll(RegExp(r'\.0+$'), ''),
|
"cost": cost,
|
||||||
"stock": stock,
|
"business_type": businessType,
|
||||||
"status": status,
|
"metadata": metadata,
|
||||||
"isFavorite": isFavorite,
|
"is_active": isActive,
|
||||||
"createdAt": createdAt?.toIso8601String(),
|
"created_at": createdAt?.toIso8601String(),
|
||||||
"updatedAt": updatedAt?.toIso8601String(),
|
"updated_at": updatedAt?.toIso8601String(),
|
||||||
"printer_type": printerType,
|
"variants": variants == null
|
||||||
|
? []
|
||||||
|
: List<dynamic>.from(variants!.map((x) => x.toMap())),
|
||||||
};
|
};
|
||||||
|
|
||||||
Map<String, dynamic> toMap() => {
|
Map<String, dynamic> toMap() => {
|
||||||
"id": id,
|
"id": id,
|
||||||
"product_id": productId,
|
"organization_id": organizationId,
|
||||||
"category_id": categoryId,
|
"category_id": categoryId,
|
||||||
|
"sku": sku,
|
||||||
"name": name,
|
"name": name,
|
||||||
"description": description,
|
"description": description,
|
||||||
"image": image,
|
|
||||||
"price": price,
|
"price": price,
|
||||||
"stock": stock,
|
"cost": cost,
|
||||||
"status": status,
|
"business_type": businessType,
|
||||||
"is_favorite": isFavorite,
|
"metadata": metadata,
|
||||||
|
"is_active": isActive,
|
||||||
"created_at": createdAt?.toIso8601String(),
|
"created_at": createdAt?.toIso8601String(),
|
||||||
"updated_at": updatedAt?.toIso8601String(),
|
"updated_at": updatedAt?.toIso8601String(),
|
||||||
"category": category?.toMap(),
|
"variants": variants == null
|
||||||
"printer_type": printerType,
|
? []
|
||||||
|
: List<dynamic>.from(variants!.map((x) => x.toMap())),
|
||||||
};
|
};
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -164,70 +201,80 @@ class Product {
|
|||||||
if (identical(this, other)) return true;
|
if (identical(this, other)) return true;
|
||||||
|
|
||||||
return other.id == id &&
|
return other.id == id &&
|
||||||
other.productId == productId &&
|
other.organizationId == organizationId &&
|
||||||
other.categoryId == categoryId &&
|
other.categoryId == categoryId &&
|
||||||
|
other.sku == sku &&
|
||||||
other.name == name &&
|
other.name == name &&
|
||||||
other.description == description &&
|
other.description == description &&
|
||||||
other.image == image &&
|
|
||||||
other.price == price &&
|
other.price == price &&
|
||||||
other.stock == stock &&
|
other.cost == cost &&
|
||||||
other.status == status &&
|
other.businessType == businessType &&
|
||||||
other.isFavorite == isFavorite &&
|
other.metadata == metadata &&
|
||||||
|
other.isActive == isActive &&
|
||||||
other.createdAt == createdAt &&
|
other.createdAt == createdAt &&
|
||||||
other.updatedAt == updatedAt &&
|
other.updatedAt == updatedAt &&
|
||||||
other.category == category &&
|
_listEquals(other.variants, variants);
|
||||||
other.printerType == printerType;
|
}
|
||||||
|
|
||||||
|
bool _listEquals(List<ProductVariant>? a, List<ProductVariant>? b) {
|
||||||
|
if (a == null && b == null) return true;
|
||||||
|
if (a == null || b == null) return false;
|
||||||
|
if (a.length != b.length) return false;
|
||||||
|
for (int i = 0; i < a.length; i++) {
|
||||||
|
if (a[i] != b[i]) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode {
|
int get hashCode {
|
||||||
return id.hashCode ^
|
return id.hashCode ^
|
||||||
productId.hashCode ^
|
organizationId.hashCode ^
|
||||||
categoryId.hashCode ^
|
categoryId.hashCode ^
|
||||||
|
sku.hashCode ^
|
||||||
name.hashCode ^
|
name.hashCode ^
|
||||||
description.hashCode ^
|
description.hashCode ^
|
||||||
image.hashCode ^
|
|
||||||
price.hashCode ^
|
price.hashCode ^
|
||||||
stock.hashCode ^
|
cost.hashCode ^
|
||||||
status.hashCode ^
|
businessType.hashCode ^
|
||||||
isFavorite.hashCode ^
|
metadata.hashCode ^
|
||||||
|
isActive.hashCode ^
|
||||||
createdAt.hashCode ^
|
createdAt.hashCode ^
|
||||||
updatedAt.hashCode ^
|
updatedAt.hashCode ^
|
||||||
category.hashCode ^
|
variants.hashCode;
|
||||||
printerType.hashCode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Product copyWith({
|
Product copyWith({
|
||||||
int? id,
|
String? id,
|
||||||
int? productId,
|
String? organizationId,
|
||||||
int? categoryId,
|
String? categoryId,
|
||||||
|
String? sku,
|
||||||
String? name,
|
String? name,
|
||||||
String? description,
|
String? description,
|
||||||
String? image,
|
int? price,
|
||||||
String? price,
|
int? cost,
|
||||||
int? stock,
|
String? businessType,
|
||||||
int? status,
|
Map<String, dynamic>? metadata,
|
||||||
int? isFavorite,
|
bool? isActive,
|
||||||
DateTime? createdAt,
|
DateTime? createdAt,
|
||||||
DateTime? updatedAt,
|
DateTime? updatedAt,
|
||||||
Category? category,
|
List<ProductVariant>? variants,
|
||||||
String? printerType,
|
|
||||||
}) {
|
}) {
|
||||||
return Product(
|
return Product(
|
||||||
id: id ?? this.id,
|
id: id ?? this.id,
|
||||||
productId: productId ?? this.productId,
|
organizationId: organizationId ?? this.organizationId,
|
||||||
categoryId: categoryId ?? this.categoryId,
|
categoryId: categoryId ?? this.categoryId,
|
||||||
|
sku: sku ?? this.sku,
|
||||||
name: name ?? this.name,
|
name: name ?? this.name,
|
||||||
description: description ?? this.description,
|
description: description ?? this.description,
|
||||||
image: image ?? this.image,
|
|
||||||
price: price ?? this.price,
|
price: price ?? this.price,
|
||||||
stock: stock ?? this.stock,
|
cost: cost ?? this.cost,
|
||||||
status: status ?? this.status,
|
businessType: businessType ?? this.businessType,
|
||||||
isFavorite: isFavorite ?? this.isFavorite,
|
metadata: metadata ?? this.metadata,
|
||||||
|
isActive: isActive ?? this.isActive,
|
||||||
createdAt: createdAt ?? this.createdAt,
|
createdAt: createdAt ?? this.createdAt,
|
||||||
updatedAt: updatedAt ?? this.updatedAt,
|
updatedAt: updatedAt ?? this.updatedAt,
|
||||||
category: category ?? this.category,
|
variants: variants ?? this.variants,
|
||||||
printerType: printerType ?? this.printerType,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -297,3 +344,51 @@ class Category {
|
|||||||
updatedAt.hashCode;
|
updatedAt.hashCode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ProductVariant {
|
||||||
|
final String? id;
|
||||||
|
final String? productId;
|
||||||
|
final String? name;
|
||||||
|
final int? priceModifier;
|
||||||
|
final int? cost;
|
||||||
|
final Map<String, dynamic>? metadata;
|
||||||
|
final DateTime? createdAt;
|
||||||
|
final DateTime? updatedAt;
|
||||||
|
|
||||||
|
ProductVariant({
|
||||||
|
this.id,
|
||||||
|
this.productId,
|
||||||
|
this.name,
|
||||||
|
this.priceModifier,
|
||||||
|
this.cost,
|
||||||
|
this.metadata,
|
||||||
|
this.createdAt,
|
||||||
|
this.updatedAt,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory ProductVariant.fromMap(Map<String, dynamic> json) => ProductVariant(
|
||||||
|
id: json["id"],
|
||||||
|
productId: json["product_id"],
|
||||||
|
name: json["name"],
|
||||||
|
priceModifier: json["price_modifier"],
|
||||||
|
cost: json["cost"],
|
||||||
|
metadata: json["metadata"] ?? {},
|
||||||
|
createdAt: json["created_at"] == null
|
||||||
|
? null
|
||||||
|
: DateTime.parse(json["created_at"]),
|
||||||
|
updatedAt: json["updated_at"] == null
|
||||||
|
? null
|
||||||
|
: DateTime.parse(json["updated_at"]),
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> toMap() => {
|
||||||
|
"id": id,
|
||||||
|
"product_id": productId,
|
||||||
|
"name": name,
|
||||||
|
"price_modifier": priceModifier,
|
||||||
|
"cost": cost,
|
||||||
|
"metadata": metadata,
|
||||||
|
"created_at": createdAt?.toIso8601String(),
|
||||||
|
"updated_at": updatedAt?.toIso8601String(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import 'dart:developer';
|
import 'dart:developer';
|
||||||
import 'package:enaklo_pos/core/constants/theme.dart';
|
import 'package:enaklo_pos/core/constants/theme.dart';
|
||||||
|
import 'package:enaklo_pos/presentation/home/bloc/product_loader/product_loader_bloc.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:enaklo_pos/data/datasources/auth_local_datasource.dart';
|
import 'package:enaklo_pos/data/datasources/auth_local_datasource.dart';
|
||||||
import 'package:enaklo_pos/data/datasources/auth_remote_datasource.dart';
|
import 'package:enaklo_pos/data/datasources/auth_remote_datasource.dart';
|
||||||
@ -217,6 +218,9 @@ class _MyAppState extends State<MyApp> {
|
|||||||
BlocProvider(
|
BlocProvider(
|
||||||
create: (context) => AddOrderItemsBloc(OrderRemoteDatasource()),
|
create: (context) => AddOrderItemsBloc(OrderRemoteDatasource()),
|
||||||
),
|
),
|
||||||
|
BlocProvider(
|
||||||
|
create: (context) => ProductLoaderBloc(ProductRemoteDatasource()),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
child: MaterialApp(
|
child: MaterialApp(
|
||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false,
|
||||||
|
|||||||
@ -3,7 +3,6 @@ import 'dart:developer';
|
|||||||
import 'package:bloc/bloc.dart';
|
import 'package:bloc/bloc.dart';
|
||||||
import 'package:enaklo_pos/data/datasources/order_remote_datasource.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/presentation/home/models/product_quantity.dart';
|
||||||
import 'package:enaklo_pos/core/extensions/string_ext.dart';
|
|
||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
|
||||||
part 'add_order_items_event.dart';
|
part 'add_order_items_event.dart';
|
||||||
@ -12,24 +11,26 @@ part 'add_order_items_bloc.freezed.dart';
|
|||||||
|
|
||||||
class AddOrderItemsBloc extends Bloc<AddOrderItemsEvent, AddOrderItemsState> {
|
class AddOrderItemsBloc extends Bloc<AddOrderItemsEvent, AddOrderItemsState> {
|
||||||
final OrderRemoteDatasource orderRemoteDatasource;
|
final OrderRemoteDatasource orderRemoteDatasource;
|
||||||
|
|
||||||
AddOrderItemsBloc(
|
AddOrderItemsBloc(
|
||||||
this.orderRemoteDatasource,
|
this.orderRemoteDatasource,
|
||||||
) : super(const _Initial()) {
|
) : super(const _Initial()) {
|
||||||
on<_AddOrderItems>((event, emit) async {
|
on<_AddOrderItems>((event, emit) async {
|
||||||
emit(const _Loading());
|
emit(const _Loading());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Convert ProductQuantity list to the format expected by the API
|
// Convert ProductQuantity list to the format expected by the API
|
||||||
final orderItems = event.items.map((item) => {
|
final orderItems = event.items
|
||||||
'id_product': item.product.productId,
|
.map((item) => {
|
||||||
'quantity': item.quantity,
|
'id_product': item.product.id,
|
||||||
'price': item.product.price!.toIntegerFromText,
|
'quantity': item.quantity,
|
||||||
'notes': item.notes,
|
'price': item.product.price,
|
||||||
}).toList();
|
'notes': item.notes,
|
||||||
|
})
|
||||||
|
.toList();
|
||||||
|
|
||||||
log("Adding order items: ${orderItems.toString()}");
|
log("Adding order items: ${orderItems.toString()}");
|
||||||
|
|
||||||
final result = await orderRemoteDatasource.addOrderItems(
|
final result = await orderRemoteDatasource.addOrderItems(
|
||||||
event.orderId,
|
event.orderId,
|
||||||
orderItems,
|
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:bloc/bloc.dart';
|
||||||
import 'package:freezed_annotation/freezed_annotation.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/auth_local_datasource.dart';
|
||||||
import 'package:enaklo_pos/data/datasources/order_remote_datasource.dart';
|
import 'package:enaklo_pos/data/datasources/order_remote_datasource.dart';
|
||||||
import 'package:enaklo_pos/data/datasources/product_local_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>(
|
final subTotal = event.items.fold<int>(
|
||||||
0,
|
0,
|
||||||
(previousValue, element) =>
|
(previousValue, element) =>
|
||||||
previousValue +
|
previousValue + (element.product.price! * element.quantity));
|
||||||
(element.product.price!.toIntegerFromText * element.quantity));
|
|
||||||
// final total = subTotal + event.tax + event.serviceCharge - event.discount;
|
// final total = subTotal + event.tax + event.serviceCharge - event.discount;
|
||||||
|
|
||||||
final totalItem = event.items.fold<int>(
|
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 {
|
return {
|
||||||
'id_order': orderId,
|
'id_order': orderId,
|
||||||
'id_product': product.productId,
|
'id_product': product.id,
|
||||||
'quantity': quantity,
|
'quantity': quantity,
|
||||||
'price': product.price,
|
'price': product.price,
|
||||||
'notes': notes,
|
'notes': notes,
|
||||||
@ -47,11 +47,11 @@ class ProductQuantity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> toServerMap(int? orderId) {
|
Map<String, dynamic> toServerMap(int? orderId) {
|
||||||
log("toServerMap: ${product.productId}");
|
log("toServerMap: ${product.id}");
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'id_order': orderId ?? 0,
|
'id_order': orderId ?? 0,
|
||||||
'id_product': product.productId,
|
'id_product': product.id,
|
||||||
'quantity': quantity,
|
'quantity': quantity,
|
||||||
'price': product.price,
|
'price': product.price,
|
||||||
'notes': notes,
|
'notes': notes,
|
||||||
|
|||||||
@ -254,8 +254,7 @@ class _ConfirmPaymentPageState extends State<ConfirmPaymentPage> {
|
|||||||
0,
|
0,
|
||||||
(previousValue, element) =>
|
(previousValue, element) =>
|
||||||
previousValue +
|
previousValue +
|
||||||
(element.product.price!
|
(element.product.price! *
|
||||||
.toIntegerFromText *
|
|
||||||
element.quantity),
|
element.quantity),
|
||||||
));
|
));
|
||||||
return Text(
|
return Text(
|
||||||
@ -315,8 +314,7 @@ class _ConfirmPaymentPageState extends State<ConfirmPaymentPage> {
|
|||||||
0,
|
0,
|
||||||
(previousValue, element) =>
|
(previousValue, element) =>
|
||||||
previousValue +
|
previousValue +
|
||||||
(element.product.price!
|
(element.product.price! *
|
||||||
.toIntegerFromText *
|
|
||||||
element.quantity),
|
element.quantity),
|
||||||
));
|
));
|
||||||
|
|
||||||
@ -373,8 +371,7 @@ class _ConfirmPaymentPageState extends State<ConfirmPaymentPage> {
|
|||||||
0,
|
0,
|
||||||
(previousValue, element) =>
|
(previousValue, element) =>
|
||||||
previousValue +
|
previousValue +
|
||||||
(element.product.price!
|
(element.product.price! *
|
||||||
.toIntegerFromText *
|
|
||||||
element.quantity),
|
element.quantity),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -457,8 +454,7 @@ class _ConfirmPaymentPageState extends State<ConfirmPaymentPage> {
|
|||||||
0,
|
0,
|
||||||
(previousValue, element) =>
|
(previousValue, element) =>
|
||||||
previousValue +
|
previousValue +
|
||||||
(element.product.price!
|
(element.product.price! *
|
||||||
.toIntegerFromText *
|
|
||||||
element.quantity),
|
element.quantity),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -509,8 +505,7 @@ class _ConfirmPaymentPageState extends State<ConfirmPaymentPage> {
|
|||||||
0,
|
0,
|
||||||
(previousValue, element) =>
|
(previousValue, element) =>
|
||||||
previousValue +
|
previousValue +
|
||||||
(element.product.price!
|
(element.product.price! *
|
||||||
.toIntegerFromText *
|
|
||||||
element.quantity),
|
element.quantity),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -1262,8 +1257,7 @@ class _ConfirmPaymentPageState extends State<ConfirmPaymentPage> {
|
|||||||
0,
|
0,
|
||||||
(previousValue, element) =>
|
(previousValue, element) =>
|
||||||
previousValue +
|
previousValue +
|
||||||
(element.product.price!
|
(element.product.price! *
|
||||||
.toIntegerFromText *
|
|
||||||
element.quantity),
|
element.quantity),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -1566,10 +1560,8 @@ class _ConfirmPaymentPageState extends State<ConfirmPaymentPage> {
|
|||||||
0,
|
0,
|
||||||
(sum, item) =>
|
(sum, item) =>
|
||||||
sum +
|
sum +
|
||||||
(int.tryParse(item
|
(item.product
|
||||||
.product
|
.price ??
|
||||||
.price ??
|
|
||||||
'0') ??
|
|
||||||
0) *
|
0) *
|
||||||
item.quantity),
|
item.quantity),
|
||||||
);
|
);
|
||||||
|
|||||||
@ -282,8 +282,7 @@ class _ConfirmPaymentPageState extends State<ConfirmPaymentPage> {
|
|||||||
0,
|
0,
|
||||||
(previousValue, element) =>
|
(previousValue, element) =>
|
||||||
previousValue +
|
previousValue +
|
||||||
(element.product.price!
|
(element.product.price! *
|
||||||
.toIntegerFromText *
|
|
||||||
element.quantity),
|
element.quantity),
|
||||||
));
|
));
|
||||||
return Text(
|
return Text(
|
||||||
@ -340,8 +339,7 @@ class _ConfirmPaymentPageState extends State<ConfirmPaymentPage> {
|
|||||||
0,
|
0,
|
||||||
(previousValue, element) =>
|
(previousValue, element) =>
|
||||||
previousValue +
|
previousValue +
|
||||||
(element.product.price!
|
(element.product.price! *
|
||||||
.toIntegerFromText *
|
|
||||||
element.quantity),
|
element.quantity),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -417,8 +415,7 @@ class _ConfirmPaymentPageState extends State<ConfirmPaymentPage> {
|
|||||||
0,
|
0,
|
||||||
(previousValue, element) =>
|
(previousValue, element) =>
|
||||||
previousValue +
|
previousValue +
|
||||||
(element.product.price!
|
(element.product.price! *
|
||||||
.toIntegerFromText *
|
|
||||||
element.quantity),
|
element.quantity),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,16 +1,13 @@
|
|||||||
// ignore_for_file: public_member_api_docs, sort_constructors_first
|
// 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:enaklo_pos/presentation/home/widgets/home_right_title.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
import 'package:enaklo_pos/core/extensions/build_context_ext.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/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/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/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 'package:enaklo_pos/data/models/response/product_response_model.dart';
|
||||||
|
|
||||||
import '../../../core/assets/assets.gen.dart';
|
import '../../../core/assets/assets.gen.dart';
|
||||||
@ -49,12 +46,15 @@ class _HomePageState extends State<HomePage> {
|
|||||||
|
|
||||||
void _syncAndLoadProducts() {
|
void _syncAndLoadProducts() {
|
||||||
// Trigger sync from API first
|
// 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
|
// Also load local products initially in case sync fails or takes time
|
||||||
|
// context
|
||||||
|
// .read<LocalProductBloc>()
|
||||||
|
// .add(const LocalProductEvent.getLocalProduct());
|
||||||
context
|
context
|
||||||
.read<LocalProductBloc>()
|
.read<ProductLoaderBloc>()
|
||||||
.add(const LocalProductEvent.getLocalProduct());
|
.add(const ProductLoaderEvent.getProduct());
|
||||||
|
|
||||||
// Initialize checkout with tax and service charge settings
|
// Initialize checkout with tax and service charge settings
|
||||||
context.read<CheckoutBloc>().add(const CheckoutEvent.started());
|
context.read<CheckoutBloc>().add(const CheckoutEvent.started());
|
||||||
@ -83,7 +83,7 @@ class _HomePageState extends State<HomePage> {
|
|||||||
List<Product> products, int categoryId) {
|
List<Product> products, int categoryId) {
|
||||||
final filteredBySearch = _filterProducts(products);
|
final filteredBySearch = _filterProducts(products);
|
||||||
return filteredBySearch
|
return filteredBySearch
|
||||||
.where((element) => element.category?.id == categoryId)
|
.where((element) => element.price == categoryId)
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,451 +93,420 @@ class _HomePageState extends State<HomePage> {
|
|||||||
tag: 'confirmation_screen',
|
tag: 'confirmation_screen',
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
backgroundColor: AppColors.white,
|
backgroundColor: AppColors.white,
|
||||||
body: BlocListener<SyncProductBloc, SyncProductState>(
|
body: Row(
|
||||||
listener: (context, state) {
|
children: [
|
||||||
state.maybeWhen(
|
Expanded(
|
||||||
orElse: () {},
|
flex: 3,
|
||||||
error: (message) {
|
child: Align(
|
||||||
// If sync fails, still try to load local products
|
alignment: AlignmentDirectional.topStart,
|
||||||
context
|
child: Column(
|
||||||
.read<LocalProductBloc>()
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
.add(const LocalProductEvent.getLocalProduct());
|
children: [
|
||||||
},
|
HomeTitle(
|
||||||
loaded: (productResponseModel) async {
|
controller: searchController,
|
||||||
// Store context reference before async operations
|
onChanged: (value) {
|
||||||
final localProductBloc = context.read<LocalProductBloc>();
|
setState(() {
|
||||||
|
searchQuery = value;
|
||||||
// Save synced products to local database
|
});
|
||||||
await ProductLocalDatasource.instance.deleteAllProducts();
|
},
|
||||||
await ProductLocalDatasource.instance.insertProducts(
|
),
|
||||||
productResponseModel.data!,
|
BlocBuilder<ProductLoaderBloc, ProductLoaderState>(
|
||||||
);
|
builder: (context, state) {
|
||||||
// Then load local products to display
|
return Expanded(
|
||||||
localProductBloc.add(const LocalProductEvent.getLocalProduct());
|
child: CustomTabBarV2(
|
||||||
},
|
tabTitles: const [
|
||||||
);
|
'Semua',
|
||||||
},
|
'Makanan',
|
||||||
child: Row(
|
'Minuman',
|
||||||
children: [
|
'Paket'
|
||||||
Expanded(
|
],
|
||||||
flex: 3,
|
tabViews: [
|
||||||
child: Align(
|
// All Products Tab
|
||||||
alignment: AlignmentDirectional.topStart,
|
SizedBox(
|
||||||
child: Column(
|
child: state.maybeWhen(orElse: () {
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
return const Center(
|
||||||
children: [
|
child: CircularProgressIndicator(),
|
||||||
HomeTitle(
|
);
|
||||||
controller: searchController,
|
}, loading: () {
|
||||||
onChanged: (value) {
|
return const Center(
|
||||||
setState(() {
|
child: CircularProgressIndicator(),
|
||||||
searchQuery = value;
|
);
|
||||||
});
|
}, loaded: (products) {
|
||||||
},
|
final filteredProducts =
|
||||||
),
|
_filterProducts(products);
|
||||||
BlocBuilder<LocalProductBloc, LocalProductState>(
|
if (filteredProducts.isEmpty) {
|
||||||
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(
|
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(
|
return const Center(
|
||||||
child: CircularProgressIndicator(),
|
child: Text('No Items'),
|
||||||
);
|
);
|
||||||
}, loaded: (products) {
|
}
|
||||||
final filteredProducts =
|
final filteredProducts =
|
||||||
_filterProducts(products);
|
_filterProductsByCategory(products, 1);
|
||||||
if (filteredProducts.isEmpty) {
|
return filteredProducts.isEmpty
|
||||||
return const Center(
|
? const _IsEmpty()
|
||||||
child: Text('No Items Found'),
|
: GridView.builder(
|
||||||
);
|
itemCount: filteredProducts.length,
|
||||||
}
|
padding: const EdgeInsets.all(16),
|
||||||
return GridView.builder(
|
gridDelegate:
|
||||||
itemCount: filteredProducts.length,
|
SliverGridDelegateWithMaxCrossAxisExtent(
|
||||||
padding: const EdgeInsets.all(16),
|
maxCrossAxisExtent:
|
||||||
gridDelegate:
|
200, // Lebar maksimal tiap item (bisa kamu ubah)
|
||||||
SliverGridDelegateWithMaxCrossAxisExtent(
|
mainAxisSpacing: 30,
|
||||||
maxCrossAxisExtent: 180,
|
crossAxisSpacing: 30,
|
||||||
mainAxisSpacing: 30,
|
childAspectRatio: 0.85,
|
||||||
crossAxisSpacing: 30,
|
),
|
||||||
childAspectRatio: 180 / 240,
|
itemBuilder: (context, index) =>
|
||||||
),
|
ProductCard(
|
||||||
itemBuilder: (context, index) =>
|
data: filteredProducts[index],
|
||||||
ProductCard(
|
onCartButton: () {},
|
||||||
data: filteredProducts[index],
|
),
|
||||||
onCartButton: () {},
|
);
|
||||||
),
|
}),
|
||||||
);
|
),
|
||||||
}),
|
// Minuman Tab
|
||||||
),
|
SizedBox(
|
||||||
// Makanan Tab
|
child: state.maybeWhen(orElse: () {
|
||||||
SizedBox(
|
return const Center(
|
||||||
child: state.maybeWhen(orElse: () {
|
child: CircularProgressIndicator(),
|
||||||
|
);
|
||||||
|
}, loading: () {
|
||||||
|
return const Center(
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
);
|
||||||
|
}, loaded: (products) {
|
||||||
|
if (products.isEmpty) {
|
||||||
return const Center(
|
return const Center(
|
||||||
child: CircularProgressIndicator(),
|
child: Text('No Items'),
|
||||||
);
|
);
|
||||||
}, loading: () {
|
}
|
||||||
return const Center(
|
final filteredProducts =
|
||||||
child: CircularProgressIndicator(),
|
_filterProductsByCategory(products, 2);
|
||||||
);
|
return filteredProducts.isEmpty
|
||||||
}, loaded: (products) {
|
? const _IsEmpty()
|
||||||
if (products.isEmpty) {
|
: GridView.builder(
|
||||||
return const Center(
|
itemCount: filteredProducts.length,
|
||||||
child: Text('No Items'),
|
padding: const EdgeInsets.all(16),
|
||||||
);
|
gridDelegate:
|
||||||
}
|
SliverGridDelegateWithMaxCrossAxisExtent(
|
||||||
final filteredProducts =
|
maxCrossAxisExtent:
|
||||||
_filterProductsByCategory(products, 1);
|
200, // Lebar maksimal tiap item (bisa kamu ubah)
|
||||||
return filteredProducts.isEmpty
|
mainAxisSpacing: 30,
|
||||||
? const _IsEmpty()
|
crossAxisSpacing: 30,
|
||||||
: GridView.builder(
|
childAspectRatio: 0.85,
|
||||||
itemCount: filteredProducts.length,
|
),
|
||||||
padding: const EdgeInsets.all(16),
|
itemBuilder: (context, index) {
|
||||||
gridDelegate:
|
return ProductCard(
|
||||||
SliverGridDelegateWithMaxCrossAxisExtent(
|
|
||||||
maxCrossAxisExtent:
|
|
||||||
200, // Lebar maksimal tiap item (bisa kamu ubah)
|
|
||||||
mainAxisSpacing: 30,
|
|
||||||
crossAxisSpacing: 30,
|
|
||||||
childAspectRatio: 0.85,
|
|
||||||
),
|
|
||||||
itemBuilder: (context, index) =>
|
|
||||||
ProductCard(
|
|
||||||
data: filteredProducts[index],
|
data: filteredProducts[index],
|
||||||
onCartButton: () {},
|
onCartButton: () {},
|
||||||
),
|
);
|
||||||
);
|
},
|
||||||
}),
|
);
|
||||||
),
|
}),
|
||||||
// Minuman Tab
|
),
|
||||||
SizedBox(
|
// Snack Tab
|
||||||
child: state.maybeWhen(orElse: () {
|
SizedBox(
|
||||||
|
child: state.maybeWhen(orElse: () {
|
||||||
|
return const Center(
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
);
|
||||||
|
}, loading: () {
|
||||||
|
return const Center(
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
);
|
||||||
|
}, loaded: (products) {
|
||||||
|
if (products.isEmpty) {
|
||||||
return const Center(
|
return const Center(
|
||||||
child: CircularProgressIndicator(),
|
child: Text('No Items'),
|
||||||
);
|
);
|
||||||
}, loading: () {
|
}
|
||||||
return const Center(
|
final filteredProducts =
|
||||||
child: CircularProgressIndicator(),
|
_filterProductsByCategory(products, 3);
|
||||||
);
|
return filteredProducts.isEmpty
|
||||||
}, loaded: (products) {
|
? const _IsEmpty()
|
||||||
if (products.isEmpty) {
|
: GridView.builder(
|
||||||
return const Center(
|
itemCount: filteredProducts.length,
|
||||||
child: Text('No Items'),
|
padding: const EdgeInsets.all(16),
|
||||||
);
|
gridDelegate:
|
||||||
}
|
SliverGridDelegateWithMaxCrossAxisExtent(
|
||||||
final filteredProducts =
|
maxCrossAxisExtent:
|
||||||
_filterProductsByCategory(products, 2);
|
200, // Lebar maksimal tiap item (bisa kamu ubah)
|
||||||
return filteredProducts.isEmpty
|
mainAxisSpacing: 30,
|
||||||
? const _IsEmpty()
|
crossAxisSpacing: 30,
|
||||||
: GridView.builder(
|
childAspectRatio: 0.85,
|
||||||
itemCount: filteredProducts.length,
|
),
|
||||||
padding: const EdgeInsets.all(16),
|
itemBuilder: (context, index) {
|
||||||
gridDelegate:
|
return ProductCard(
|
||||||
SliverGridDelegateWithMaxCrossAxisExtent(
|
data: filteredProducts[index],
|
||||||
maxCrossAxisExtent:
|
onCartButton: () {},
|
||||||
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: () {},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
),
|
||||||
flex: 2,
|
Expanded(
|
||||||
child: Align(
|
flex: 2,
|
||||||
alignment: Alignment.topCenter,
|
child: Align(
|
||||||
child: Material(
|
alignment: Alignment.topCenter,
|
||||||
color: Colors.white,
|
child: Material(
|
||||||
child: Column(
|
color: Colors.white,
|
||||||
children: [
|
child: Column(
|
||||||
HomeRightTitle(
|
children: [
|
||||||
table: widget.table,
|
HomeRightTitle(
|
||||||
),
|
table: widget.table,
|
||||||
Padding(
|
),
|
||||||
padding: const EdgeInsets.all(16.0)
|
Padding(
|
||||||
.copyWith(bottom: 0, top: 27),
|
padding: const EdgeInsets.all(16.0)
|
||||||
child: Column(
|
.copyWith(bottom: 0, top: 27),
|
||||||
children: [
|
child: Column(
|
||||||
const Row(
|
children: [
|
||||||
mainAxisAlignment:
|
const Row(
|
||||||
MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Item',
|
'Item',
|
||||||
|
style: TextStyle(
|
||||||
|
color: AppColors.primary,
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: 130,
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: 50.0,
|
||||||
|
child: Text(
|
||||||
|
'Qty',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: AppColors.primary,
|
color: AppColors.primary,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(
|
),
|
||||||
width: 130,
|
SizedBox(
|
||||||
),
|
child: Text(
|
||||||
SizedBox(
|
'Price',
|
||||||
width: 50.0,
|
style: TextStyle(
|
||||||
child: Text(
|
color: AppColors.primary,
|
||||||
'Qty',
|
fontSize: 16,
|
||||||
style: TextStyle(
|
fontWeight: FontWeight.w600,
|
||||||
color: AppColors.primary,
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(
|
),
|
||||||
child: Text(
|
],
|
||||||
'Price',
|
),
|
||||||
style: TextStyle(
|
const SpaceHeight(8),
|
||||||
color: AppColors.primary,
|
const Divider(),
|
||||||
fontSize: 16,
|
],
|
||||||
fontWeight: FontWeight.w600,
|
),
|
||||||
),
|
),
|
||||||
|
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 SpaceHeight(8.0),
|
||||||
const Divider(),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
),
|
||||||
child: SingleChildScrollView(
|
Padding(
|
||||||
padding:
|
padding: const EdgeInsets.all(16.0).copyWith(top: 0),
|
||||||
const EdgeInsets.all(16.0).copyWith(top: 0),
|
child: Column(
|
||||||
child: Column(
|
children: [
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
const Divider(),
|
||||||
|
const SpaceHeight(16.0),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
|
const Text(
|
||||||
|
'Pajak',
|
||||||
|
style: TextStyle(
|
||||||
|
color: AppColors.black,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
BlocBuilder<CheckoutBloc, CheckoutState>(
|
BlocBuilder<CheckoutBloc, CheckoutState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
return state.maybeWhen(
|
final tax = state.maybeWhen(
|
||||||
orElse: () => const Center(
|
orElse: () => 0,
|
||||||
child: Text('No Items'),
|
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),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
const SpaceHeight(16.0),
|
||||||
),
|
Row(
|
||||||
Padding(
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
padding: const EdgeInsets.all(16.0).copyWith(top: 0),
|
children: [
|
||||||
child: Column(
|
const Text(
|
||||||
children: [
|
'Sub total',
|
||||||
const Divider(),
|
style: TextStyle(
|
||||||
const SpaceHeight(16.0),
|
color: AppColors.black,
|
||||||
Row(
|
fontWeight: FontWeight.bold,
|
||||||
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',
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
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:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:enaklo_pos/core/constants/variables.dart';
|
import 'package:enaklo_pos/core/constants/variables.dart';
|
||||||
import 'package:enaklo_pos/core/extensions/int_ext.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/bloc/checkout/checkout_bloc.dart';
|
||||||
import 'package:enaklo_pos/presentation/home/models/product_quantity.dart';
|
import 'package:enaklo_pos/presentation/home/models/product_quantity.dart';
|
||||||
|
|
||||||
@ -52,7 +51,7 @@ class _OrderMenuState extends State<OrderMenu> {
|
|||||||
child: ListTile(
|
child: ListTile(
|
||||||
contentPadding: EdgeInsets.zero,
|
contentPadding: EdgeInsets.zero,
|
||||||
leading: ClipRRect(
|
leading: ClipRRect(
|
||||||
borderRadius: BorderRadius.all(Radius.circular(50.0)),
|
borderRadius: BorderRadius.all(Radius.circular(8.0)),
|
||||||
child:
|
child:
|
||||||
// Icon(
|
// Icon(
|
||||||
// Icons.fastfood,
|
// Icons.fastfood,
|
||||||
@ -60,14 +59,23 @@ class _OrderMenuState extends State<OrderMenu> {
|
|||||||
// color: AppColors.primary,
|
// color: AppColors.primary,
|
||||||
// ),
|
// ),
|
||||||
CachedNetworkImage(
|
CachedNetworkImage(
|
||||||
imageUrl: widget.data.product.image!.contains('http')
|
imageUrl: widget.data.product.name!.contains('http')
|
||||||
? widget.data.product.image!
|
? widget.data.product.name!
|
||||||
: '${Variables.baseUrl}/${widget.data.product.image}',
|
: '${Variables.baseUrl}/${widget.data.product.name}',
|
||||||
width: 50.0,
|
width: 50.0,
|
||||||
height: 50.0,
|
height: 50.0,
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
errorWidget: (context, url, error) =>
|
errorWidget: (context, url, error) => Container(
|
||||||
const Icon(Icons.error),
|
width: 50.0,
|
||||||
|
height: 50.0,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: AppColors.disabled.withOpacity(0.4),
|
||||||
|
),
|
||||||
|
child: const Icon(
|
||||||
|
Icons.image,
|
||||||
|
color: AppColors.grey,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
title: Row(
|
title: Row(
|
||||||
@ -86,8 +94,7 @@ class _OrderMenuState extends State<OrderMenu> {
|
|||||||
subtitle: Column(
|
subtitle: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(widget.data.product.price!.toIntegerFromText
|
Text(widget.data.product.price!.currencyFormatRp),
|
||||||
.currencyFormatRp),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -139,8 +146,7 @@ class _OrderMenuState extends State<OrderMenu> {
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
width: 80.0,
|
width: 80.0,
|
||||||
child: Text(
|
child: Text(
|
||||||
(widget.data.product.price!.toIntegerFromText *
|
(widget.data.product.price! * widget.data.quantity)
|
||||||
widget.data.quantity)
|
|
||||||
.currencyFormatRp,
|
.currencyFormatRp,
|
||||||
textAlign: TextAlign.right,
|
textAlign: TextAlign.right,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
import 'package:cached_network_image/cached_network_image.dart';
|
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/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:enaklo_pos/core/constants/variables.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/data/models/response/product_response_model.dart';
|
||||||
import 'package:enaklo_pos/presentation/home/bloc/checkout/checkout_bloc.dart';
|
import 'package:enaklo_pos/presentation/home/bloc/checkout/checkout_bloc.dart';
|
||||||
|
|
||||||
@ -43,9 +42,9 @@ class ProductCard extends StatelessWidget {
|
|||||||
ClipRRect(
|
ClipRRect(
|
||||||
borderRadius: BorderRadius.all(Radius.circular(8.0)),
|
borderRadius: BorderRadius.all(Radius.circular(8.0)),
|
||||||
child: CachedNetworkImage(
|
child: CachedNetworkImage(
|
||||||
imageUrl: data.image!.contains('http')
|
imageUrl: data.name!.contains('http')
|
||||||
? data.image!
|
? data.name!
|
||||||
: '${Variables.baseUrl}/${data.image}',
|
: '${Variables.baseUrl}/${data.name}',
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
height: 120,
|
height: 120,
|
||||||
@ -76,7 +75,7 @@ class ProductCard extends StatelessWidget {
|
|||||||
Align(
|
Align(
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
child: Text(
|
child: Text(
|
||||||
data.category?.name ?? '-',
|
'-',
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
color: AppColors.grey,
|
color: AppColors.grey,
|
||||||
@ -90,7 +89,7 @@ class ProductCard extends StatelessWidget {
|
|||||||
Align(
|
Align(
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
child: Text(
|
child: Text(
|
||||||
data.price!.toIntegerFromText.currencyFormatRp,
|
data.price!.currencyFormatRp,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
|
|||||||
@ -62,7 +62,7 @@ class SalesListOrder extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
product.product.price ?? '',
|
(product.product.price ?? 0) as String,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
),
|
),
|
||||||
@ -76,7 +76,7 @@ class SalesListOrder extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
product.product.price ?? '',
|
(product.product.price ?? 0) as String,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
),
|
),
|
||||||
|
|||||||
@ -20,10 +20,10 @@ class AddProductBloc extends Bloc<AddProductEvent, AddProductState> {
|
|||||||
emit(const _Loading());
|
emit(const _Loading());
|
||||||
final requestData = ProductRequestModel(
|
final requestData = ProductRequestModel(
|
||||||
name: event.product.name!,
|
name: event.product.name!,
|
||||||
price: int.parse(event.product.price!),
|
price: event.product.price!,
|
||||||
stock: event.product.stock!,
|
stock: 0,
|
||||||
categoryId: event.product.categoryId!,
|
categoryId: 0,
|
||||||
isBestSeller: event.product.isFavorite!,
|
isBestSeller: 0,
|
||||||
image: event.image,
|
image: event.image,
|
||||||
);
|
);
|
||||||
log("requestData: ${requestData.toString()}");
|
log("requestData: ${requestData.toString()}");
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import 'package:bloc/bloc.dart';
|
import 'package:bloc/bloc.dart';
|
||||||
import 'package:enaklo_pos/data/datasources/product_remote_datasource.dart';
|
import 'package:enaklo_pos/data/datasources/product_remote_datasource.dart';
|
||||||
import 'package:enaklo_pos/data/models/response/product_response_model.dart';
|
import 'package:enaklo_pos/data/models/response/product_response_model.dart';
|
||||||
@ -19,7 +18,7 @@ class GetProductsBloc extends Bloc<GetProductsEvent, GetProductsState> {
|
|||||||
response.fold(
|
response.fold(
|
||||||
(l) => emit(_Error(l)),
|
(l) => emit(_Error(l)),
|
||||||
(r) {
|
(r) {
|
||||||
emit(_Success(r.data!));
|
emit(_Success(r.data!.products!));
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -19,57 +19,58 @@ class UpdateProductBloc extends Bloc<UpdateProductEvent, UpdateProductState> {
|
|||||||
) : super(const _Initial()) {
|
) : super(const _Initial()) {
|
||||||
on<_UpdateProduct>((event, emit) async {
|
on<_UpdateProduct>((event, emit) async {
|
||||||
emit(const _Loading());
|
emit(const _Loading());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Validate required fields
|
// Validate required fields
|
||||||
if (event.product.name == null || event.product.name!.isEmpty) {
|
if (event.product.name == null || event.product.name!.isEmpty) {
|
||||||
emit(_Error('Product name is required'));
|
emit(_Error('Product name is required'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.product.price == null || event.product.price!.isEmpty) {
|
if (event.product.price == null || event.product.price == 0) {
|
||||||
emit(_Error('Product price is required'));
|
emit(_Error('Product price is required'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.product.stock == null) {
|
// if (event.product.stock == null) {
|
||||||
emit(_Error('Product stock is required'));
|
// emit(_Error('Product stock is required'));
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (event.product.categoryId == null) {
|
if (event.product.categoryId == null) {
|
||||||
emit(_Error('Product category is required'));
|
emit(_Error('Product category is required'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse price safely
|
// Parse price safely
|
||||||
final price = int.tryParse(event.product.price!);
|
final price = event.product.price!;
|
||||||
if (price == null) {
|
if (price == 0) {
|
||||||
emit(_Error('Invalid price format'));
|
emit(_Error('Invalid price format'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final requestData = ProductRequestModel(
|
final requestData = ProductRequestModel(
|
||||||
id: event.product.id,
|
id: event.product.id,
|
||||||
name: event.product.name!,
|
name: event.product.name!,
|
||||||
price: price,
|
price: price,
|
||||||
stock: event.product.stock!,
|
stock: 0,
|
||||||
categoryId: event.product.categoryId!,
|
categoryId: 0,
|
||||||
isBestSeller: event.product.isFavorite ?? 0, // Default to 0 if null
|
isBestSeller: 0, // Default to 0 if null
|
||||||
image: event.image,
|
image: event.image,
|
||||||
printerType: event.product.printerType ?? 'kitchen', // Default to kitchen if null
|
printerType: 'kitchen', // Default to kitchen if null
|
||||||
);
|
);
|
||||||
|
|
||||||
log("Update requestData: ${requestData.toString()}");
|
log("Update requestData: ${requestData.toString()}");
|
||||||
log("Request map: ${requestData.toMap()}");
|
log("Request map: ${requestData.toMap()}");
|
||||||
|
|
||||||
final response = await datasource.updateProduct(requestData);
|
final response = await datasource.updateProduct(requestData);
|
||||||
response.fold(
|
response.fold(
|
||||||
(l) => emit(_Error(l)),
|
(l) => emit(_Error(l)),
|
||||||
(r) async {
|
(r) async {
|
||||||
// Update local database after successful API update
|
// Update local database after successful API update
|
||||||
try {
|
try {
|
||||||
await ProductLocalDatasource.instance.updateProduct(event.product);
|
await ProductLocalDatasource.instance
|
||||||
|
.updateProduct(event.product);
|
||||||
log("Local product updated successfully");
|
log("Local product updated successfully");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log("Error updating local product: $e");
|
log("Error updating local product: $e");
|
||||||
@ -83,4 +84,4 @@ class UpdateProductBloc extends Bloc<UpdateProductEvent, UpdateProductState> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,9 +28,9 @@ class DetailProductDialog extends StatelessWidget {
|
|||||||
ClipRRect(
|
ClipRRect(
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
child: CachedNetworkImage(
|
child: CachedNetworkImage(
|
||||||
imageUrl: product.image!.contains('http')
|
imageUrl: product.name!.contains('http')
|
||||||
? product.image!
|
? product.name!
|
||||||
: '${Variables.baseUrl}/${product.image}',
|
: '${Variables.baseUrl}/${product.name}',
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
width: 120,
|
width: 120,
|
||||||
height: 120,
|
height: 120,
|
||||||
@ -88,20 +88,20 @@ class DetailProductDialog extends StatelessWidget {
|
|||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
_buildItem(
|
_buildItem(
|
||||||
product.category?.name ?? "-",
|
"-",
|
||||||
"Kategori",
|
"Kategori",
|
||||||
),
|
),
|
||||||
|
// _buildItem(
|
||||||
|
// "${product.stock}",
|
||||||
|
// "Stok",
|
||||||
|
// valueColor: product.stock! < 50
|
||||||
|
// ? AppColors.red
|
||||||
|
// : product.stock! < 100
|
||||||
|
// ? Colors.yellow
|
||||||
|
// : AppColors.green,
|
||||||
|
// ),
|
||||||
_buildItem(
|
_buildItem(
|
||||||
"${product.stock}",
|
(product.price ?? 0).toString().currencyFormatRpV2,
|
||||||
"Stok",
|
|
||||||
valueColor: product.stock! < 50
|
|
||||||
? AppColors.red
|
|
||||||
: product.stock! < 100
|
|
||||||
? Colors.yellow
|
|
||||||
: AppColors.green,
|
|
||||||
),
|
|
||||||
_buildItem(
|
|
||||||
(product.price ?? "0").currencyFormatRpV2,
|
|
||||||
"Harga",
|
"Harga",
|
||||||
valueColor: AppColors.primary,
|
valueColor: AppColors.primary,
|
||||||
),
|
),
|
||||||
@ -142,11 +142,11 @@ class DetailProductDialog extends StatelessWidget {
|
|||||||
return Container(
|
return Container(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: product.status == 1 ? AppColors.green : AppColors.red,
|
color: product.isActive == true ? AppColors.green : AppColors.red,
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
product.status == 1 ? 'Aktif' : 'Tidak Aktif',
|
product.isActive == true ? 'Aktif' : 'Tidak Aktif',
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: Colors.white, fontSize: 12, fontWeight: FontWeight.w700),
|
color: Colors.white, fontSize: 12, fontWeight: FontWeight.w700),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -57,12 +57,12 @@ class _FormProductDialogState extends State<FormProductDialog> {
|
|||||||
// Pre-fill the form with existing product data
|
// Pre-fill the form with existing product data
|
||||||
final product = widget.product!;
|
final product = widget.product!;
|
||||||
nameController!.text = product.name ?? '';
|
nameController!.text = product.name ?? '';
|
||||||
priceValue = int.tryParse(product.price ?? '0') ?? 0;
|
priceValue = product.price ?? 0;
|
||||||
priceController!.text = priceValue.currencyFormatRp;
|
priceController!.text = priceValue.currencyFormatRp;
|
||||||
stockController!.text = (product.stock ?? 0).toString();
|
stockController!.text = '';
|
||||||
isBestSeller = product.isFavorite == 1;
|
isBestSeller = false;
|
||||||
printType = product.printerType ?? 'kitchen';
|
printType = 'kitchen';
|
||||||
imageUrl = product.image;
|
imageUrl = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
super.initState();
|
super.initState();
|
||||||
@ -129,72 +129,72 @@ class _FormProductDialogState extends State<FormProductDialog> {
|
|||||||
keyboardType: TextInputType.number,
|
keyboardType: TextInputType.number,
|
||||||
),
|
),
|
||||||
const SpaceHeight(20.0),
|
const SpaceHeight(20.0),
|
||||||
const Text(
|
// const Text(
|
||||||
"Kategori",
|
// "Kategori",
|
||||||
style: TextStyle(
|
// style: TextStyle(
|
||||||
fontSize: 14,
|
// fontSize: 14,
|
||||||
fontWeight: FontWeight.w700,
|
// fontWeight: FontWeight.w700,
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
const SpaceHeight(12.0),
|
// const SpaceHeight(12.0),
|
||||||
BlocBuilder<GetCategoriesBloc, GetCategoriesState>(
|
// BlocBuilder<GetCategoriesBloc, GetCategoriesState>(
|
||||||
builder: (context, state) {
|
// builder: (context, state) {
|
||||||
return state.maybeWhen(
|
// return state.maybeWhen(
|
||||||
orElse: () {
|
// orElse: () {
|
||||||
return const Center(
|
// return const Center(
|
||||||
child: CircularProgressIndicator(),
|
// child: CircularProgressIndicator(),
|
||||||
);
|
// );
|
||||||
},
|
// },
|
||||||
success: (categories) {
|
// success: (categories) {
|
||||||
// Set the selected category if in edit mode and not already set
|
// // Set the selected category if in edit mode and not already set
|
||||||
if (isEditMode &&
|
// if (isEditMode &&
|
||||||
selectCategory == null &&
|
// selectCategory == null &&
|
||||||
widget.product?.category != null) {
|
// widget.product?.category != null) {
|
||||||
try {
|
// try {
|
||||||
selectCategory = categories.firstWhere(
|
// selectCategory = categories.firstWhere(
|
||||||
(cat) => cat.id == widget.product!.category!.id,
|
// (cat) => cat.id == widget.product!.category!.id,
|
||||||
);
|
// );
|
||||||
} catch (e) {
|
// } catch (e) {
|
||||||
// If no exact match found, leave selectCategory as null
|
// // If no exact match found, leave selectCategory as null
|
||||||
// This will show the hint text instead
|
// // This will show the hint text instead
|
||||||
log("No matching category found for product category ID: ${widget.product!.category!.id}");
|
// log("No matching category found for product category ID: ${widget.product!.category!.id}");
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
return DropdownButtonHideUnderline(
|
// return DropdownButtonHideUnderline(
|
||||||
child: Container(
|
// child: Container(
|
||||||
decoration: BoxDecoration(
|
// decoration: BoxDecoration(
|
||||||
border: Border.all(color: Colors.grey),
|
// border: Border.all(color: Colors.grey),
|
||||||
borderRadius: BorderRadius.circular(12),
|
// borderRadius: BorderRadius.circular(12),
|
||||||
),
|
// ),
|
||||||
padding: const EdgeInsets.symmetric(
|
// padding: const EdgeInsets.symmetric(
|
||||||
horizontal: 10, vertical: 5),
|
// horizontal: 10, vertical: 5),
|
||||||
child: DropdownButton<CategoryModel>(
|
// child: DropdownButton<CategoryModel>(
|
||||||
value: selectCategory,
|
// value: selectCategory,
|
||||||
hint: const Text("Pilih Kategori"),
|
// hint: const Text("Pilih Kategori"),
|
||||||
isExpanded: true, // Untuk mengisi lebar container
|
// isExpanded: true, // Untuk mengisi lebar container
|
||||||
onChanged: (newValue) {
|
// onChanged: (newValue) {
|
||||||
if (newValue != null) {
|
// if (newValue != null) {
|
||||||
selectCategory = newValue;
|
// selectCategory = newValue;
|
||||||
setState(() {});
|
// setState(() {});
|
||||||
log("selectCategory: ${selectCategory!.name}");
|
// log("selectCategory: ${selectCategory!.name}");
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
items: categories
|
// items: categories
|
||||||
.map<DropdownMenuItem<CategoryModel>>(
|
// .map<DropdownMenuItem<CategoryModel>>(
|
||||||
(CategoryModel category) {
|
// (CategoryModel category) {
|
||||||
return DropdownMenuItem<CategoryModel>(
|
// return DropdownMenuItem<CategoryModel>(
|
||||||
value: category,
|
// value: category,
|
||||||
child: Text(category.name!),
|
// child: Text(category.name!),
|
||||||
);
|
// );
|
||||||
}).toList(),
|
// }).toList(),
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
);
|
// );
|
||||||
},
|
// },
|
||||||
);
|
// );
|
||||||
},
|
// },
|
||||||
),
|
// ),
|
||||||
const SpaceHeight(12.0),
|
const SpaceHeight(12.0),
|
||||||
const Text(
|
const Text(
|
||||||
"Tipe Print",
|
"Tipe Print",
|
||||||
@ -296,23 +296,23 @@ class _FormProductDialogState extends State<FormProductDialog> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
log("isBestSeller: $isBestSeller");
|
// log("isBestSeller: $isBestSeller");
|
||||||
final String name = nameController!.text;
|
// final String name = nameController!.text;
|
||||||
final int stock =
|
// final int stock =
|
||||||
stockController!.text.toIntegerFromText;
|
// stockController!.text.toIntegerFromText;
|
||||||
|
|
||||||
final Product product = widget.product!.copyWith(
|
// final Product product = widget.product!.copyWith(
|
||||||
name: name,
|
// name: name,
|
||||||
price: priceValue.toString(),
|
// price: priceValue.toString(),
|
||||||
stock: stock,
|
// stock: stock,
|
||||||
categoryId: selectCategory!.id!,
|
// categoryId: selectCategory!.id!,
|
||||||
isFavorite: isBestSeller ? 1 : 0,
|
// isFavorite: isBestSeller ? 1 : 0,
|
||||||
printerType: printType,
|
// printerType: printType,
|
||||||
);
|
// );
|
||||||
|
|
||||||
context.read<UpdateProductBloc>().add(
|
// context.read<UpdateProductBloc>().add(
|
||||||
UpdateProductEvent.updateProduct(
|
// UpdateProductEvent.updateProduct(
|
||||||
product, imageFile));
|
// product, imageFile));
|
||||||
},
|
},
|
||||||
label: 'Ubah Produk',
|
label: 'Ubah Produk',
|
||||||
);
|
);
|
||||||
@ -354,33 +354,33 @@ class _FormProductDialogState extends State<FormProductDialog> {
|
|||||||
orElse: () {
|
orElse: () {
|
||||||
return Button.filled(
|
return Button.filled(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (selectCategory == null) {
|
// if (selectCategory == null) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
// ScaffoldMessenger.of(context).showSnackBar(
|
||||||
const SnackBar(
|
// const SnackBar(
|
||||||
content: Text('Please select a category'),
|
// content: Text('Please select a category'),
|
||||||
backgroundColor: Colors.red,
|
// backgroundColor: Colors.red,
|
||||||
),
|
// ),
|
||||||
);
|
// );
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
log("isBestSeller: $isBestSeller");
|
// log("isBestSeller: $isBestSeller");
|
||||||
final String name = nameController!.text;
|
// final String name = nameController!.text;
|
||||||
|
|
||||||
final int stock =
|
// final int stock =
|
||||||
stockController!.text.toIntegerFromText;
|
// stockController!.text.toIntegerFromText;
|
||||||
final Product product = Product(
|
// final Product product = Product(
|
||||||
name: name,
|
// name: name,
|
||||||
price: priceValue.toString(),
|
// price: priceValue.toString(),
|
||||||
stock: stock,
|
// stock: stock,
|
||||||
categoryId: selectCategory!.id!,
|
// categoryId: selectCategory!.id!,
|
||||||
isFavorite: isBestSeller ? 1 : 0,
|
// isFavorite: isBestSeller ? 1 : 0,
|
||||||
image: imageFile!.path,
|
// image: imageFile!.path,
|
||||||
printerType: printType,
|
// printerType: printType,
|
||||||
);
|
// );
|
||||||
context.read<AddProductBloc>().add(
|
// context.read<AddProductBloc>().add(
|
||||||
AddProductEvent.addProduct(
|
// AddProductEvent.addProduct(
|
||||||
product, imageFile!));
|
// product, imageFile!));
|
||||||
},
|
},
|
||||||
label: 'Simpan Produk',
|
label: 'Simpan Produk',
|
||||||
);
|
);
|
||||||
@ -441,14 +441,14 @@ class _FormProductDialogOldState extends State<FormProductDialogOld> {
|
|||||||
|
|
||||||
if (isEditMode) {
|
if (isEditMode) {
|
||||||
// Pre-fill the form with existing product data
|
// Pre-fill the form with existing product data
|
||||||
final product = widget.product!;
|
// final product = widget.product!;
|
||||||
nameController!.text = product.name ?? '';
|
// nameController!.text = product.name ?? '';
|
||||||
priceValue = int.tryParse(product.price ?? '0') ?? 0;
|
// priceValue = int.tryParse(product.price ?? '0') ?? 0;
|
||||||
priceController!.text = priceValue.currencyFormatRp;
|
// priceController!.text = priceValue.currencyFormatRp;
|
||||||
stockController!.text = (product.stock ?? 0).toString();
|
// stockController!.text = (product.stock ?? 0).toString();
|
||||||
isBestSeller = product.isFavorite == 1;
|
// isBestSeller = product.isFavorite == 1;
|
||||||
printType = product.printerType ?? 'kitchen';
|
// printType = product.printerType ?? 'kitchen';
|
||||||
imageUrl = product.image;
|
// imageUrl = product.image;
|
||||||
}
|
}
|
||||||
|
|
||||||
super.initState();
|
super.initState();
|
||||||
@ -542,19 +542,19 @@ class _FormProductDialogOldState extends State<FormProductDialogOld> {
|
|||||||
},
|
},
|
||||||
success: (categories) {
|
success: (categories) {
|
||||||
// Set the selected category if in edit mode and not already set
|
// Set the selected category if in edit mode and not already set
|
||||||
if (isEditMode &&
|
// if (isEditMode &&
|
||||||
selectCategory == null &&
|
// selectCategory == null &&
|
||||||
widget.product?.category != null) {
|
// widget.product?.category != null) {
|
||||||
try {
|
// try {
|
||||||
selectCategory = categories.firstWhere(
|
// selectCategory = categories.firstWhere(
|
||||||
(cat) => cat.id == widget.product!.category!.id,
|
// (cat) => cat.id == widget.product!.category!.id,
|
||||||
);
|
// );
|
||||||
} catch (e) {
|
// } catch (e) {
|
||||||
// If no exact match found, leave selectCategory as null
|
// // If no exact match found, leave selectCategory as null
|
||||||
// This will show the hint text instead
|
// // This will show the hint text instead
|
||||||
log("No matching category found for product category ID: ${widget.product!.category!.id}");
|
// log("No matching category found for product category ID: ${widget.product!.category!.id}");
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
return DropdownButtonHideUnderline(
|
return DropdownButtonHideUnderline(
|
||||||
child: Container(
|
child: Container(
|
||||||
@ -696,18 +696,18 @@ class _FormProductDialogOldState extends State<FormProductDialogOld> {
|
|||||||
final int stock =
|
final int stock =
|
||||||
stockController!.text.toIntegerFromText;
|
stockController!.text.toIntegerFromText;
|
||||||
|
|
||||||
final Product product = widget.product!.copyWith(
|
// final Product product = widget.product!.copyWith(
|
||||||
name: name,
|
// name: name,
|
||||||
price: priceValue.toString(),
|
// price: priceValue.toString(),
|
||||||
stock: stock,
|
// stock: stock,
|
||||||
categoryId: selectCategory!.id!,
|
// categoryId: selectCategory!.id!,
|
||||||
isFavorite: isBestSeller ? 1 : 0,
|
// isFavorite: isBestSeller ? 1 : 0,
|
||||||
printerType: printType,
|
// printerType: printType,
|
||||||
);
|
// );
|
||||||
|
|
||||||
context.read<UpdateProductBloc>().add(
|
// context.read<UpdateProductBloc>().add(
|
||||||
UpdateProductEvent.updateProduct(
|
// UpdateProductEvent.updateProduct(
|
||||||
product, imageFile));
|
// product, imageFile));
|
||||||
},
|
},
|
||||||
label: 'Update Product',
|
label: 'Update Product',
|
||||||
);
|
);
|
||||||
@ -764,18 +764,18 @@ class _FormProductDialogOldState extends State<FormProductDialogOld> {
|
|||||||
|
|
||||||
final int stock =
|
final int stock =
|
||||||
stockController!.text.toIntegerFromText;
|
stockController!.text.toIntegerFromText;
|
||||||
final Product product = Product(
|
// final Product product = Product(
|
||||||
name: name,
|
// name: name,
|
||||||
price: priceValue.toString(),
|
// price: priceValue.toString(),
|
||||||
stock: stock,
|
// stock: stock,
|
||||||
categoryId: selectCategory!.id!,
|
// categoryId: selectCategory!.id!,
|
||||||
isFavorite: isBestSeller ? 1 : 0,
|
// isFavorite: isBestSeller ? 1 : 0,
|
||||||
image: imageFile!.path,
|
// image: imageFile!.path,
|
||||||
printerType: printType,
|
// printerType: printType,
|
||||||
);
|
// );
|
||||||
context.read<AddProductBloc>().add(
|
// context.read<AddProductBloc>().add(
|
||||||
AddProductEvent.addProduct(
|
// AddProductEvent.addProduct(
|
||||||
product, imageFile!));
|
// product, imageFile!));
|
||||||
},
|
},
|
||||||
label: 'Save Product',
|
label: 'Save Product',
|
||||||
);
|
);
|
||||||
|
|||||||
@ -62,7 +62,7 @@ class _SyncDataPageState extends State<SyncDataPage> {
|
|||||||
.deleteAllProducts();
|
.deleteAllProducts();
|
||||||
await ProductLocalDatasource.instance
|
await ProductLocalDatasource.instance
|
||||||
.insertProducts(
|
.insertProducts(
|
||||||
productResponseModel.data!,
|
productResponseModel.data!.products!,
|
||||||
);
|
);
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
const SnackBar(
|
const SnackBar(
|
||||||
|
|||||||
@ -36,9 +36,9 @@ class MenuProductItem extends StatelessWidget {
|
|||||||
child: ClipRRect(
|
child: ClipRRect(
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
child: CachedNetworkImage(
|
child: CachedNetworkImage(
|
||||||
imageUrl: data.image!.contains('http')
|
imageUrl: data.name!.contains('http')
|
||||||
? data.image!
|
? data.name!
|
||||||
: '${Variables.baseUrl}/${data.image}',
|
: '${Variables.baseUrl}/${data.name}',
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
errorWidget: (context, url, error) => Container(
|
errorWidget: (context, url, error) => Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
@ -67,7 +67,7 @@ class MenuProductItem extends StatelessWidget {
|
|||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
data.category?.name ?? "",
|
"",
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: AppColors.white,
|
color: AppColors.white,
|
||||||
fontSize: 10,
|
fontSize: 10,
|
||||||
@ -185,7 +185,7 @@ class MenuProductItemOld extends StatelessWidget {
|
|||||||
child: ClipRRect(
|
child: ClipRRect(
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(10.0)),
|
borderRadius: const BorderRadius.all(Radius.circular(10.0)),
|
||||||
child: CachedNetworkImage(
|
child: CachedNetworkImage(
|
||||||
imageUrl: '${Variables.baseUrl}/${data.image}',
|
imageUrl: '${Variables.baseUrl}/${data.name}',
|
||||||
placeholder: (context, url) =>
|
placeholder: (context, url) =>
|
||||||
const Center(child: CircularProgressIndicator()),
|
const Center(child: CircularProgressIndicator()),
|
||||||
errorWidget: (context, url, error) => const Icon(
|
errorWidget: (context, url, error) => const Icon(
|
||||||
@ -214,7 +214,7 @@ class MenuProductItemOld extends StatelessWidget {
|
|||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
data.category?.name ?? '-',
|
'-',
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
color: Colors.grey,
|
color: Colors.grey,
|
||||||
@ -260,7 +260,7 @@ class MenuProductItemOld extends StatelessWidget {
|
|||||||
Radius.circular(10.0)),
|
Radius.circular(10.0)),
|
||||||
child: CachedNetworkImage(
|
child: CachedNetworkImage(
|
||||||
imageUrl:
|
imageUrl:
|
||||||
'${Variables.baseUrl}${data.image}',
|
'${Variables.baseUrl}${data.name}',
|
||||||
placeholder: (context, url) =>
|
placeholder: (context, url) =>
|
||||||
const Center(
|
const Center(
|
||||||
child:
|
child:
|
||||||
@ -275,7 +275,7 @@ class MenuProductItemOld extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
const SpaceHeight(10.0),
|
const SpaceHeight(10.0),
|
||||||
Text(
|
Text(
|
||||||
data.category?.name ?? '-',
|
'-',
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
color: Colors.grey,
|
color: Colors.grey,
|
||||||
@ -291,7 +291,7 @@ class MenuProductItemOld extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
const SpaceHeight(10.0),
|
const SpaceHeight(10.0),
|
||||||
Text(
|
Text(
|
||||||
data.stock.toString(),
|
"data.stock.toString()",
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
color: Colors.grey,
|
color: Colors.grey,
|
||||||
|
|||||||
@ -26,7 +26,7 @@ class DraftOrderItem {
|
|||||||
Map<String, dynamic> toMapForLocal(int orderId) {
|
Map<String, dynamic> toMapForLocal(int orderId) {
|
||||||
return {
|
return {
|
||||||
'id_draft_order': orderId,
|
'id_draft_order': orderId,
|
||||||
'id_product': product.productId,
|
'id_product': product.id,
|
||||||
'quantity': quantity,
|
'quantity': quantity,
|
||||||
'price': product.price,
|
'price': product.price,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -46,7 +46,7 @@ class _PaymentTablePageState extends State<PaymentTablePage> {
|
|||||||
PaymentMethod? selectedPaymentMethod;
|
PaymentMethod? selectedPaymentMethod;
|
||||||
int totalPriceFinal = 0;
|
int totalPriceFinal = 0;
|
||||||
int discountAmountFinal = 0;
|
int discountAmountFinal = 0;
|
||||||
|
|
||||||
// Helper method to handle post-payment cleanup
|
// Helper method to handle post-payment cleanup
|
||||||
Future<void> _handlePostPaymentCleanup() async {
|
Future<void> _handlePostPaymentCleanup() async {
|
||||||
if (widget.table != null && widget.draftOrder?.id != null) {
|
if (widget.table != null && widget.draftOrder?.id != null) {
|
||||||
@ -60,21 +60,22 @@ class _PaymentTablePageState extends State<PaymentTablePage> {
|
|||||||
startTime: DateTime.now().toIso8601String(),
|
startTime: DateTime.now().toIso8601String(),
|
||||||
position: widget.table!.position,
|
position: widget.table!.position,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Update table status
|
// Update table status
|
||||||
await ProductLocalDatasource.instance.updateStatusTable(newTable);
|
await ProductLocalDatasource.instance.updateStatusTable(newTable);
|
||||||
|
|
||||||
// Remove draft order
|
// Remove draft order
|
||||||
await ProductLocalDatasource.instance.removeDraftOrderById(widget.draftOrder!.id!);
|
await ProductLocalDatasource.instance
|
||||||
|
.removeDraftOrderById(widget.draftOrder!.id!);
|
||||||
|
|
||||||
// Refresh table status
|
// Refresh table status
|
||||||
context.read<GetTableStatusBloc>().add(
|
context.read<GetTableStatusBloc>().add(
|
||||||
GetTableStatusEvent.getTablesStatus('all'),
|
GetTableStatusEvent.getTablesStatus('all'),
|
||||||
);
|
);
|
||||||
|
|
||||||
log("Table ${widget.table!.tableName} freed up and draft order removed");
|
log("Table ${widget.table!.tableName} freed up and draft order removed");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Safely navigate back - pop multiple times to get to table management
|
// Safely navigate back - pop multiple times to get to table management
|
||||||
// Pop the success dialog first, then the payment page
|
// Pop the success dialog first, then the payment page
|
||||||
if (Navigator.of(context).canPop()) {
|
if (Navigator.of(context).canPop()) {
|
||||||
@ -84,6 +85,7 @@ class _PaymentTablePageState extends State<PaymentTablePage> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
context
|
context
|
||||||
@ -93,7 +95,7 @@ class _PaymentTablePageState extends State<PaymentTablePage> {
|
|||||||
.read<PaymentMethodsBloc>()
|
.read<PaymentMethodsBloc>()
|
||||||
.add(PaymentMethodsEvent.fetchPaymentMethods());
|
.add(PaymentMethodsEvent.fetchPaymentMethods());
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
// Set a default payment method in case API fails
|
// Set a default payment method in case API fails
|
||||||
selectedPaymentMethod = PaymentMethod(
|
selectedPaymentMethod = PaymentMethod(
|
||||||
id: 1,
|
id: 1,
|
||||||
@ -135,7 +137,8 @@ class _PaymentTablePageState extends State<PaymentTablePage> {
|
|||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
title: const Text('Kembali'),
|
title: const Text('Kembali'),
|
||||||
content: const Text('Apakah Anda yakin ingin kembali? Order akan tetap tersimpan.'),
|
content: const Text(
|
||||||
|
'Apakah Anda yakin ingin kembali? Order akan tetap tersimpan.'),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
@ -146,7 +149,8 @@ class _PaymentTablePageState extends State<PaymentTablePage> {
|
|||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.of(context).pop(); // Close dialog
|
Navigator.of(context).pop(); // Close dialog
|
||||||
Navigator.of(context).pop(); // Go back to previous page
|
Navigator.of(context)
|
||||||
|
.pop(); // Go back to previous page
|
||||||
},
|
},
|
||||||
child: const Text('Ya'),
|
child: const Text('Ya'),
|
||||||
),
|
),
|
||||||
@ -157,7 +161,8 @@ class _PaymentTablePageState extends State<PaymentTablePage> {
|
|||||||
},
|
},
|
||||||
child: const Text(
|
child: const Text(
|
||||||
'Kembali',
|
'Kembali',
|
||||||
style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
|
style: TextStyle(
|
||||||
|
color: Colors.white, fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -251,7 +256,8 @@ class _PaymentTablePageState extends State<PaymentTablePage> {
|
|||||||
serviceCharge,
|
serviceCharge,
|
||||||
totalQuantity,
|
totalQuantity,
|
||||||
totalPrice,
|
totalPrice,
|
||||||
draftName, orderType) {
|
draftName,
|
||||||
|
orderType) {
|
||||||
if (products.isEmpty) {
|
if (products.isEmpty) {
|
||||||
return const Center(
|
return const Center(
|
||||||
child: Text('No Items'),
|
child: Text('No Items'),
|
||||||
@ -294,13 +300,13 @@ class _PaymentTablePageState extends State<PaymentTablePage> {
|
|||||||
serviceCharge,
|
serviceCharge,
|
||||||
totalQuantity,
|
totalQuantity,
|
||||||
totalPrice,
|
totalPrice,
|
||||||
draftName, orderType) =>
|
draftName,
|
||||||
|
orderType) =>
|
||||||
products.fold(
|
products.fold(
|
||||||
0,
|
0,
|
||||||
(previousValue, element) =>
|
(previousValue, element) =>
|
||||||
previousValue +
|
previousValue +
|
||||||
(element.product.price!
|
(element.product.price! *
|
||||||
.toIntegerFromText *
|
|
||||||
element.quantity),
|
element.quantity),
|
||||||
));
|
));
|
||||||
return Text(
|
return Text(
|
||||||
@ -374,7 +380,8 @@ class _PaymentTablePageState extends State<PaymentTablePage> {
|
|||||||
serviceCharge,
|
serviceCharge,
|
||||||
totalQuantity,
|
totalQuantity,
|
||||||
totalPrice,
|
totalPrice,
|
||||||
draftName, orderType) =>
|
draftName,
|
||||||
|
orderType) =>
|
||||||
tax,
|
tax,
|
||||||
);
|
);
|
||||||
final price = state.maybeWhen(
|
final price = state.maybeWhen(
|
||||||
@ -387,13 +394,13 @@ class _PaymentTablePageState extends State<PaymentTablePage> {
|
|||||||
serviceCharge,
|
serviceCharge,
|
||||||
totalQuantity,
|
totalQuantity,
|
||||||
totalPrice,
|
totalPrice,
|
||||||
draftName, orderType) =>
|
draftName,
|
||||||
|
orderType) =>
|
||||||
products.fold(
|
products.fold(
|
||||||
0,
|
0,
|
||||||
(previousValue, element) =>
|
(previousValue, element) =>
|
||||||
previousValue +
|
previousValue +
|
||||||
(element.product.price!
|
(element.product.price! *
|
||||||
.toIntegerFromText *
|
|
||||||
element.quantity),
|
element.quantity),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -408,7 +415,8 @@ class _PaymentTablePageState extends State<PaymentTablePage> {
|
|||||||
serviceCharge,
|
serviceCharge,
|
||||||
totalQuantity,
|
totalQuantity,
|
||||||
totalPrice,
|
totalPrice,
|
||||||
draftName, orderType) {
|
draftName,
|
||||||
|
orderType) {
|
||||||
return discountAmount;
|
return discountAmount;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -446,7 +454,8 @@ class _PaymentTablePageState extends State<PaymentTablePage> {
|
|||||||
serviceCharge,
|
serviceCharge,
|
||||||
totalQuantity,
|
totalQuantity,
|
||||||
totalPrice,
|
totalPrice,
|
||||||
draftName, orderType) =>
|
draftName,
|
||||||
|
orderType) =>
|
||||||
tax,
|
tax,
|
||||||
);
|
);
|
||||||
final price = state.maybeWhen(
|
final price = state.maybeWhen(
|
||||||
@ -459,13 +468,13 @@ class _PaymentTablePageState extends State<PaymentTablePage> {
|
|||||||
serviceCharge,
|
serviceCharge,
|
||||||
totalQuantity,
|
totalQuantity,
|
||||||
totalPrice,
|
totalPrice,
|
||||||
draftName, orderType) =>
|
draftName,
|
||||||
|
orderType) =>
|
||||||
products.fold(
|
products.fold(
|
||||||
0,
|
0,
|
||||||
(previousValue, element) =>
|
(previousValue, element) =>
|
||||||
previousValue +
|
previousValue +
|
||||||
(element.product.price!
|
(element.product.price! *
|
||||||
.toIntegerFromText *
|
|
||||||
element.quantity),
|
element.quantity),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -480,7 +489,8 @@ class _PaymentTablePageState extends State<PaymentTablePage> {
|
|||||||
serviceCharge,
|
serviceCharge,
|
||||||
totalQuantity,
|
totalQuantity,
|
||||||
totalPrice,
|
totalPrice,
|
||||||
draftName, orderType) {
|
draftName,
|
||||||
|
orderType) {
|
||||||
return discountAmount;
|
return discountAmount;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -494,7 +504,8 @@ class _PaymentTablePageState extends State<PaymentTablePage> {
|
|||||||
serviceCharge,
|
serviceCharge,
|
||||||
totalQuantity,
|
totalQuantity,
|
||||||
totalPrice,
|
totalPrice,
|
||||||
draftName, orderType) =>
|
draftName,
|
||||||
|
orderType) =>
|
||||||
serviceCharge,
|
serviceCharge,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -536,13 +547,13 @@ class _PaymentTablePageState extends State<PaymentTablePage> {
|
|||||||
serviceCharge,
|
serviceCharge,
|
||||||
totalQuantity,
|
totalQuantity,
|
||||||
totalPrice,
|
totalPrice,
|
||||||
draftName, orderType) =>
|
draftName,
|
||||||
|
orderType) =>
|
||||||
products.fold(
|
products.fold(
|
||||||
0,
|
0,
|
||||||
(previousValue, element) =>
|
(previousValue, element) =>
|
||||||
previousValue +
|
previousValue +
|
||||||
(element.product.price!
|
(element.product.price! *
|
||||||
.toIntegerFromText *
|
|
||||||
element.quantity),
|
element.quantity),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -557,7 +568,8 @@ class _PaymentTablePageState extends State<PaymentTablePage> {
|
|||||||
serviceCharge,
|
serviceCharge,
|
||||||
totalQuantity,
|
totalQuantity,
|
||||||
totalPrice,
|
totalPrice,
|
||||||
draftName, orderType) {
|
draftName,
|
||||||
|
orderType) {
|
||||||
return discountAmount;
|
return discountAmount;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -571,7 +583,8 @@ class _PaymentTablePageState extends State<PaymentTablePage> {
|
|||||||
serviceCharge,
|
serviceCharge,
|
||||||
totalQuantity,
|
totalQuantity,
|
||||||
totalPrice,
|
totalPrice,
|
||||||
draftName, orderType) =>
|
draftName,
|
||||||
|
orderType) =>
|
||||||
serviceCharge,
|
serviceCharge,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -585,7 +598,8 @@ class _PaymentTablePageState extends State<PaymentTablePage> {
|
|||||||
serviceCharge,
|
serviceCharge,
|
||||||
totalQuantity,
|
totalQuantity,
|
||||||
totalPrice,
|
totalPrice,
|
||||||
draftName, orderType) =>
|
draftName,
|
||||||
|
orderType) =>
|
||||||
tax,
|
tax,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -666,7 +680,8 @@ class _PaymentTablePageState extends State<PaymentTablePage> {
|
|||||||
serviceCharge,
|
serviceCharge,
|
||||||
totalQuantity,
|
totalQuantity,
|
||||||
totalPrice,
|
totalPrice,
|
||||||
draftName, orderType) {
|
draftName,
|
||||||
|
orderType) {
|
||||||
customerController.text = draftName;
|
customerController.text = draftName;
|
||||||
return TextFormField(
|
return TextFormField(
|
||||||
readOnly: true,
|
readOnly: true,
|
||||||
@ -699,7 +714,8 @@ class _PaymentTablePageState extends State<PaymentTablePage> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SpaceHeight(12.0),
|
const SpaceHeight(12.0),
|
||||||
BlocBuilder<PaymentMethodsBloc, PaymentMethodsState>(
|
BlocBuilder<PaymentMethodsBloc,
|
||||||
|
PaymentMethodsState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
return state.maybeWhen(
|
return state.maybeWhen(
|
||||||
orElse: () => const Center(
|
orElse: () => const Center(
|
||||||
@ -717,14 +733,16 @@ class _PaymentTablePageState extends State<PaymentTablePage> {
|
|||||||
error: (message) => Column(
|
error: (message) => Column(
|
||||||
children: [
|
children: [
|
||||||
Center(
|
Center(
|
||||||
child: Text('Error loading payment methods: $message'),
|
child: Text(
|
||||||
|
'Error loading payment methods: $message'),
|
||||||
),
|
),
|
||||||
const SpaceHeight(16.0),
|
const SpaceHeight(16.0),
|
||||||
Button.filled(
|
Button.filled(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context
|
context
|
||||||
.read<PaymentMethodsBloc>()
|
.read<PaymentMethodsBloc>()
|
||||||
.add(PaymentMethodsEvent.fetchPaymentMethods());
|
.add(PaymentMethodsEvent
|
||||||
|
.fetchPaymentMethods());
|
||||||
},
|
},
|
||||||
label: 'Retry',
|
label: 'Retry',
|
||||||
),
|
),
|
||||||
@ -739,32 +757,39 @@ class _PaymentTablePageState extends State<PaymentTablePage> {
|
|||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
const Center(
|
const Center(
|
||||||
child: Text('No payment methods available'),
|
child: Text(
|
||||||
|
'No payment methods available'),
|
||||||
),
|
),
|
||||||
const SpaceHeight(16.0),
|
const SpaceHeight(16.0),
|
||||||
Button.filled(
|
Button.filled(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context
|
context
|
||||||
.read<PaymentMethodsBloc>()
|
.read<PaymentMethodsBloc>()
|
||||||
.add(PaymentMethodsEvent.fetchPaymentMethods());
|
.add(PaymentMethodsEvent
|
||||||
|
.fetchPaymentMethods());
|
||||||
},
|
},
|
||||||
label: 'Retry',
|
label: 'Retry',
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set default selected payment method if none selected or if current selection is not in the list
|
// Set default selected payment method if none selected or if current selection is not in the list
|
||||||
if (selectedPaymentMethod == null ||
|
if (selectedPaymentMethod == null ||
|
||||||
!paymentMethods.any((method) => method.id == selectedPaymentMethod?.id)) {
|
!paymentMethods.any((method) =>
|
||||||
selectedPaymentMethod = paymentMethods.first;
|
method.id ==
|
||||||
|
selectedPaymentMethod?.id)) {
|
||||||
|
selectedPaymentMethod =
|
||||||
|
paymentMethods.first;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Wrap(
|
return Wrap(
|
||||||
spacing: 12.0,
|
spacing: 12.0,
|
||||||
runSpacing: 8.0,
|
runSpacing: 8.0,
|
||||||
children: paymentMethods.map((method) {
|
children: paymentMethods.map((method) {
|
||||||
final isSelected = selectedPaymentMethod?.id == method.id;
|
final isSelected =
|
||||||
|
selectedPaymentMethod?.id ==
|
||||||
|
method.id;
|
||||||
return Container(
|
return Container(
|
||||||
constraints: const BoxConstraints(
|
constraints: const BoxConstraints(
|
||||||
minWidth: 120.0,
|
minWidth: 120.0,
|
||||||
@ -775,31 +800,44 @@ class _PaymentTablePageState extends State<PaymentTablePage> {
|
|||||||
color: AppColors.primary,
|
color: AppColors.primary,
|
||||||
width: 2.0,
|
width: 2.0,
|
||||||
),
|
),
|
||||||
borderRadius: BorderRadius.circular(8.0),
|
borderRadius:
|
||||||
|
BorderRadius.circular(
|
||||||
|
8.0),
|
||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
child: Tooltip(
|
child: Tooltip(
|
||||||
message: method.description ?? 'No description available',
|
message: method.description ??
|
||||||
|
'No description available',
|
||||||
child: isSelected
|
child: isSelected
|
||||||
? Button.filled(
|
? Button.filled(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
height: 50.0,
|
height: 50.0,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
selectedPaymentMethod = method;
|
selectedPaymentMethod =
|
||||||
|
method;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
label: method.name?.isNotEmpty == true ? method.name! : 'Unknown',
|
label: method.name
|
||||||
|
?.isNotEmpty ==
|
||||||
|
true
|
||||||
|
? method.name!
|
||||||
|
: 'Unknown',
|
||||||
)
|
)
|
||||||
: Button.outlined(
|
: Button.outlined(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
height: 50.0,
|
height: 50.0,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
selectedPaymentMethod = method;
|
selectedPaymentMethod =
|
||||||
|
method;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
label: method.name?.isNotEmpty == true ? method.name! : 'Unknown',
|
label: method.name
|
||||||
|
?.isNotEmpty ==
|
||||||
|
true
|
||||||
|
? method.name!
|
||||||
|
: 'Unknown',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -881,30 +919,41 @@ class _PaymentTablePageState extends State<PaymentTablePage> {
|
|||||||
builder: (context) => AlertDialog(
|
builder: (context) => AlertDialog(
|
||||||
title: Row(
|
title: Row(
|
||||||
children: [
|
children: [
|
||||||
Icon(Icons.warning, color: AppColors.red),
|
Icon(Icons.warning,
|
||||||
|
color: AppColors.red),
|
||||||
SizedBox(width: 8),
|
SizedBox(width: 8),
|
||||||
Text('Batalkan Pesanan?'),
|
Text('Batalkan Pesanan?'),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
content: Text(
|
content: Text(
|
||||||
'Apakah anda yakin ingin membatalkan pesanan untuk meja ${widget.table?.tableName ?? "ini"}?\n\nPesanan akan dihapus secara permanen.'),
|
'Apakah anda yakin ingin membatalkan pesanan untuk meja ${widget.table?.tableName ?? "ini"}?\n\nPesanan akan dihapus secara permanen.'),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.pop(context),
|
onPressed: () =>
|
||||||
child: Text('Tidak',
|
Navigator.pop(context),
|
||||||
style: TextStyle(color: AppColors.primary)),
|
child: Text('Tidak',
|
||||||
|
style: TextStyle(
|
||||||
|
color:
|
||||||
|
AppColors.primary)),
|
||||||
),
|
),
|
||||||
BlocListener<StatusTableBloc, StatusTableState>(
|
BlocListener<StatusTableBloc,
|
||||||
|
StatusTableState>(
|
||||||
listener: (context, state) {
|
listener: (context, state) {
|
||||||
state.maybeWhen(
|
state.maybeWhen(
|
||||||
orElse: () {},
|
orElse: () {},
|
||||||
success: () {
|
success: () {
|
||||||
Navigator.pop(context); // Close void dialog
|
Navigator.pop(
|
||||||
Navigator.pop(context); // Close payment page
|
context); // Close void dialog
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
Navigator.pop(
|
||||||
|
context); // Close payment page
|
||||||
|
ScaffoldMessenger.of(
|
||||||
|
context)
|
||||||
|
.showSnackBar(
|
||||||
const SnackBar(
|
const SnackBar(
|
||||||
content: Text('Pesanan berhasil dibatalkan'),
|
content: Text(
|
||||||
backgroundColor: AppColors.primary,
|
'Pesanan berhasil dibatalkan'),
|
||||||
|
backgroundColor:
|
||||||
|
AppColors.primary,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -912,34 +961,47 @@ class _PaymentTablePageState extends State<PaymentTablePage> {
|
|||||||
},
|
},
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: AppColors.red,
|
backgroundColor:
|
||||||
|
AppColors.red,
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
// Void the order
|
// Void the order
|
||||||
if (widget.table != null) {
|
if (widget.table != null) {
|
||||||
final newTable = TableModel(
|
final newTable = TableModel(
|
||||||
id: widget.table!.id,
|
id: widget.table!.id,
|
||||||
tableName: widget.table!.tableName,
|
tableName: widget
|
||||||
|
.table!.tableName,
|
||||||
status: 'available',
|
status: 'available',
|
||||||
orderId: 0,
|
orderId: 0,
|
||||||
paymentAmount: 0,
|
paymentAmount: 0,
|
||||||
startTime: DateTime.now().toIso8601String(),
|
startTime: DateTime.now()
|
||||||
position: widget.table!.position,
|
.toIso8601String(),
|
||||||
|
position: widget
|
||||||
|
.table!.position,
|
||||||
);
|
);
|
||||||
context.read<StatusTableBloc>().add(
|
context
|
||||||
StatusTableEvent.statusTabel(newTable),
|
.read<StatusTableBloc>()
|
||||||
|
.add(
|
||||||
|
StatusTableEvent
|
||||||
|
.statusTabel(
|
||||||
|
newTable),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// Remove draft order from local storage
|
// Remove draft order from local storage
|
||||||
if (widget.draftOrder?.id != null) {
|
if (widget.draftOrder?.id !=
|
||||||
ProductLocalDatasource.instance
|
null) {
|
||||||
.removeDraftOrderById(widget.draftOrder!.id!);
|
ProductLocalDatasource
|
||||||
|
.instance
|
||||||
|
.removeDraftOrderById(
|
||||||
|
widget.draftOrder!
|
||||||
|
.id!);
|
||||||
}
|
}
|
||||||
log("Voided order from payment page");
|
log("Voided order from payment page");
|
||||||
},
|
},
|
||||||
child: const Text(
|
child: const Text(
|
||||||
"Ya, Batalkan",
|
"Ya, Batalkan",
|
||||||
style: TextStyle(color: Colors.white),
|
style: TextStyle(
|
||||||
|
color: Colors.white),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -1011,8 +1073,7 @@ class _PaymentTablePageState extends State<PaymentTablePage> {
|
|||||||
0,
|
0,
|
||||||
(previousValue, element) =>
|
(previousValue, element) =>
|
||||||
previousValue +
|
previousValue +
|
||||||
(element.product.price!
|
(element.product.price! *
|
||||||
.toIntegerFromText *
|
|
||||||
element.quantity),
|
element.quantity),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -1080,22 +1141,29 @@ class _PaymentTablePageState extends State<PaymentTablePage> {
|
|||||||
child: Button.filled(
|
child: Button.filled(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
if (selectedPaymentMethod == null) {
|
if (selectedPaymentMethod == null) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context)
|
||||||
|
.showSnackBar(
|
||||||
const SnackBar(
|
const SnackBar(
|
||||||
content: Text('Please select a payment method'),
|
content: Text(
|
||||||
|
'Please select a payment method'),
|
||||||
backgroundColor: Colors.red,
|
backgroundColor: Colors.red,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final paymentMethodName = selectedPaymentMethod?.name?.toLowerCase() ?? '';
|
final paymentMethodName =
|
||||||
|
selectedPaymentMethod?.name
|
||||||
|
?.toLowerCase() ??
|
||||||
|
'';
|
||||||
log("Selected payment method: ${selectedPaymentMethod?.name} (normalized: $paymentMethodName)");
|
log("Selected payment method: ${selectedPaymentMethod?.name} (normalized: $paymentMethodName)");
|
||||||
|
|
||||||
if (paymentMethodName == 'cash' ||
|
if (paymentMethodName == 'cash' ||
|
||||||
paymentMethodName == 'tunai' ||
|
paymentMethodName == 'tunai' ||
|
||||||
paymentMethodName == 'uang tunai' ||
|
paymentMethodName ==
|
||||||
paymentMethodName == 'cash payment') {
|
'uang tunai' ||
|
||||||
|
paymentMethodName ==
|
||||||
|
'cash payment') {
|
||||||
context.read<OrderBloc>().add(
|
context.read<OrderBloc>().add(
|
||||||
OrderEvent.order(
|
OrderEvent.order(
|
||||||
items,
|
items,
|
||||||
@ -1109,7 +1177,9 @@ class _PaymentTablePageState extends State<PaymentTablePage> {
|
|||||||
widget.table?.id ?? 0,
|
widget.table?.id ?? 0,
|
||||||
'completed',
|
'completed',
|
||||||
'paid',
|
'paid',
|
||||||
selectedPaymentMethod?.name ?? 'Cash',
|
selectedPaymentMethod
|
||||||
|
?.name ??
|
||||||
|
'Cash',
|
||||||
totalPriceFinal,
|
totalPriceFinal,
|
||||||
orderType));
|
orderType));
|
||||||
|
|
||||||
@ -1149,7 +1219,9 @@ class _PaymentTablePageState extends State<PaymentTablePage> {
|
|||||||
widget.table?.id ?? 0,
|
widget.table?.id ?? 0,
|
||||||
'completed',
|
'completed',
|
||||||
'paid',
|
'paid',
|
||||||
selectedPaymentMethod?.name ?? 'Unknown Payment Method',
|
selectedPaymentMethod
|
||||||
|
?.name ??
|
||||||
|
'Unknown Payment Method',
|
||||||
totalPriceFinal,
|
totalPriceFinal,
|
||||||
orderType));
|
orderType));
|
||||||
|
|
||||||
@ -1173,7 +1245,7 @@ class _PaymentTablePageState extends State<PaymentTablePage> {
|
|||||||
customerController.text,
|
customerController.text,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Handle post-payment cleanup
|
// Handle post-payment cleanup
|
||||||
await _handlePostPaymentCleanup();
|
await _handlePostPaymentCleanup();
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user