update carton filter and merge api for shipment
This commit is contained in:
@@ -63,17 +63,6 @@ class _CartonEditorState extends State<CartonEditor> {
|
||||
_isNew = true;
|
||||
_selectedCartonType = carton_from_packages;
|
||||
_cartons = [];
|
||||
_sender = User(
|
||||
name: "ptd-phyo44 kaelone",
|
||||
fcsID: "FCS-8X6V",
|
||||
phoneNumber: "+959444444444",
|
||||
id: "48u_4s-HiQeW-HwSqeRd9TSMWh3mLZfSk5rpaUEh_zw");
|
||||
|
||||
_consignee = User(
|
||||
id: "HsIwG88K-0_HSazgEy5QR27kcjkOvfv7_Sr1JP18Q1A",
|
||||
name: "One One",
|
||||
phoneNumber: "+959111111111",
|
||||
fcsID: "FCS-EFRF");
|
||||
}
|
||||
if (mounted) {
|
||||
setState(() {});
|
||||
|
||||
@@ -3,11 +3,14 @@ import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '../../domain/constants.dart';
|
||||
import '../../domain/entities/fcs_shipment.dart';
|
||||
import '../../domain/entities/user.dart';
|
||||
import '../../helpers/theme.dart';
|
||||
import '../../localization/app_translations.dart';
|
||||
import '../main/util.dart';
|
||||
import '../widgets/local_text.dart';
|
||||
import 'model/shipment_selection_model.dart';
|
||||
import 'widget/shipment_result.dart';
|
||||
import 'widget/user_search_result.dart';
|
||||
import 'model/carton_model.dart';
|
||||
import 'model/consignee_selection_model.dart';
|
||||
@@ -24,6 +27,8 @@ class _CartonFilterState extends State<CartonFilter> {
|
||||
String? _selectedStatus;
|
||||
User? _selectedSender;
|
||||
User? _selectedConsignee;
|
||||
FcsShipment? _selectedShipment;
|
||||
bool _isLoadMoreShipment = false;
|
||||
|
||||
List<String> statusList = [
|
||||
all_status,
|
||||
@@ -48,11 +53,13 @@ class _CartonFilterState extends State<CartonFilter> {
|
||||
_selectedStatus = model.filterByStatus ?? all_status;
|
||||
_selectedConsignee = model.filterByConsingee ?? User(id: all, name: "All");
|
||||
_selectedSender = model.filterBySender ?? User(id: all, name: "All");
|
||||
_selectedShipment = model.shipment ?? model.defaultShipment;
|
||||
init();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
init() async {
|
||||
_initShipment();
|
||||
_initConsignee();
|
||||
_initSender();
|
||||
if (mounted) {
|
||||
@@ -60,6 +67,13 @@ class _CartonFilterState extends State<CartonFilter> {
|
||||
}
|
||||
}
|
||||
|
||||
_initShipment() async {
|
||||
await context.read<ShipmentSelectionModel>().refresh();
|
||||
if (mounted) {
|
||||
setState(() {});
|
||||
}
|
||||
}
|
||||
|
||||
_initConsignee() {
|
||||
var model = context.read<ConsigneeSelectionModel>();
|
||||
_consigneeCtl.text = model.query;
|
||||
@@ -109,6 +123,21 @@ class _CartonFilterState extends State<CartonFilter> {
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _loadMoreShipment() async {
|
||||
if (_isLoadMoreShipment) return;
|
||||
var model = context.read<ShipmentSelectionModel>();
|
||||
if (model.ended) return;
|
||||
setState(() {
|
||||
_isLoadMoreShipment = true;
|
||||
});
|
||||
|
||||
await model.loadMoreData();
|
||||
|
||||
setState(() {
|
||||
_isLoadMoreShipment = false;
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _loadMoreSender() async {
|
||||
if (_isLoadMoreSender) return;
|
||||
var model = context.read<SenderSelectionModel>();
|
||||
@@ -130,9 +159,11 @@ class _CartonFilterState extends State<CartonFilter> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var consigneeModel = context.watch<ConsigneeSelectionModel>();
|
||||
List<User> consignees = consigneeModel.getConsginees;
|
||||
var senderModel = context.watch<SenderSelectionModel>();
|
||||
var shipmentModel = context.watch<ShipmentSelectionModel>();
|
||||
List<User> consignees = consigneeModel.getConsginees;
|
||||
List<User> senders = senderModel.getSenders;
|
||||
List<FcsShipment> shipments = shipmentModel.getShipments;
|
||||
|
||||
final _titleWidget = SizedBox(
|
||||
height: 30,
|
||||
@@ -144,6 +175,9 @@ class _CartonFilterState extends State<CartonFilter> {
|
||||
labelPadding: const EdgeInsets.all(0),
|
||||
indicatorPadding: const EdgeInsets.all(0),
|
||||
tabs: [
|
||||
Tab(
|
||||
text: AppTranslations.of(context)?.text("box.fcs_shipment_num"),
|
||||
),
|
||||
Tab(
|
||||
text: AppTranslations.of(context)?.text("box.consignee.title"),
|
||||
),
|
||||
@@ -157,6 +191,30 @@ class _CartonFilterState extends State<CartonFilter> {
|
||||
),
|
||||
);
|
||||
|
||||
final _shipmentWidget = Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: ShipmentResult(
|
||||
searchResults: shipments,
|
||||
isLoading: shipmentModel.isLoading,
|
||||
noDataLabelKey: 'user.no_consignee',
|
||||
selectedUser: _selectedShipment,
|
||||
controller: widget.controller,
|
||||
isLoadingMore: _isLoadMoreShipment,
|
||||
onLoadMore: _loadMoreShipment,
|
||||
onRefresh: () async {
|
||||
_initShipment();
|
||||
},
|
||||
onTap: (a) async {
|
||||
setState(() {
|
||||
_selectedShipment = a;
|
||||
});
|
||||
},
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
|
||||
final _consingeeWidget = Column(
|
||||
children: [
|
||||
const SizedBox(height: 15),
|
||||
@@ -335,13 +393,14 @@ class _CartonFilterState extends State<CartonFilter> {
|
||||
),
|
||||
Expanded(
|
||||
child: DefaultTabController(
|
||||
length: 3,
|
||||
length: 4,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
_titleWidget,
|
||||
Expanded(
|
||||
child: TabBarView(children: <Widget>[
|
||||
_shipmentWidget,
|
||||
_consingeeWidget,
|
||||
_senderWidget,
|
||||
_statusWidget
|
||||
@@ -428,14 +487,16 @@ class _CartonFilterState extends State<CartonFilter> {
|
||||
|
||||
_clearFilter() async {
|
||||
await context.read<CartonModel>().filterCarton(
|
||||
User(id: all, name: "All"), User(id: all, name: "All"), all_status);
|
||||
Navigator.pop(context);
|
||||
FcsShipment(shipmentNumber: "All shipments", id: all),
|
||||
User(id: all, name: "All"),
|
||||
User(id: all, name: "All"),
|
||||
all_status);
|
||||
Navigator.pop(context, true);
|
||||
}
|
||||
|
||||
_filter() async {
|
||||
await context
|
||||
.read<CartonModel>()
|
||||
.filterCarton(_selectedConsignee, _selectedSender, _selectedStatus);
|
||||
Navigator.pop(context);
|
||||
await context.read<CartonModel>().filterCarton(_selectedShipment,
|
||||
_selectedConsignee, _selectedSender, _selectedStatus);
|
||||
Navigator.pop(context, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,6 @@ import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_vector_icons/flutter_vector_icons.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '../../domain/constants.dart';
|
||||
import '../../domain/entities/carton.dart';
|
||||
import '../../pagination/paginator_listview.dart';
|
||||
import '../carton_search/carton_search.dart';
|
||||
@@ -38,10 +36,9 @@ class _CartonListState extends State<CartonList> {
|
||||
|
||||
_init() async {
|
||||
var model = context.read<CartonModel>();
|
||||
_shipments = await context.read<FcsShipmentModel>().getAllShipments();
|
||||
_shipments.insert(0, FcsShipment(shipmentNumber: "All Shipments", id: all));
|
||||
_selectedShipment =
|
||||
model.shipment ?? FcsShipment(shipmentNumber: "All Shipments", id: all);
|
||||
_shipments = await context.read<FcsShipmentModel>().getShipments();
|
||||
_shipments.insert(0, model.defaultShipment);
|
||||
_selectedShipment = model.shipment ?? model.defaultShipment;
|
||||
model.loadPaginationCartons();
|
||||
|
||||
if (mounted) {
|
||||
@@ -309,7 +306,7 @@ class _CartonListState extends State<CartonList> {
|
||||
],
|
||||
),
|
||||
onPressed: () async {
|
||||
await showModalBottomSheet(
|
||||
bool? updated = await showModalBottomSheet(
|
||||
context: context,
|
||||
useRootNavigator: true,
|
||||
isScrollControlled: true,
|
||||
@@ -323,6 +320,12 @@ class _CartonListState extends State<CartonList> {
|
||||
expand: false,
|
||||
builder: (_, controller) =>
|
||||
CartonFilter(controller: controller)));
|
||||
var model = context.read<CartonModel>();
|
||||
if (updated ?? false) {
|
||||
setState(() {
|
||||
_selectedShipment = model.shipment ?? model.defaultShipment;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@ import 'package:path/path.dart' as Path;
|
||||
class CartonModel extends BaseModel {
|
||||
final log = Logger('CartonModel');
|
||||
|
||||
var defaultShipment =FcsShipment(shipmentNumber: "All shipments", id: all);
|
||||
|
||||
PaginatorListener<Carton>? cartonsByFilter;
|
||||
PaginatorListener<Carton>? getBoxes;
|
||||
|
||||
@@ -56,7 +58,8 @@ class CartonModel extends BaseModel {
|
||||
_loadPaginationCartons();
|
||||
}
|
||||
|
||||
filterCarton(User? consignee, User? sender, String? status) async {
|
||||
filterCarton(FcsShipment? fcsShipment, User? consignee, User? sender,
|
||||
String? status) async {
|
||||
filterByStatus = status;
|
||||
|
||||
if (status == all_status) {
|
||||
@@ -77,6 +80,12 @@ class CartonModel extends BaseModel {
|
||||
filterBySender = sender;
|
||||
}
|
||||
|
||||
if (fcsShipment?.id == all) {
|
||||
shipment = null;
|
||||
} else {
|
||||
shipment = fcsShipment;
|
||||
}
|
||||
|
||||
loadPaginationCartons();
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
75
lib/pages/carton/model/shipment_selection_model.dart
Normal file
75
lib/pages/carton/model/shipment_selection_model.dart
Normal file
@@ -0,0 +1,75 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:fcs/domain/entities/fcs_shipment.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
import '../../../domain/constants.dart';
|
||||
import '../../main/model/base_model.dart';
|
||||
|
||||
class ShipmentSelectionModel extends BaseModel {
|
||||
final log = Logger("ShipmentSelectionModel");
|
||||
|
||||
List<FcsShipment> _shipments = [];
|
||||
|
||||
List<FcsShipment> get getShipments {
|
||||
var list = new List<FcsShipment>.from(_shipments);
|
||||
return list
|
||||
..insert(0, FcsShipment(id: all, shipmentNumber: "All shipments"));
|
||||
}
|
||||
|
||||
bool isLoading = false;
|
||||
DocumentSnapshot? _lastDocument;
|
||||
bool ended = false;
|
||||
|
||||
Future<void> refresh() async {
|
||||
_shipments.clear();
|
||||
_lastDocument = null;
|
||||
ended = false;
|
||||
await loadMoreData();
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> loadMoreData() async {
|
||||
int rowPerPage = 20;
|
||||
|
||||
try {
|
||||
isLoading = true;
|
||||
String path = "/$fcs_shipment_collection";
|
||||
Query query = FirebaseFirestore.instance
|
||||
.collection(path)
|
||||
.where("status", whereIn: [
|
||||
fcs_shipment_processing_status,
|
||||
fcs_shipment_shipped_status,
|
||||
fcs_shipment_arrived_status,
|
||||
fcs_shipment_invoiced_status
|
||||
])
|
||||
.where("is_deleted", isEqualTo: false)
|
||||
.orderBy("update_time", descending: true);
|
||||
|
||||
if (_lastDocument != null) {
|
||||
query = query.startAfterDocument(_lastDocument!);
|
||||
}
|
||||
|
||||
QuerySnapshot querySnap = await query.limit(rowPerPage).get();
|
||||
|
||||
if (querySnap.docs.isEmpty) return;
|
||||
_lastDocument = querySnap.docs[querySnap.docs.length - 1];
|
||||
|
||||
List<FcsShipment> list = querySnap.docs.map((documentSnapshot) {
|
||||
var p = FcsShipment.fromMap(
|
||||
documentSnapshot.data() as Map<String, dynamic>,
|
||||
documentSnapshot.id);
|
||||
return p;
|
||||
}).toList();
|
||||
|
||||
_shipments.addAll(list);
|
||||
if (list.length < rowPerPage) ended = true;
|
||||
notifyListeners();
|
||||
} catch (e) {
|
||||
log.warning("error:$e");
|
||||
} finally {
|
||||
isLoading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,6 @@ import '../widgets/continue_button.dart';
|
||||
import '../widgets/display_text.dart';
|
||||
import '../widgets/local_title.dart';
|
||||
import '../widgets/previous_button.dart';
|
||||
import 'model/carton_selection_model.dart';
|
||||
import 'model/package_selection_model.dart';
|
||||
import 'package_selection_result.dart';
|
||||
|
||||
@@ -63,25 +62,26 @@ class _PackageSelectionWidgetState extends State<PackageSelectionWidget> {
|
||||
|
||||
_init() {
|
||||
var searchModel = context.read<PackageSelectionModel>();
|
||||
|
||||
searchModel.addDefaultPackages(
|
||||
shipmentId: widget.shipment.id!,
|
||||
consigneeId: widget.consignee.id!,
|
||||
senderId: widget.sender.id!);
|
||||
|
||||
searchModel.addSelectedPackage(widget.packages);
|
||||
|
||||
_controller.text = searchModel.query;
|
||||
_query = searchModel.query;
|
||||
|
||||
if (mounted) {
|
||||
setState(() {});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(covariant PackageSelectionWidget oldWidget) {
|
||||
_init();
|
||||
super.didUpdateWidget(oldWidget);
|
||||
}
|
||||
// @override
|
||||
// void didUpdateWidget(covariant PackageSelectionWidget oldWidget) {
|
||||
// _init();
|
||||
// super.didUpdateWidget(oldWidget);
|
||||
// }
|
||||
|
||||
Future<void> _loadMoreData() async {
|
||||
if (_isLoadMore) return;
|
||||
@@ -278,7 +278,7 @@ class _PackageSelectionWidgetState extends State<PackageSelectionWidget> {
|
||||
isLoadingMore: _isLoadMore,
|
||||
onLoadMore: _loadMoreData,
|
||||
onRefresh: () async {
|
||||
_init();
|
||||
_search();
|
||||
setState(() {
|
||||
_down = true;
|
||||
});
|
||||
@@ -330,9 +330,11 @@ class _PackageSelectionWidgetState extends State<PackageSelectionWidget> {
|
||||
|
||||
_search({bool imm = false}) async {
|
||||
try {
|
||||
await context
|
||||
.read<CartonSelectionModel>()
|
||||
.search(_query, imm: imm, shipmentId: widget.shipment.id!);
|
||||
await context.read<PackageSelectionModel>().search(_query,
|
||||
imm: imm,
|
||||
shipmentId: widget.shipment.id!,
|
||||
senderId: widget.sender.id!,
|
||||
consigneeId: widget.consignee.id!);
|
||||
} catch (e) {
|
||||
showMsgDialog(context, 'Error', e.toString());
|
||||
}
|
||||
|
||||
97
lib/pages/carton/widget/shipment_result.dart
Normal file
97
lib/pages/carton/widget/shipment_result.dart
Normal file
@@ -0,0 +1,97 @@
|
||||
import 'package:fcs/domain/entities/fcs_shipment.dart';
|
||||
import 'package:fcs/pages/widgets/local_text.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../../helpers/theme.dart';
|
||||
|
||||
typedef OnAction = Future<void> Function();
|
||||
|
||||
class ShipmentResult extends StatelessWidget {
|
||||
final bool isLoadingMore;
|
||||
final OnAction onLoadMore;
|
||||
final OnAction onRefresh;
|
||||
final Function(FcsShipment)? onTap;
|
||||
final ScrollController controller;
|
||||
final FcsShipment? selectedUser;
|
||||
final List<FcsShipment> searchResults;
|
||||
final String? noDataLabelKey;
|
||||
final bool isLoading;
|
||||
|
||||
const ShipmentResult(
|
||||
{super.key,
|
||||
required this.isLoadingMore,
|
||||
required this.onLoadMore,
|
||||
required this.onRefresh,
|
||||
this.onTap,
|
||||
required this.controller,
|
||||
this.selectedUser,
|
||||
this.searchResults = const [],
|
||||
this.noDataLabelKey,
|
||||
this.isLoading = false});
|
||||
|
||||
bool _scrollNotification(ScrollNotification scrollInfo) {
|
||||
if (!isLoadingMore &&
|
||||
scrollInfo.metrics.pixels == scrollInfo.metrics.maxScrollExtent) {
|
||||
onLoadMore();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return searchResults.isEmpty && !isLoading
|
||||
? noDataLabelKey == null
|
||||
? const SizedBox()
|
||||
: Center(
|
||||
child: LocalText(context, noDataLabelKey!,
|
||||
color: Colors.black, fontSize: 15))
|
||||
: Column(children: [
|
||||
Expanded(
|
||||
child: NotificationListener<ScrollNotification>(
|
||||
onNotification: _scrollNotification,
|
||||
child: RefreshIndicator(
|
||||
color: primaryColor,
|
||||
onRefresh: () => onRefresh(),
|
||||
child: ListView.builder(
|
||||
controller: controller,
|
||||
shrinkWrap: true,
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
itemBuilder: (context, index) {
|
||||
FcsShipment user = searchResults[index];
|
||||
|
||||
return ListTile(
|
||||
onTap: () {
|
||||
if (onTap != null) {
|
||||
onTap!(user);
|
||||
}
|
||||
},
|
||||
title: Row(
|
||||
children: [
|
||||
Text(user.shipmentNumber ?? "",
|
||||
style: const TextStyle(
|
||||
fontSize: 15, color: Colors.black)),
|
||||
const SizedBox(
|
||||
width: 20,
|
||||
),
|
||||
selectedUser?.id == user.id
|
||||
? const Icon(
|
||||
Icons.check,
|
||||
color: Colors.grey,
|
||||
)
|
||||
: const SizedBox()
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
itemCount: searchResults.length)),
|
||||
)),
|
||||
Container(
|
||||
height: isLoadingMore ? 50.0 : 0,
|
||||
color: Colors.transparent,
|
||||
child: const Center(
|
||||
child: CircularProgressIndicator(
|
||||
valueColor: AlwaysStoppedAnimation<Color>(primaryColor)),
|
||||
)),
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user