feat : segmentation page
This commit is contained in:
@@ -6,7 +6,7 @@ part 'segmentation_model.g.dart';
|
||||
|
||||
@freezed
|
||||
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;
|
||||
|
||||
factory SegmentationModel.fromJson(Map<String, dynamic> json) =>
|
||||
|
||||
@@ -16,7 +16,7 @@ T _$identity<T>(T value) => value;
|
||||
/// @nodoc
|
||||
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
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@@ -49,7 +49,7 @@ abstract mixin class $SegmentationModelCopyWith<$Res> {
|
||||
factory $SegmentationModelCopyWith(SegmentationModel value, $Res Function(SegmentationModel) _then) = _$SegmentationModelCopyWithImpl;
|
||||
@useResult
|
||||
$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 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 double?,
|
||||
as int?,
|
||||
));
|
||||
}
|
||||
/// Create a copy of SegmentationModel
|
||||
@@ -101,7 +101,7 @@ class _SegmentationModel implements SegmentationModel {
|
||||
@override final String? key;
|
||||
@override final Buyer? buyer;
|
||||
@override final DateTime? date;
|
||||
@override final double? weight;
|
||||
@override final int? weight;
|
||||
|
||||
/// Create a copy of SegmentationModel
|
||||
/// 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;
|
||||
@override @useResult
|
||||
$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 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 double?,
|
||||
as int?,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ _SegmentationModel _$SegmentationModelFromJson(Map<String, dynamic> json) =>
|
||||
date: json['date'] == null
|
||||
? null
|
||||
: DateTime.parse(json['date'] as String),
|
||||
weight: (json['weight'] as num?)?.toDouble(),
|
||||
weight: (json['weight'] as num?)?.toInt(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$SegmentationModelToJson(_SegmentationModel instance) =>
|
||||
|
||||
@@ -148,6 +148,8 @@ abstract class ChickenRepository {
|
||||
Map<String, dynamic>? queryParameters,
|
||||
});
|
||||
|
||||
Future<void> createSegmentation({required String token, required SegmentationModel model});
|
||||
|
||||
Future<void> editSegmentation({required String token, required SegmentationModel model});
|
||||
|
||||
Future<void> deleteSegmentation({required String token, required String key});
|
||||
|
||||
@@ -450,6 +450,15 @@ class ChickenRepositoryImpl implements ChickenRepository {
|
||||
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
|
||||
Future<void> editSegmentation({required String token, required SegmentationModel model}) async {
|
||||
await _httpClient.put(
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart' show Colors;
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:rasadyar_auth/data/services/token_storage_service.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/profile/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/utils/utils.dart';
|
||||
import 'package:rasadyar_core/core.dart';
|
||||
@@ -21,13 +21,7 @@ enum ErrorLocationType { serviceDisabled, permissionDenied, none }
|
||||
|
||||
class RootLogic extends GetxController {
|
||||
RxInt currentPage = 2.obs;
|
||||
List<Widget> pages = [
|
||||
BuyPage(),
|
||||
SalePage(),
|
||||
HomePage(),
|
||||
Container(color: Colors.blue),
|
||||
ProfilePage(),
|
||||
];
|
||||
List<Widget> pages = [BuyPage(), SalePage(), HomePage(), SegmentationPage(), ProfilePage()];
|
||||
|
||||
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_buyers/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/widget/base_page/logic.dart';
|
||||
import 'package:rasadyar_chicken/presentation/widget/search/logic.dart';
|
||||
@@ -40,6 +41,7 @@ sealed class ChickenPages {
|
||||
Get.lazyPut(() => BuyLogic());
|
||||
Get.lazyPut(() => SaleLogic());
|
||||
Get.lazyPut(() => ProfileLogic());
|
||||
Get.lazyPut(() => SegmentationLogic());
|
||||
}),
|
||||
),
|
||||
|
||||
@@ -53,7 +55,6 @@ sealed class ChickenPages {
|
||||
}),
|
||||
),
|
||||
|
||||
|
||||
//sales
|
||||
GetPage(
|
||||
name: ChickenRoutes.sale,
|
||||
@@ -98,7 +99,6 @@ sealed class ChickenPages {
|
||||
Get.lazyPut(() => BuyLogic());
|
||||
}),
|
||||
),
|
||||
|
||||
GetPage(
|
||||
name: ChickenRoutes.buysOutOfProvince,
|
||||
page: () => BuyOutOfProvincePage(),
|
||||
@@ -109,7 +109,6 @@ sealed class ChickenPages {
|
||||
Get.lazyPut(() => BuyOutOfProvinceLogic());
|
||||
}),
|
||||
),
|
||||
|
||||
GetPage(
|
||||
name: ChickenRoutes.buysInProvince,
|
||||
page: () => BuyInProvincePage(),
|
||||
|
||||
@@ -6,6 +6,7 @@ sealed class ChickenRoutes {
|
||||
static const home = '$_base/home';
|
||||
static const buy = '$_base/buy';
|
||||
static const sale = '$_base/sale';
|
||||
static const segmentation = '$_base/segmentation';
|
||||
|
||||
//buys
|
||||
static const buysOutOfProvince = '$buy/buyOutOfProvince';
|
||||
@@ -14,4 +15,6 @@ sealed class ChickenRoutes {
|
||||
//sales
|
||||
static const salesInProvince = '$sale/SalesInProvince';
|
||||
static const salesOutOfProvince = '$sale/saleOutOfProvince';
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -48,9 +48,9 @@ export 'package:image_picker/image_picker.dart';
|
||||
//utils
|
||||
export 'utils/logger_utils.dart';
|
||||
export 'utils/network/network.dart';
|
||||
export 'utils/date_time_utils.dart';
|
||||
export 'utils/num_utils.dart';
|
||||
export 'utils/extension/date_time_utils.dart';
|
||||
export 'utils/extension/num_utils.dart';
|
||||
export 'utils/map_utils.dart';
|
||||
export 'utils/route_utils.dart';
|
||||
export 'utils/string_utils.dart';
|
||||
export 'utils/extension/string_utils.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: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);
|
||||
|
||||
String get formattedJalaliDate {
|
||||
@@ -27,14 +38,3 @@ extension XDateTime on String {
|
||||
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