feat : segmentation page
This commit is contained in:
@@ -6,7 +6,7 @@ part 'segmentation_model.g.dart';
|
|||||||
|
|
||||||
@freezed
|
@freezed
|
||||||
abstract class SegmentationModel with _$SegmentationModel {
|
abstract class SegmentationModel with _$SegmentationModel {
|
||||||
const factory SegmentationModel({String? key, Buyer? buyer, DateTime? date, double? weight}) =
|
const factory SegmentationModel({String? key, Buyer? buyer, DateTime? date, int? weight}) =
|
||||||
_SegmentationModel;
|
_SegmentationModel;
|
||||||
|
|
||||||
factory SegmentationModel.fromJson(Map<String, dynamic> json) =>
|
factory SegmentationModel.fromJson(Map<String, dynamic> json) =>
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ T _$identity<T>(T value) => value;
|
|||||||
/// @nodoc
|
/// @nodoc
|
||||||
mixin _$SegmentationModel {
|
mixin _$SegmentationModel {
|
||||||
|
|
||||||
String? get key; Buyer? get buyer; DateTime? get date; double? get weight;
|
String? get key; Buyer? get buyer; DateTime? get date; int? get weight;
|
||||||
/// Create a copy of SegmentationModel
|
/// Create a copy of SegmentationModel
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@@ -49,7 +49,7 @@ abstract mixin class $SegmentationModelCopyWith<$Res> {
|
|||||||
factory $SegmentationModelCopyWith(SegmentationModel value, $Res Function(SegmentationModel) _then) = _$SegmentationModelCopyWithImpl;
|
factory $SegmentationModelCopyWith(SegmentationModel value, $Res Function(SegmentationModel) _then) = _$SegmentationModelCopyWithImpl;
|
||||||
@useResult
|
@useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
String? key, Buyer? buyer, DateTime? date, double? weight
|
String? key, Buyer? buyer, DateTime? date, int? weight
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -72,7 +72,7 @@ key: freezed == key ? _self.key : key // ignore: cast_nullable_to_non_nullable
|
|||||||
as String?,buyer: freezed == buyer ? _self.buyer : buyer // ignore: cast_nullable_to_non_nullable
|
as String?,buyer: freezed == buyer ? _self.buyer : buyer // ignore: cast_nullable_to_non_nullable
|
||||||
as Buyer?,date: freezed == date ? _self.date : date // ignore: cast_nullable_to_non_nullable
|
as Buyer?,date: freezed == date ? _self.date : date // ignore: cast_nullable_to_non_nullable
|
||||||
as DateTime?,weight: freezed == weight ? _self.weight : weight // ignore: cast_nullable_to_non_nullable
|
as DateTime?,weight: freezed == weight ? _self.weight : weight // ignore: cast_nullable_to_non_nullable
|
||||||
as double?,
|
as int?,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
/// Create a copy of SegmentationModel
|
/// Create a copy of SegmentationModel
|
||||||
@@ -101,7 +101,7 @@ class _SegmentationModel implements SegmentationModel {
|
|||||||
@override final String? key;
|
@override final String? key;
|
||||||
@override final Buyer? buyer;
|
@override final Buyer? buyer;
|
||||||
@override final DateTime? date;
|
@override final DateTime? date;
|
||||||
@override final double? weight;
|
@override final int? weight;
|
||||||
|
|
||||||
/// Create a copy of SegmentationModel
|
/// Create a copy of SegmentationModel
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@@ -136,7 +136,7 @@ abstract mixin class _$SegmentationModelCopyWith<$Res> implements $SegmentationM
|
|||||||
factory _$SegmentationModelCopyWith(_SegmentationModel value, $Res Function(_SegmentationModel) _then) = __$SegmentationModelCopyWithImpl;
|
factory _$SegmentationModelCopyWith(_SegmentationModel value, $Res Function(_SegmentationModel) _then) = __$SegmentationModelCopyWithImpl;
|
||||||
@override @useResult
|
@override @useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
String? key, Buyer? buyer, DateTime? date, double? weight
|
String? key, Buyer? buyer, DateTime? date, int? weight
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -159,7 +159,7 @@ key: freezed == key ? _self.key : key // ignore: cast_nullable_to_non_nullable
|
|||||||
as String?,buyer: freezed == buyer ? _self.buyer : buyer // ignore: cast_nullable_to_non_nullable
|
as String?,buyer: freezed == buyer ? _self.buyer : buyer // ignore: cast_nullable_to_non_nullable
|
||||||
as Buyer?,date: freezed == date ? _self.date : date // ignore: cast_nullable_to_non_nullable
|
as Buyer?,date: freezed == date ? _self.date : date // ignore: cast_nullable_to_non_nullable
|
||||||
as DateTime?,weight: freezed == weight ? _self.weight : weight // ignore: cast_nullable_to_non_nullable
|
as DateTime?,weight: freezed == weight ? _self.weight : weight // ignore: cast_nullable_to_non_nullable
|
||||||
as double?,
|
as int?,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ _SegmentationModel _$SegmentationModelFromJson(Map<String, dynamic> json) =>
|
|||||||
date: json['date'] == null
|
date: json['date'] == null
|
||||||
? null
|
? null
|
||||||
: DateTime.parse(json['date'] as String),
|
: DateTime.parse(json['date'] as String),
|
||||||
weight: (json['weight'] as num?)?.toDouble(),
|
weight: (json['weight'] as num?)?.toInt(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> _$SegmentationModelToJson(_SegmentationModel instance) =>
|
Map<String, dynamic> _$SegmentationModelToJson(_SegmentationModel instance) =>
|
||||||
|
|||||||
@@ -148,6 +148,8 @@ abstract class ChickenRepository {
|
|||||||
Map<String, dynamic>? queryParameters,
|
Map<String, dynamic>? queryParameters,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Future<void> createSegmentation({required String token, required SegmentationModel model});
|
||||||
|
|
||||||
Future<void> editSegmentation({required String token, required SegmentationModel model});
|
Future<void> editSegmentation({required String token, required SegmentationModel model});
|
||||||
|
|
||||||
Future<void> deleteSegmentation({required String token, required String key});
|
Future<void> deleteSegmentation({required String token, required String key});
|
||||||
|
|||||||
@@ -450,6 +450,15 @@ class ChickenRepositoryImpl implements ChickenRepository {
|
|||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> createSegmentation({required String token, required SegmentationModel model}) async {
|
||||||
|
await _httpClient.post(
|
||||||
|
'/app-segmentation/',
|
||||||
|
data: model.toJson()..removeWhere((key, value) => value == null),
|
||||||
|
headers: {'Authorization': 'Bearer $token'},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> editSegmentation({required String token, required SegmentationModel model}) async {
|
Future<void> editSegmentation({required String token, required SegmentationModel model}) async {
|
||||||
await _httpClient.put(
|
await _httpClient.put(
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/material.dart' show Colors;
|
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:rasadyar_auth/data/services/token_storage_service.dart';
|
import 'package:rasadyar_auth/data/services/token_storage_service.dart';
|
||||||
import 'package:rasadyar_auth/data/utils/safe_call.dart';
|
import 'package:rasadyar_auth/data/utils/safe_call.dart';
|
||||||
@@ -13,6 +12,7 @@ import 'package:rasadyar_chicken/presentation/pages/buy/view.dart';
|
|||||||
import 'package:rasadyar_chicken/presentation/pages/home/view.dart';
|
import 'package:rasadyar_chicken/presentation/pages/home/view.dart';
|
||||||
import 'package:rasadyar_chicken/presentation/pages/profile/view.dart';
|
import 'package:rasadyar_chicken/presentation/pages/profile/view.dart';
|
||||||
import 'package:rasadyar_chicken/presentation/pages/sale/view.dart';
|
import 'package:rasadyar_chicken/presentation/pages/sale/view.dart';
|
||||||
|
import 'package:rasadyar_chicken/presentation/pages/segmentation/view.dart';
|
||||||
import 'package:rasadyar_chicken/presentation/routes/routes.dart';
|
import 'package:rasadyar_chicken/presentation/routes/routes.dart';
|
||||||
import 'package:rasadyar_chicken/presentation/utils/utils.dart';
|
import 'package:rasadyar_chicken/presentation/utils/utils.dart';
|
||||||
import 'package:rasadyar_core/core.dart';
|
import 'package:rasadyar_core/core.dart';
|
||||||
@@ -21,13 +21,7 @@ enum ErrorLocationType { serviceDisabled, permissionDenied, none }
|
|||||||
|
|
||||||
class RootLogic extends GetxController {
|
class RootLogic extends GetxController {
|
||||||
RxInt currentPage = 2.obs;
|
RxInt currentPage = 2.obs;
|
||||||
List<Widget> pages = [
|
List<Widget> pages = [BuyPage(), SalePage(), HomePage(), SegmentationPage(), ProfilePage()];
|
||||||
BuyPage(),
|
|
||||||
SalePage(),
|
|
||||||
HomePage(),
|
|
||||||
Container(color: Colors.blue),
|
|
||||||
ProfilePage(),
|
|
||||||
];
|
|
||||||
|
|
||||||
final defaultRoutes = <int, String>{0: ChickenRoutes.buy, 1: ChickenRoutes.sale};
|
final defaultRoutes = <int, String>{0: ChickenRoutes.buy, 1: ChickenRoutes.sale};
|
||||||
|
|
||||||
|
|||||||
192
packages/chicken/lib/presentation/pages/segmentation/logic.dart
Normal file
192
packages/chicken/lib/presentation/pages/segmentation/logic.dart
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:rasadyar_auth/data/utils/safe_call.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/roles_products/roles_products.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/segmentation_model/segmentation_model.dart';
|
||||||
|
import 'package:rasadyar_chicken/presentation/pages/root/logic.dart';
|
||||||
|
import 'package:rasadyar_chicken/presentation/utils/utils.dart';
|
||||||
|
import 'package:rasadyar_core/core.dart';
|
||||||
|
|
||||||
|
class SegmentationLogic extends GetxController {
|
||||||
|
RootLogic rootLogic = Get.find<RootLogic>();
|
||||||
|
|
||||||
|
RxBool isLoadingMoreAllocationsMade = false.obs;
|
||||||
|
RxInt currentPage = 1.obs;
|
||||||
|
|
||||||
|
late List<String> routesName;
|
||||||
|
RxInt selectedSegmentIndex = 0.obs;
|
||||||
|
RxBool isExpanded = false.obs;
|
||||||
|
|
||||||
|
RxList<int> isExpandedList = <int>[].obs;
|
||||||
|
Rx<Jalali> fromDateFilter = Jalali.now().obs;
|
||||||
|
Rx<Jalali> toDateFilter = Jalali.now().obs;
|
||||||
|
RxnString searchedValue = RxnString();
|
||||||
|
|
||||||
|
GlobalKey<FormState> formKey = GlobalKey<FormState>();
|
||||||
|
TextEditingController weightController = TextEditingController();
|
||||||
|
RxBool isSaleSubmitButtonEnabled = false.obs;
|
||||||
|
|
||||||
|
RxList<ProductModel> rolesProductsModel = RxList<ProductModel>();
|
||||||
|
Rxn<ProductModel> selectedProduct = Rxn<ProductModel>();
|
||||||
|
Rxn<SegmentationModel> selectedSegment = Rxn<SegmentationModel>();
|
||||||
|
|
||||||
|
Rx<Resource<PaginationModel<SegmentationModel>>> segmentationList =
|
||||||
|
Resource<PaginationModel<SegmentationModel>>.loading().obs;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onInit() {
|
||||||
|
super.onInit();
|
||||||
|
routesName = ['قطعهبندی'].toList();
|
||||||
|
getAllSegmentation();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onReady() {
|
||||||
|
super.onReady();
|
||||||
|
setUpListener();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onClose() {
|
||||||
|
// TODO: implement onClose
|
||||||
|
super.onClose();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSearchValue(String? value) {
|
||||||
|
searchedValue.value = value?.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setUpListener() {
|
||||||
|
debounce(
|
||||||
|
searchedValue,
|
||||||
|
(callback) => getAllSegmentation(),
|
||||||
|
time: Duration(milliseconds: timeDebounce),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setEditData(SegmentationModel item) {
|
||||||
|
selectedSegment.value = item;
|
||||||
|
weightController.text = item.weight.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearForm() {
|
||||||
|
weightController.clear();
|
||||||
|
isSaleSubmitButtonEnabled.value = false;
|
||||||
|
selectedProduct.value = null;
|
||||||
|
selectedSegment.value = null;
|
||||||
|
formKey.currentState?.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> getAllSegmentation([bool isLoadingMore = false]) async {
|
||||||
|
if (isLoadingMore) {
|
||||||
|
isLoadingMoreAllocationsMade.value = true;
|
||||||
|
} else {
|
||||||
|
segmentationList.value = Resource<PaginationModel<SegmentationModel>>.loading();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (searchedValue.value != null &&
|
||||||
|
searchedValue.value!.trim().isNotEmpty &&
|
||||||
|
currentPage.value > 1) {
|
||||||
|
currentPage.value = 1; // Reset to first page if search value is set
|
||||||
|
}
|
||||||
|
|
||||||
|
await safeCall(
|
||||||
|
call: () async => await rootLogic.chickenRepository.getSegmentation(
|
||||||
|
token: rootLogic.tokenService.accessToken.value!,
|
||||||
|
queryParameters: buildQueryParams(
|
||||||
|
pageSize: 20,
|
||||||
|
page: currentPage.value,
|
||||||
|
search: 'filter',
|
||||||
|
role: 'Steward',
|
||||||
|
value: searchedValue.value,
|
||||||
|
fromDate: fromDateFilter.value.toDateTime(),
|
||||||
|
toDate: toDateFilter.value.toDateTime(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
onSuccess: (result) {
|
||||||
|
if ((result?.count ?? 0) == 0) {
|
||||||
|
segmentationList.value = Resource<PaginationModel<SegmentationModel>>.empty();
|
||||||
|
} else {
|
||||||
|
segmentationList.value = Resource<PaginationModel<SegmentationModel>>.success(
|
||||||
|
PaginationModel<SegmentationModel>(
|
||||||
|
count: result?.count ?? 0,
|
||||||
|
next: result?.next,
|
||||||
|
previous: result?.previous,
|
||||||
|
results: [
|
||||||
|
...(segmentationList.value.data?.results ?? []),
|
||||||
|
...(result?.results ?? []),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
isLoadingMoreAllocationsMade.value = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> deleteSegmentation(String key) async {
|
||||||
|
await safeCall(
|
||||||
|
call: () => rootLogic.chickenRepository.deleteSegmentation(
|
||||||
|
token: rootLogic.tokenService.accessToken.value!,
|
||||||
|
key: key,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> getRolesProducts() async {
|
||||||
|
safeCall(
|
||||||
|
call: () async => await rootLogic.chickenRepository.getRolesProducts(
|
||||||
|
token: rootLogic.tokenService.accessToken.value!,
|
||||||
|
),
|
||||||
|
onSuccess: (result) {
|
||||||
|
if (result != null) {
|
||||||
|
rolesProductsModel.value = result;
|
||||||
|
|
||||||
|
selectedProduct.value = rolesProductsModel.first;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onError: (error, stacktrace) {},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> editSegment() async {
|
||||||
|
var res = true;
|
||||||
|
safeCall(
|
||||||
|
call: () async => await rootLogic.chickenRepository.editSegmentation(
|
||||||
|
token: rootLogic.tokenService.accessToken.value!,
|
||||||
|
model: SegmentationModel(
|
||||||
|
key: selectedSegment.value?.key,
|
||||||
|
weight: int.tryParse(weightController.text) ?? 0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onSuccess: (result) {
|
||||||
|
res = true;
|
||||||
|
},
|
||||||
|
onError: (error, stacktrace) {
|
||||||
|
res = false;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> createSegment() async {
|
||||||
|
var res = true;
|
||||||
|
safeCall(
|
||||||
|
call: () async => await rootLogic.chickenRepository.createSegmentation(
|
||||||
|
token: rootLogic.tokenService.accessToken.value!,
|
||||||
|
model: SegmentationModel(
|
||||||
|
key: selectedProduct.value?.key,
|
||||||
|
weight: int.tryParse(weightController.text) ?? 0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onSuccess: (result) {
|
||||||
|
res = true;
|
||||||
|
},
|
||||||
|
onError: (error, stacktrace) {
|
||||||
|
res = false;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
331
packages/chicken/lib/presentation/pages/segmentation/view.dart
Normal file
331
packages/chicken/lib/presentation/pages/segmentation/view.dart
Normal file
@@ -0,0 +1,331 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/roles_products/roles_products.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/segmentation_model/segmentation_model.dart';
|
||||||
|
import 'package:rasadyar_chicken/presentation/widget/base_page/view.dart';
|
||||||
|
import 'package:rasadyar_chicken/presentation/widget/filter_bottom_sheet.dart';
|
||||||
|
import 'package:rasadyar_chicken/presentation/widget/list_item/list_item.dart';
|
||||||
|
import 'package:rasadyar_chicken/presentation/widget/list_row_item.dart';
|
||||||
|
import 'package:rasadyar_core/core.dart';
|
||||||
|
|
||||||
|
import 'logic.dart';
|
||||||
|
|
||||||
|
class SegmentationPage extends GetView<SegmentationLogic> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return BasePage(
|
||||||
|
routes: controller.routesName,
|
||||||
|
onSearchChanged: (data) => controller.setSearchValue(data),
|
||||||
|
filteringWidget: filterBottomSheet(),
|
||||||
|
isBase: true,
|
||||||
|
widgets: [
|
||||||
|
Expanded(
|
||||||
|
child: ObxValue((data) {
|
||||||
|
return RPaginatedListView(
|
||||||
|
onLoadMore: () async => controller.getAllSegmentation(true),
|
||||||
|
onRefresh: () async {
|
||||||
|
controller.currentPage.value = 1;
|
||||||
|
await controller.getAllSegmentation();
|
||||||
|
},
|
||||||
|
hasMore: data.value.data?.next != null,
|
||||||
|
listType: ListType.separated,
|
||||||
|
resource: data.value,
|
||||||
|
padding: EdgeInsets.fromLTRB(8, 8, 8, 80),
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
var item = data.value.data!.results![index];
|
||||||
|
return ObxValue((val) {
|
||||||
|
return ListItem2(
|
||||||
|
selected: val.contains(index),
|
||||||
|
onTap: () => controller.isExpandedList.toggle(index),
|
||||||
|
index: index,
|
||||||
|
child: itemListWidget(item),
|
||||||
|
secondChild: itemListExpandedWidget(item, index),
|
||||||
|
labelColor: AppColor.blueLight,
|
||||||
|
labelIcon: Assets.vec.timerSvg.path,
|
||||||
|
);
|
||||||
|
}, controller.isExpandedList);
|
||||||
|
},
|
||||||
|
itemCount: data.value.data?.results?.length ?? 0,
|
||||||
|
separatorBuilder: (context, index) => SizedBox(height: 8.h),
|
||||||
|
);
|
||||||
|
}, controller.segmentationList),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
|
||||||
|
floatingActionButton: RFab.add(
|
||||||
|
onPressed: () {
|
||||||
|
//TODO
|
||||||
|
//Get.bottomSheet(addOrEditSaleBottomSheet(), isScrollControlled: true);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget filterBottomSheet() => filterBottomSheetWidget(
|
||||||
|
fromDate: controller.fromDateFilter,
|
||||||
|
onChangedFromDate: (jalali) => controller.fromDateFilter.value = jalali,
|
||||||
|
toDate: controller.toDateFilter,
|
||||||
|
onChangedToDate: (jalali) => controller.toDateFilter.value = jalali,
|
||||||
|
onSubmit: () => controller.getAllSegmentation(),
|
||||||
|
);
|
||||||
|
|
||||||
|
itemListWidget(SegmentationModel item) {
|
||||||
|
return Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
children: [
|
||||||
|
SizedBox(width: 12),
|
||||||
|
Expanded(
|
||||||
|
flex: 3,
|
||||||
|
child: Text(
|
||||||
|
item.date?.formattedJalaliDate ?? 'N/A',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: AppFonts.yekan12.copyWith(color: AppColor.bgDark),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(width: 4),
|
||||||
|
Expanded(
|
||||||
|
flex: 5,
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
item.buyer?.fullname ?? 'N/A',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: AppFonts.yekan14.copyWith(color: AppColor.blueNormal),
|
||||||
|
),
|
||||||
|
|
||||||
|
SizedBox(height: 2),
|
||||||
|
Text(
|
||||||
|
item.buyer?.shop ?? 'N/A',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: AppFonts.yekan14.copyWith(color: AppColor.bgDark),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(width: 4),
|
||||||
|
Expanded(
|
||||||
|
flex: 4,
|
||||||
|
child: Text(
|
||||||
|
item.date?.formattedJalaliDate,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: AppFonts.yekan12.copyWith(color: AppColor.bgDark),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
flex: 2,
|
||||||
|
child: Text(
|
||||||
|
'${item.weight} KG',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: AppFonts.yekan12.copyWith(color: AppColor.bgDark),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
itemListExpandedWidget(SegmentationModel item, int index) {
|
||||||
|
return Container(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 8),
|
||||||
|
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(8)),
|
||||||
|
child: Column(
|
||||||
|
spacing: 8,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
height: 32,
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 8),
|
||||||
|
decoration: ShapeDecoration(
|
||||||
|
color: AppColor.blueLight,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
side: BorderSide(width: 1, color: AppColor.blueLightHover),
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
spacing: 3,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
DateTimeExtensions(item.date)?.toJalali().formatter.wN ?? 'N/A',
|
||||||
|
style: AppFonts.yekan14.copyWith(color: AppColor.textColor),
|
||||||
|
),
|
||||||
|
|
||||||
|
Text(
|
||||||
|
'${DateTimeExtensions(item.date)?.toJalali().formatter.d} ${DateTimeExtensions(item.date)?.toJalali().formatter.mN ?? 'N/A'}',
|
||||||
|
style: AppFonts.yekan14.copyWith(color: AppColor.blueNormal),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
Text(
|
||||||
|
'${DateTimeExtensions(item.date)?.toJalali().formatter.y}',
|
||||||
|
style: AppFonts.yekan20.copyWith(color: AppColor.textColor),
|
||||||
|
),
|
||||||
|
|
||||||
|
Text(
|
||||||
|
'${DateTimeExtensions(item.date)?.toJalali().formatter.tHH}:${DateTimeExtensions(item.date)?.toJalali().formatter.tMM ?? 'N/A'}',
|
||||||
|
style: AppFonts.yekan14.copyWith(color: AppColor.textColor),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
buildRow(title: 'مشخصات خریدار', value: item.buyer?.fullname ?? 'N/A'),
|
||||||
|
buildRow(title: 'تلفن خریدار', value: item.buyer?.mobile ?? 'N/A'),
|
||||||
|
buildRow(title: 'نام واحد', value: item.buyer?.shop ?? 'N/A'),
|
||||||
|
buildRow(title: 'وزن قطعهبندی', value: '${item.weight?.separatedByComma}'),
|
||||||
|
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
spacing: 16.w,
|
||||||
|
children: [
|
||||||
|
RElevated(
|
||||||
|
text: 'ویرایش',
|
||||||
|
width: 150.w,
|
||||||
|
height: 40.h,
|
||||||
|
onPressed: () {
|
||||||
|
controller.setEditData(item);
|
||||||
|
Get.bottomSheet(
|
||||||
|
addOrEditBottomSheet(true),
|
||||||
|
isScrollControlled: true,
|
||||||
|
).whenComplete(() {
|
||||||
|
controller.clearForm();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
textStyle: AppFonts.yekan20.copyWith(color: Colors.white),
|
||||||
|
backgroundColor: AppColor.greenNormal,
|
||||||
|
),
|
||||||
|
ROutlinedElevated(
|
||||||
|
text: 'حذف',
|
||||||
|
textStyle: AppFonts.yekan20.copyWith(color: AppColor.redNormal),
|
||||||
|
width: 150.w,
|
||||||
|
height: 40.h,
|
||||||
|
onPressed: () {
|
||||||
|
buildDeleteDialog(
|
||||||
|
onConfirm: () async {
|
||||||
|
controller.isExpandedList.remove(index);
|
||||||
|
controller.deleteSegmentation(item.key!);
|
||||||
|
},
|
||||||
|
onRefresh: () => controller.getAllSegmentation(),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
borderColor: AppColor.redNormal,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget addOrEditBottomSheet([bool isOnEdit = false]) {
|
||||||
|
return BaseBottomSheet(
|
||||||
|
height: 500.h,
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Form(
|
||||||
|
key: controller.formKey,
|
||||||
|
child: Column(
|
||||||
|
spacing: 16,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
isOnEdit ? 'ویرایش قطعهبندی' : 'افزودن قطعهبندی',
|
||||||
|
style: AppFonts.yekan16Bold.copyWith(color: AppColor.blueNormal),
|
||||||
|
),
|
||||||
|
_productDropDown(),
|
||||||
|
|
||||||
|
Container(
|
||||||
|
padding: EdgeInsets.all(8),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
border: Border.all(color: AppColor.darkGreyLight, width: 1),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
spacing: 12,
|
||||||
|
children: [
|
||||||
|
RTextField(
|
||||||
|
controller: controller.weightController,
|
||||||
|
label: 'وزن',
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
borderColor: AppColor.darkGreyLight,
|
||||||
|
filledColor: AppColor.bgLight,
|
||||||
|
filled: true,
|
||||||
|
inputFormatters: [
|
||||||
|
FilteringTextInputFormatter.digitsOnly,
|
||||||
|
SeparatorInputFormatter(),
|
||||||
|
],
|
||||||
|
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null) {
|
||||||
|
return 'لطفاً وزن لاشه را وارد کنید';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
submitButtonWidget(isOnEdit),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget submitButtonWidget(bool isOnEdit) {
|
||||||
|
return ObxValue((data) {
|
||||||
|
return RElevated(
|
||||||
|
isFullWidth: true,
|
||||||
|
backgroundColor: AppColor.greenNormal,
|
||||||
|
text: isOnEdit ? 'ویرایش' : 'ثبت',
|
||||||
|
onPressed: data.value
|
||||||
|
? () async {
|
||||||
|
var res = isOnEdit
|
||||||
|
? await controller.editSegment()
|
||||||
|
: await controller.createSegment();
|
||||||
|
if (res) {
|
||||||
|
controller.getAllSegmentation();
|
||||||
|
controller.clearForm();
|
||||||
|
Get.back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
height: 40,
|
||||||
|
);
|
||||||
|
}, controller.isSaleSubmitButtonEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _productDropDown() {
|
||||||
|
return Obx(() {
|
||||||
|
return OverlayDropdownWidget<ProductModel>(
|
||||||
|
items: controller.rolesProductsModel,
|
||||||
|
height: 56,
|
||||||
|
hasDropIcon: false,
|
||||||
|
background: Colors.white,
|
||||||
|
onChanged: (value) {
|
||||||
|
controller.selectedProduct.value = value;
|
||||||
|
},
|
||||||
|
selectedItem: controller.selectedProduct.value,
|
||||||
|
initialValue: controller.selectedProduct.value,
|
||||||
|
itemBuilder: (item) => Text(item.name ?? 'بدون نام'),
|
||||||
|
labelBuilder: (item) => Row(
|
||||||
|
spacing: 8,
|
||||||
|
children: [
|
||||||
|
(item?.name?.contains('مرغ گرم') ?? false)
|
||||||
|
? Assets.images.chicken.image(width: 40, height: 40)
|
||||||
|
: Assets.vec.placeHolderSvg.svg(width: 40, height: 40),
|
||||||
|
|
||||||
|
Text(item?.name ?? 'انتخاب محصول'),
|
||||||
|
Spacer(),
|
||||||
|
Text(
|
||||||
|
'موجودی:${controller.rootLogic.inventoryModel.value?.totalRemainWeight.separatedByComma ?? 0}',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,6 +20,7 @@ import 'package:rasadyar_chicken/presentation/pages/sales_out_of_province/logic.
|
|||||||
import 'package:rasadyar_chicken/presentation/pages/sales_out_of_province/view.dart';
|
import 'package:rasadyar_chicken/presentation/pages/sales_out_of_province/view.dart';
|
||||||
import 'package:rasadyar_chicken/presentation/pages/sales_out_of_province_buyers/logic.dart';
|
import 'package:rasadyar_chicken/presentation/pages/sales_out_of_province_buyers/logic.dart';
|
||||||
import 'package:rasadyar_chicken/presentation/pages/sales_out_of_province_sales_list/logic.dart';
|
import 'package:rasadyar_chicken/presentation/pages/sales_out_of_province_sales_list/logic.dart';
|
||||||
|
import 'package:rasadyar_chicken/presentation/pages/segmentation/logic.dart';
|
||||||
import 'package:rasadyar_chicken/presentation/routes/routes.dart';
|
import 'package:rasadyar_chicken/presentation/routes/routes.dart';
|
||||||
import 'package:rasadyar_chicken/presentation/widget/base_page/logic.dart';
|
import 'package:rasadyar_chicken/presentation/widget/base_page/logic.dart';
|
||||||
import 'package:rasadyar_chicken/presentation/widget/search/logic.dart';
|
import 'package:rasadyar_chicken/presentation/widget/search/logic.dart';
|
||||||
@@ -40,6 +41,7 @@ sealed class ChickenPages {
|
|||||||
Get.lazyPut(() => BuyLogic());
|
Get.lazyPut(() => BuyLogic());
|
||||||
Get.lazyPut(() => SaleLogic());
|
Get.lazyPut(() => SaleLogic());
|
||||||
Get.lazyPut(() => ProfileLogic());
|
Get.lazyPut(() => ProfileLogic());
|
||||||
|
Get.lazyPut(() => SegmentationLogic());
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
|
|
||||||
@@ -53,7 +55,6 @@ sealed class ChickenPages {
|
|||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|
||||||
//sales
|
//sales
|
||||||
GetPage(
|
GetPage(
|
||||||
name: ChickenRoutes.sale,
|
name: ChickenRoutes.sale,
|
||||||
@@ -61,9 +62,9 @@ sealed class ChickenPages {
|
|||||||
middlewares: [AuthMiddleware()],
|
middlewares: [AuthMiddleware()],
|
||||||
binding: BindingsBuilder(() {
|
binding: BindingsBuilder(() {
|
||||||
Get.lazyPut(() => SaleLogic());
|
Get.lazyPut(() => SaleLogic());
|
||||||
Get.lazyPut(() => BaseLogic());
|
Get.lazyPut(() => BaseLogic());
|
||||||
Get.lazyPut(() => SalesOutOfProvinceLogic());
|
Get.lazyPut(() => SalesOutOfProvinceLogic());
|
||||||
Get.lazyPut(() => RootLogic());
|
Get.lazyPut(() => RootLogic());
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
GetPage(
|
GetPage(
|
||||||
@@ -83,7 +84,7 @@ sealed class ChickenPages {
|
|||||||
middlewares: [AuthMiddleware()],
|
middlewares: [AuthMiddleware()],
|
||||||
binding: BindingsBuilder(() {
|
binding: BindingsBuilder(() {
|
||||||
Get.lazyPut(() => BaseLogic());
|
Get.lazyPut(() => BaseLogic());
|
||||||
Get.lazyPut(() => SalesInProvinceLogic());
|
Get.lazyPut(() => SalesInProvinceLogic());
|
||||||
Get.lazyPut(() => SearchLogic());
|
Get.lazyPut(() => SearchLogic());
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
@@ -98,7 +99,6 @@ sealed class ChickenPages {
|
|||||||
Get.lazyPut(() => BuyLogic());
|
Get.lazyPut(() => BuyLogic());
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
|
|
||||||
GetPage(
|
GetPage(
|
||||||
name: ChickenRoutes.buysOutOfProvince,
|
name: ChickenRoutes.buysOutOfProvince,
|
||||||
page: () => BuyOutOfProvincePage(),
|
page: () => BuyOutOfProvincePage(),
|
||||||
@@ -106,10 +106,9 @@ sealed class ChickenPages {
|
|||||||
binding: BindingsBuilder(() {
|
binding: BindingsBuilder(() {
|
||||||
Get.lazyPut(() => BaseLogic());
|
Get.lazyPut(() => BaseLogic());
|
||||||
Get.lazyPut(() => SearchLogic());
|
Get.lazyPut(() => SearchLogic());
|
||||||
Get.lazyPut(() => BuyOutOfProvinceLogic());
|
Get.lazyPut(() => BuyOutOfProvinceLogic());
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
|
|
||||||
GetPage(
|
GetPage(
|
||||||
name: ChickenRoutes.buysInProvince,
|
name: ChickenRoutes.buysInProvince,
|
||||||
page: () => BuyInProvincePage(),
|
page: () => BuyInProvincePage(),
|
||||||
@@ -117,9 +116,9 @@ sealed class ChickenPages {
|
|||||||
binding: BindingsBuilder(() {
|
binding: BindingsBuilder(() {
|
||||||
Get.lazyPut(() => BaseLogic());
|
Get.lazyPut(() => BaseLogic());
|
||||||
Get.lazyPut(() => SearchLogic());
|
Get.lazyPut(() => SearchLogic());
|
||||||
Get.lazyPut(() => BuyInProvinceLogic());
|
Get.lazyPut(() => BuyInProvinceLogic());
|
||||||
Get.lazyPut(() => BuyInProvinceWaitingLogic());
|
Get.lazyPut(() => BuyInProvinceWaitingLogic());
|
||||||
Get.lazyPut(() => BuyInProvinceAllLogic());
|
Get.lazyPut(() => BuyInProvinceAllLogic());
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ sealed class ChickenRoutes {
|
|||||||
static const home = '$_base/home';
|
static const home = '$_base/home';
|
||||||
static const buy = '$_base/buy';
|
static const buy = '$_base/buy';
|
||||||
static const sale = '$_base/sale';
|
static const sale = '$_base/sale';
|
||||||
|
static const segmentation = '$_base/segmentation';
|
||||||
|
|
||||||
//buys
|
//buys
|
||||||
static const buysOutOfProvince = '$buy/buyOutOfProvince';
|
static const buysOutOfProvince = '$buy/buyOutOfProvince';
|
||||||
@@ -14,4 +15,6 @@ sealed class ChickenRoutes {
|
|||||||
//sales
|
//sales
|
||||||
static const salesInProvince = '$sale/SalesInProvince';
|
static const salesInProvince = '$sale/SalesInProvince';
|
||||||
static const salesOutOfProvince = '$sale/saleOutOfProvince';
|
static const salesOutOfProvince = '$sale/saleOutOfProvince';
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,9 +48,9 @@ export 'package:image_picker/image_picker.dart';
|
|||||||
//utils
|
//utils
|
||||||
export 'utils/logger_utils.dart';
|
export 'utils/logger_utils.dart';
|
||||||
export 'utils/network/network.dart';
|
export 'utils/network/network.dart';
|
||||||
export 'utils/date_time_utils.dart';
|
export 'utils/extension/date_time_utils.dart';
|
||||||
export 'utils/num_utils.dart';
|
export 'utils/extension/num_utils.dart';
|
||||||
export 'utils/map_utils.dart';
|
export 'utils/map_utils.dart';
|
||||||
export 'utils/route_utils.dart';
|
export 'utils/route_utils.dart';
|
||||||
export 'utils/string_utils.dart';
|
export 'utils/extension/string_utils.dart';
|
||||||
export 'utils/separator_input_formatter.dart';
|
export 'utils/separator_input_formatter.dart';
|
||||||
|
|||||||
13
packages/core/lib/utils/extension/date_time_utils.dart
Normal file
13
packages/core/lib/utils/extension/date_time_utils.dart
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import 'package:intl/intl.dart';
|
||||||
|
import 'package:persian_datetime_picker/persian_datetime_picker.dart';
|
||||||
|
|
||||||
|
extension XDateTime2 on DateTime {
|
||||||
|
get formattedJalaliDate {
|
||||||
|
final jalaliDate = Jalali.fromDateTime(this);
|
||||||
|
return "${jalaliDate.year}/${jalaliDate.month.toString().padLeft(2, '0')}/${jalaliDate.day.toString().padLeft(2, '0')}";
|
||||||
|
}
|
||||||
|
|
||||||
|
get formattedYHMS {
|
||||||
|
return DateFormat('yyyy-MM-dd HH:mm:ss').format(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,18 @@
|
|||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:persian_datetime_picker/persian_datetime_picker.dart';
|
import 'package:persian_datetime_picker/persian_datetime_picker.dart';
|
||||||
|
|
||||||
extension XDateTime on String {
|
extension XString on String {
|
||||||
|
String get separatedByComma {
|
||||||
|
final formatter = NumberFormat('#,###');
|
||||||
|
final number = num.tryParse(this);
|
||||||
|
return number != null ? formatter.format(number) : this;
|
||||||
|
}
|
||||||
|
|
||||||
|
String get clearComma {
|
||||||
|
return replaceAll(RegExp(r'\D'), '');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
get toDateTime => DateTime.parse(this);
|
get toDateTime => DateTime.parse(this);
|
||||||
|
|
||||||
String get formattedJalaliDate {
|
String get formattedJalaliDate {
|
||||||
@@ -26,15 +37,4 @@ extension XDateTime on String {
|
|||||||
final dateTime = DateTime.parse(this);
|
final dateTime = DateTime.parse(this);
|
||||||
return Jalali.fromDateTime(dateTime);
|
return Jalali.fromDateTime(dateTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension XDateTime2 on DateTime {
|
|
||||||
get formattedJalaliDate {
|
|
||||||
final jalaliDate = Jalali.fromDateTime(this);
|
|
||||||
return "${jalaliDate.year}/${jalaliDate.month.toString().padLeft(2, '0')}/${jalaliDate.day.toString().padLeft(2, '0')}";
|
|
||||||
}
|
|
||||||
|
|
||||||
get formattedYHMS {
|
|
||||||
return DateFormat('yyyy-MM-dd HH:mm:ss').format(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
import 'package:intl/intl.dart';
|
|
||||||
|
|
||||||
extension XString on String {
|
|
||||||
String get separatedByComma {
|
|
||||||
final formatter = NumberFormat('#,###');
|
|
||||||
final number = num.tryParse(this);
|
|
||||||
return number != null ? formatter.format(number) : this;
|
|
||||||
}
|
|
||||||
|
|
||||||
String get clearComma {
|
|
||||||
return replaceAll(RegExp(r'\D'), '');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
14
packages/core/lib/utils/utils.dart
Normal file
14
packages/core/lib/utils/utils.dart
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
export 'mixins/pagination_controller_mixin.dart';
|
||||||
|
|
||||||
|
export 'network/network.dart';
|
||||||
|
|
||||||
|
export 'extension/date_time_utils.dart';
|
||||||
|
export 'extension/num_utils.dart';
|
||||||
|
export 'extension/string_utils.dart';
|
||||||
|
|
||||||
|
export 'apk_updater.dart';
|
||||||
|
export 'logger_utils.dart';
|
||||||
|
export 'map_utils.dart';
|
||||||
|
export 'route_utils.dart';
|
||||||
|
export 'separator_input_formatter.dart';
|
||||||
|
|
||||||
Reference in New Issue
Block a user