diff --git a/.gitignore b/.gitignore index 9bf7bd95..f90ad501 100644 --- a/.gitignore +++ b/.gitignore @@ -16,7 +16,7 @@ migrate_working_dir/ *.iws .idea/ -# The .vscode folder contains launch configuration and tasks you configure in +# The .vscode folder contains launch configuration and tasks_request you configure in # VS Code which you may wish to be included in version control, so this line # is commented out by default. #.vscode/ diff --git a/android/key.properties b/android/key.properties index 6a8cd33e..9cd1c57c 100644 --- a/android/key.properties +++ b/android/key.properties @@ -1,4 +1,5 @@ storePassword=Cloud@AtomsSA keyPassword=Cloud@AtomsSA keyAlias=playstore -storeFile=/Users/sikandersaleem/StudioProjects/cloudsolutions-atoms/android/AtomsSA-playStore.jks +#storeFile=/Users/sikandersaleem/StudioProjects/cloudsolutions-atoms/android/AtomsSA-playStore.jks +storeFile=AtomsSA-playStore.jks diff --git a/lib/l10n/app_ar.arb b/lib/l10n/app_ar.arb index b8cb09a2..ec5b4223 100644 --- a/lib/l10n/app_ar.arb +++ b/lib/l10n/app_ar.arb @@ -549,6 +549,10 @@ "attachments": "المرفقات", "supplierName": "اسم المورد", "externalEngineerName": "اسم المهندس الخارجي", - "telephone": "الهاتف" + "telephone": "الهاتف", + "task": "مهمة", + "taskType": "نوع المهمة", + "createTaskRequest": "إنشاء طلب مهمة", + "taskRequest": "طلب مهمة" } \ No newline at end of file diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 07b5420a..d5958ab2 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -552,5 +552,9 @@ "attachments": "Attachments", "supplierName": "Supplier Name", "externalEngineerName": "External Engineer Name", - "telephone": "Telephone" + "telephone": "Telephone", + "task": "Task", + "taskType": "Task Type", + "createTaskRequest": "Create Task Request", + "taskRequest": "Task Request" } \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index b16998bd..c2082ad1 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -97,6 +97,8 @@ import 'package:timezone/data/latest_all.dart' as tz; import 'package:timezone/timezone.dart' as tz; import 'package:test_sa/views/update_available_screen.dart'; +import 'views/pages/user/tasks_request/create_task_view.dart'; + void main() async { WidgetsFlutterBinding.ensureInitialized(); @@ -291,6 +293,7 @@ class MyApp extends StatelessWidget { LandPage.routeName: (_) => const LandPage(), NewGasRefillRequestPage.routeName: (_) => const NewGasRefillRequestPage(), ServiceRequestsPage.id: (_) => const ServiceRequestsPage(), + CreateTaskView.id: (_) => const CreateTaskView(), //ReportIssuesPage.id: (_) => ReportIssuesPage(), RequestGasRefill.id: (_) => const RequestGasRefill(), CreateServiceRequestPage.id: (_) => const CreateServiceRequestPage(), diff --git a/lib/new_views/pages/land_page/create_request-type_bottomsheet.dart b/lib/new_views/pages/land_page/create_request-type_bottomsheet.dart index 87206116..f85cec84 100644 --- a/lib/new_views/pages/land_page/create_request-type_bottomsheet.dart +++ b/lib/new_views/pages/land_page/create_request-type_bottomsheet.dart @@ -6,6 +6,7 @@ import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/pages/new_gas_refill_request_page.dart'; import 'package:test_sa/service_request_latest/views/nurse/create_new_request_view.dart'; import 'package:test_sa/views/pages/device_transfer/request_device_transfer.dart'; +import 'package:test_sa/views/pages/user/tasks_request/create_task_view.dart'; class CreateRequestTypeBottomSheet extends StatelessWidget { const CreateRequestTypeBottomSheet({super.key}); @@ -52,6 +53,14 @@ class CreateRequestTypeBottomSheet extends StatelessWidget { Navigator.pushReplacementNamed(context, RequestDeviceTransfer.id); }, ), + listCard( + context: context, + icon: 'add_icon', + label: context.translation.task, + onTap: () async { + Navigator.pushReplacementNamed(context, CreateTaskView.id); + }, + ), ], ), 16.height, diff --git a/lib/new_views/pages/land_page/my_request/my_requests_page.dart b/lib/new_views/pages/land_page/my_request/my_requests_page.dart index fa744dbd..df80d66b 100644 --- a/lib/new_views/pages/land_page/my_request/my_requests_page.dart +++ b/lib/new_views/pages/land_page/my_request/my_requests_page.dart @@ -38,6 +38,7 @@ class _MyRequestsPageState extends State { context.translation.deviceTransferRequest, context.translation.preventiveMaintenance, context.translation.recurrentWo, + context.translation.taskRequest, ]; _provider = Provider.of(context, listen: false); _provider!.reset(); @@ -134,7 +135,13 @@ class _MyRequestsPageState extends State { selectedRequest = index; }); _provider!.reset(); - _provider!.getAllRequests(context, typeTransaction: selectedRequest == 0 ? null : selectedRequest); + //TODO need to remove this after testing and getting api ... + if(index==6){ + _provider!.getAllRequests(context, typeTransaction: 5); + }else{ + _provider!.getAllRequests(context, typeTransaction: selectedRequest == 0 ? null : selectedRequest); + + } } }), separatorBuilder: (cxt, index) => 8.width, diff --git a/lib/new_views/pages/land_page/widgets/request_item_view_list.dart b/lib/new_views/pages/land_page/widgets/request_item_view_list.dart index 67eafa6c..759c7a7a 100644 --- a/lib/new_views/pages/land_page/widgets/request_item_view_list.dart +++ b/lib/new_views/pages/land_page/widgets/request_item_view_list.dart @@ -9,6 +9,7 @@ import 'package:test_sa/new_views/pages/land_page/requests/gas_refill_item_view. import 'package:test_sa/new_views/pages/land_page/requests/ppm_item_view.dart'; import 'package:test_sa/new_views/pages/land_page/requests/recurrent_wo_item_view.dart'; import 'package:test_sa/new_views/pages/land_page/requests/service_request_item_view.dart'; +import 'package:test_sa/views/pages/user/tasks_request/task_request_item_view.dart'; import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; class RequestItemViewList extends StatelessWidget { @@ -26,6 +27,7 @@ class RequestItemViewList extends StatelessWidget { shrinkWrap: true, itemBuilder: (cxt, index) { if (isLoading) return const SizedBox().toRequestShimmer(cxt, isLoading); + list[index].transactionType=6; switch(list[index].transactionType){ case 1: return ServiceRequestItemView(requestDetails: list[index]); @@ -37,6 +39,9 @@ class RequestItemViewList extends StatelessWidget { return PpmItemView(requestDetails: list[index]); case 5: return RecurrentWoItemView(requestDetails: list[index]); + //TODO need to confirm this value... + case 6: + return TaskRequestItemView(requestDetails: list[index]); default: Container( height: 100, diff --git a/lib/views/pages/user/tasks_request/create_task_view.dart b/lib/views/pages/user/tasks_request/create_task_view.dart new file mode 100644 index 00000000..f9c30d05 --- /dev/null +++ b/lib/views/pages/user/tasks_request/create_task_view.dart @@ -0,0 +1,219 @@ +import 'dart:convert'; +import 'dart:io'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/providers/api/service_requests_provider.dart'; +import 'package:test_sa/dashboard_latest/dashboard_provider.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/device/asset.dart'; +import 'package:test_sa/models/enums/user_types.dart'; +import 'package:test_sa/models/helper_data_models/workorder/work_order_helper_models.dart'; +import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/models/service_request/pending_service_request_model.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; +import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; +import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; +import 'package:test_sa/providers/service_request_providers/last_situation_provider.dart'; +import 'package:test_sa/service_request_latest/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/views/pages/user/requests/pending_requests_screen.dart'; +import 'package:test_sa/views/widgets/bottom_sheets/pending_request_bottom_sheet.dart'; +import 'package:test_sa/views/widgets/equipment/asset_picker.dart'; +import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; +import '../../../../../../new_views/common_widgets/default_app_bar.dart'; + + +class CreateTaskView extends StatefulWidget { + static const String id = "/create-task"; + + const CreateTaskView({Key? key}) : super(key: key); + + @override + _CreateTaskViewState createState() => _CreateTaskViewState(); +} + +class _CreateTaskViewState extends State with TickerProviderStateMixin { + final List _deviceImages = []; + final GlobalKey _formKey = GlobalKey(); + final GlobalKey _scaffoldKey = GlobalKey(); + + //TODO need to replace with model attribute + Asset? _device; + PendingAssetServiceRequest? pendingAssetServiceRequest; + + bool _isLocalUrl(String url) { + if (url.isEmpty != false) return false; + return url.startsWith("/") || url.startsWith("file://") || url.substring(1).startsWith(':\\'); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + key: _scaffoldKey, + appBar: DefaultAppBar(title: context.translation.createTaskRequest), + body: Consumer(builder: (context, serviceRequestProvider, child) { + return SafeArea( + child: Form( + key: _formKey, + child: Column( + children: [ + SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + scanAssetButton(), + if (pendingAssetServiceRequest != null && pendingAssetServiceRequest!.details!.isNotEmpty) ...[ + 8.height, + Row( + children: [ + const Icon(Icons.warning, color: Color(0xffEE404C), size: 14), + 8.width, + Text( + "This asset already have ${pendingAssetServiceRequest!.details!.length} request pending", + style: const TextStyle(fontSize: 12, fontWeight: FontWeight.w500, color: Color(0xff7D859A), decoration: TextDecoration.underline), + ).expanded, + ], + ).onPress(() { + showPendingRequests(); + }), + ], + 16.height, + //TODO replace with provided lookup.. + SingleItemDropDownMenu( + context: context, + height: 56.toScreenHeight, + title: context.translation.taskType, + showShadow: false, + backgroundColor: AppColor.neutral100, + showAsBottomSheet: true, + initialValue: null, + onSelect: (status) { + if (status != null) { + setState(() {}); + } + }, + ), + 12.height, + AppTextFormField( + initialValue: '', + labelText: context.translation.technicalComment, + backgroundColor: AppColor.neutral100, + showShadow: false, + labelStyle: AppTextStyles.textFieldLabelStyle, + alignLabelWithHint: true, + textInputType: TextInputType.multiline, + onChange: (value) { + //save value to model attribute.. + }, + ), + 23.height, + MultiFilesPicker( + label: context.translation.attachImage, + files: _deviceImages, + buttonColor: AppColor.black10, + onlyImages: true, + buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.neutral120), + ), + ], + ).toShadowContainer(context).paddingAll(16), + ).expanded, + FooterActionButton.footerContainer( + child: AppFilledButton( + buttonColor: AppColor.primary10, + label: context.translation.submitRequest, + onPressed: checkPendingRequest ? null : _submit, + // buttonColor: AppColor.primary10, + ), + ), + ], + ), + ), + ); + }), + ); + } + + Widget scanAssetButton() { + return AssetPicker( + device: _device, + showLoading: checkPendingRequest, + borderColor: AppColor.black20, + buttonColor: AppColor.white936, + onPick: (asset) async { + pendingAssetServiceRequest = null; + _device = asset; + // _serviceRequest.device = asset; + await checkAssetForPendingServiceRequest(asset.id!.toInt()); + if (pendingAssetServiceRequest != null && pendingAssetServiceRequest!.details!.isNotEmpty) { + showPendingRequestBottomSheet(); + } + }, + ); + } + + bool checkPendingRequest = false; + + void showPendingRequests() { + Navigator.of(context).push(MaterialPageRoute(builder: (_) => PendingServiceRequestScreen(pendingAssetServiceRequest!))); + } + + void showPendingRequestBottomSheet() async { + bool view = (await showModalBottomSheet( + context: context, + isDismissible: false, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.vertical( + top: Radius.circular(20), + ), + ), + clipBehavior: Clip.antiAliasWithSaveLayer, + builder: (BuildContext context) => PendingRequestBottomSheet(pendingAssetServiceRequest!, _device ?? Asset()), + )) as bool; + if (view) { + showPendingRequests(); + } + } + + Future checkAssetForPendingServiceRequest(int assetId) async { + checkPendingRequest = true; + setState(() {}); + + pendingAssetServiceRequest = await Provider.of(context, listen: false).checkAssetPendingRequest(assetId); + await Future.delayed(const Duration(milliseconds: 250)); + + checkPendingRequest = false; + setState(() {}); + } + + Future _submit() async { + if (_formKey.currentState!.validate()) { + _formKey.currentState!.save(); + + + // List attachement = []; + // for (var item in _deviceImages) { + // attachement.add(WorkOrderAttachments(id: 0, name: "${item.path.split("/").last}|${base64Encode(item.readAsBytesSync())}")); + // } + + // int status = 0; + // if (status == 200) { + // DashBoardProvider dashBoardProvider = Provider.of(context, listen: false); + // dashBoardProvider.refreshDashboard(context: context, userType: UsersTypes.nurse); + // Navigator.pop(context); + // Navigator.pop(context); + // } else { + // Navigator.pop(context); + // } + + // await _serviceRequestsProvider.createRequest( + // context: context, + // user: _userProvider.user!, + // host: _settingProvider.host!, + // serviceRequest: _serviceRequest, + // ); + } + } +} diff --git a/lib/views/pages/user/tasks_request/task_request_item_view.dart b/lib/views/pages/user/tasks_request/task_request_item_view.dart new file mode 100644 index 00000000..bbe5a32d --- /dev/null +++ b/lib/views/pages/user/tasks_request/task_request_item_view.dart @@ -0,0 +1,73 @@ +import 'package:flutter/material.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/all_requests_and_count_model.dart'; +import 'package:test_sa/models/new_models/dashboard_detail.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/views/pages/user/ppm/ppm_work_order/recurrent_wo/recurrent_work_order_view.dart'; +import 'package:test_sa/views/widgets/requests/request_status.dart'; + +class TaskRequestItemView extends StatelessWidget { + final Data? requestData; + final RequestsDetails? requestDetails; + final bool showShadow; + + const TaskRequestItemView({Key? key, this.requestData, this.requestDetails, this.showShadow = true}) : super(key: key); + + @override + Widget build(BuildContext context) { + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + StatusLabel( + label: requestDetails!.priority!, + textColor: AppColor.getRequestStatusTextColorByName(context, requestDetails!.priority!), + backgroundColor: AppColor.getRequestStatusColorByName(context, requestDetails!.priority!), + ), + 8.width, + StatusLabel( + label: requestDetails!.status!, + textColor: AppColor.getRequestStatusTextColorByName(context, requestDetails!.status!), + backgroundColor: AppColor.getRequestStatusColorByName(context, requestDetails!.status!), + ), + 1.width.expanded, + Text( + requestDetails!.date?.toServiceRequestCardFormat ?? "", + textAlign: TextAlign.end, + style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50), + ), + ], + ), + 8.height, + // (requestDetails?.nameOfType ?? context.translation.taskRequest).heading5(context), + context.translation.taskRequest.heading5(context), + 8.height, + // '${context.translation.taskNo}: ${requestDetails!.id}'.bodyText(context), + '${context.translation.taskType}: ${'Task Type.'}'.bodyText(context), + // '${context.translation.code}: ${request.code}'.bodyText(context), + '${context.translation.taskNo}: ${'Task number'}'.bodyText(context), + 16.height, + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + context.translation.viewDetails, + style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context)), + ), + 4.width, + Icon(Icons.arrow_forward, color: AppColor.blueStatus(context), size: 14) + ], + ), + ], + ).toShadowContainer(context, withShadow: showShadow).onPress(() async { + Navigator.of(context).push(MaterialPageRoute(builder: (_) => RecurrentWorkOrderView(taskId: requestDetails!.id))); + }); + } +} diff --git a/lib/views/pages/user/tasks_request/task_request_view.dart b/lib/views/pages/user/tasks_request/task_request_view.dart new file mode 100644 index 00000000..e69de29b diff --git a/lib/views/widgets/equipment/asset_picker.dart b/lib/views/widgets/equipment/asset_picker.dart index bc3dcd17..4cfbd186 100644 --- a/lib/views/widgets/equipment/asset_picker.dart +++ b/lib/views/widgets/equipment/asset_picker.dart @@ -15,10 +15,12 @@ class AssetPicker extends StatelessWidget { final bool editable; final bool showAssetInfo; final Color? borderColor; + final Color? buttonColor; final bool forPPM; final bool showLoading; - const AssetPicker({Key? key, this.editable = true, this.device, this.onPick,this.borderColor, this.showAssetInfo = true, this.forPPM = false, this.showLoading = false}) : super(key: key); + const AssetPicker({Key? key, this.editable = true, this.device, this.onPick, this.borderColor, this.buttonColor, this.showAssetInfo = true, this.forPPM = false, this.showLoading = false}) + : super(key: key); @override Widget build(BuildContext context) { @@ -29,7 +31,7 @@ class AssetPicker extends StatelessWidget { height: 50, alignment: Alignment.center, decoration: BoxDecoration( - color: AppColor.blueStatus(context), + color: buttonColor ?? AppColor.blueStatus(context), borderRadius: BorderRadius.circular(10), // boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.03), blurRadius: 14)], ), @@ -43,7 +45,10 @@ class AssetPicker extends StatelessWidget { ], ), ).onPress(() async { - Asset? device = await Navigator.of(context).push(MaterialPageRoute(builder: (context)=>AssetScanQr(title: context.translation.assetScan,))) as Asset?; + Asset? device = await Navigator.of(context).push(MaterialPageRoute( + builder: (context) => AssetScanQr( + title: context.translation.assetScan, + ))) as Asset?; if (device != null) { onPick!(device); } @@ -53,7 +58,7 @@ class AssetPicker extends StatelessWidget { height: 50, alignment: Alignment.center, decoration: BoxDecoration( - color: Colors.white, borderRadius: BorderRadius.circular(10), border: Border.all(color:borderColor?? AppColor.blueStatus(context), width: 2), + color: Colors.white, borderRadius: BorderRadius.circular(10), border: Border.all(color: borderColor ?? AppColor.blueStatus(context), width: 2), // boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.03), blurRadius: 14)], ), padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 8.toScreenHeight), @@ -66,7 +71,10 @@ class AssetPicker extends StatelessWidget { ], ), ).onPress(() async { - Asset? device = await Navigator.of(context).push(MaterialPageRoute(builder: (context)=>AssetScanQr(title: context.translation.assetScan,))) as Asset?; + Asset? device = await Navigator.of(context).push(MaterialPageRoute( + builder: (context) => AssetScanQr( + title: context.translation.assetScan, + ))) as Asset?; if (device != null) { onPick!(device); }