Merge branch 'refs/heads/demo_branch' into design_3.0_tm_module_task_flow

# Conflicts:
#	lib/controllers/api_routes/urls.dart
#	lib/extensions/widget_extensions.dart
#	lib/l10n/app_ar.arb
#	lib/l10n/app_en.arb
#	lib/new_views/pages/land_page/create_request-type_bottomsheet.dart
#	lib/new_views/pages/new_gas_refill_request_page.dart
#	lib/views/pages/user/gas_refill/request_gas_refill.dart
#	lib/views/widgets/equipment/asset_picker.dart
design_3.0_demo_module
Sikander Saleem 1 year ago
commit e0902eddf7

@ -0,0 +1,371 @@
PODS:
- audio_session (0.0.1):
- Flutter
- audioplayers_darwin (0.0.1):
- Flutter
- device_calendar (0.0.1):
- Flutter
- DKImagePickerController/Core (4.3.9):
- DKImagePickerController/ImageDataManager
- DKImagePickerController/Resource
- DKImagePickerController/ImageDataManager (4.3.9)
- DKImagePickerController/PhotoGallery (4.3.9):
- DKImagePickerController/Core
- DKPhotoGallery
- DKImagePickerController/Resource (4.3.9)
- DKPhotoGallery (0.0.19):
- DKPhotoGallery/Core (= 0.0.19)
- DKPhotoGallery/Model (= 0.0.19)
- DKPhotoGallery/Preview (= 0.0.19)
- DKPhotoGallery/Resource (= 0.0.19)
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Core (0.0.19):
- DKPhotoGallery/Model
- DKPhotoGallery/Preview
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Model (0.0.19):
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Preview (0.0.19):
- DKPhotoGallery/Model
- DKPhotoGallery/Resource
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Resource (0.0.19):
- SDWebImage
- SwiftyGif
- DTTJailbreakDetection (0.4.0)
- file_picker (0.0.1):
- DKImagePickerController/PhotoGallery
- Flutter
- Firebase/CoreOnly (11.2.0):
- FirebaseCore (= 11.2.0)
- Firebase/Messaging (11.2.0):
- Firebase/CoreOnly
- FirebaseMessaging (~> 11.2.0)
- firebase_core (3.6.0):
- Firebase/CoreOnly (= 11.2.0)
- Flutter
- firebase_messaging (15.1.3):
- Firebase/Messaging (= 11.2.0)
- firebase_core
- Flutter
- FirebaseCore (11.2.0):
- FirebaseCoreInternal (~> 11.0)
- GoogleUtilities/Environment (~> 8.0)
- GoogleUtilities/Logger (~> 8.0)
- FirebaseCoreInternal (11.9.0):
- "GoogleUtilities/NSData+zlib (~> 8.0)"
- FirebaseInstallations (11.4.0):
- FirebaseCore (~> 11.0)
- GoogleUtilities/Environment (~> 8.0)
- GoogleUtilities/UserDefaults (~> 8.0)
- PromisesObjC (~> 2.4)
- FirebaseMessaging (11.2.0):
- FirebaseCore (~> 11.0)
- FirebaseInstallations (~> 11.0)
- GoogleDataTransport (~> 10.0)
- GoogleUtilities/AppDelegateSwizzler (~> 8.0)
- GoogleUtilities/Environment (~> 8.0)
- GoogleUtilities/Reachability (~> 8.0)
- GoogleUtilities/UserDefaults (~> 8.0)
- nanopb (~> 3.30910.0)
- Flutter (1.0.0)
- flutter_keyboard_visibility (0.0.1):
- Flutter
- flutter_local_notifications (0.0.1):
- Flutter
- flutter_sound (9.6.0):
- Flutter
- flutter_sound_core (= 9.6.0)
- flutter_sound_core (9.6.0)
- flutter_timezone (0.0.1):
- Flutter
- fluttertoast (0.0.2):
- Flutter
- Toast
- FMDB (2.7.12):
- FMDB/standard (= 2.7.12)
- FMDB/Core (2.7.12)
- FMDB/standard (2.7.12):
- FMDB/Core
- geolocator_apple (1.2.0):
- Flutter
- GoogleDataTransport (10.1.0):
- nanopb (~> 3.30910.0)
- PromisesObjC (~> 2.4)
- GoogleUtilities/AppDelegateSwizzler (8.0.2):
- GoogleUtilities/Environment
- GoogleUtilities/Logger
- GoogleUtilities/Network
- GoogleUtilities/Privacy
- GoogleUtilities/Environment (8.0.2):
- GoogleUtilities/Privacy
- GoogleUtilities/Logger (8.0.2):
- GoogleUtilities/Environment
- GoogleUtilities/Privacy
- GoogleUtilities/Network (8.0.2):
- GoogleUtilities/Logger
- "GoogleUtilities/NSData+zlib"
- GoogleUtilities/Privacy
- GoogleUtilities/Reachability
- "GoogleUtilities/NSData+zlib (8.0.2)":
- GoogleUtilities/Privacy
- GoogleUtilities/Privacy (8.0.2)
- GoogleUtilities/Reachability (8.0.2):
- GoogleUtilities/Logger
- GoogleUtilities/Privacy
- GoogleUtilities/UserDefaults (8.0.2):
- GoogleUtilities/Logger
- GoogleUtilities/Privacy
- image_cropper (0.0.4):
- Flutter
- TOCropViewController (~> 2.7.4)
- image_picker_ios (0.0.1):
- Flutter
- just_audio (0.0.1):
- Flutter
- local_auth_darwin (0.0.1):
- Flutter
- FlutterMacOS
- MTBBarcodeScanner (5.0.11)
- nanopb (3.30910.0):
- nanopb/decode (= 3.30910.0)
- nanopb/encode (= 3.30910.0)
- nanopb/decode (3.30910.0)
- nanopb/encode (3.30910.0)
- nfc_manager (0.0.1):
- Flutter
- open_file_ios (0.0.1):
- Flutter
- package_info_plus (0.4.5):
- Flutter
- path_provider_foundation (0.0.1):
- Flutter
- FlutterMacOS
- permission_handler_apple (9.3.0):
- Flutter
- pointer_interceptor_ios (0.0.1):
- Flutter
- PromisesObjC (2.4.0)
- qr_code_scanner (0.2.0):
- Flutter
- MTBBarcodeScanner
- record_mp3_plus (1.0.0):
- Flutter
- rive_common (0.0.1):
- Flutter
- safe_device (1.0.0):
- DTTJailbreakDetection
- Flutter
- SDWebImage (5.21.0):
- SDWebImage/Core (= 5.21.0)
- SDWebImage/Core (5.21.0)
- share_plus (0.0.1):
- Flutter
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
- speech_to_text (0.0.1):
- Flutter
- FlutterMacOS
- Try
- sqflite (0.0.3):
- Flutter
- FlutterMacOS
- SwiftyGif (5.4.5)
- Toast (4.1.1)
- TOCropViewController (2.7.4)
- Try (2.1.1)
- url_launcher_ios (0.0.1):
- Flutter
- wifi_iot (0.0.1):
- Flutter
DEPENDENCIES:
- audio_session (from `.symlinks/plugins/audio_session/ios`)
- audioplayers_darwin (from `.symlinks/plugins/audioplayers_darwin/ios`)
- device_calendar (from `.symlinks/plugins/device_calendar/ios`)
- file_picker (from `.symlinks/plugins/file_picker/ios`)
- firebase_core (from `.symlinks/plugins/firebase_core/ios`)
- firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`)
- Flutter (from `Flutter`)
- flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`)
- flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`)
- flutter_sound (from `.symlinks/plugins/flutter_sound/ios`)
- flutter_timezone (from `.symlinks/plugins/flutter_timezone/ios`)
- fluttertoast (from `.symlinks/plugins/fluttertoast/ios`)
- FMDB
- geolocator_apple (from `.symlinks/plugins/geolocator_apple/ios`)
- image_cropper (from `.symlinks/plugins/image_cropper/ios`)
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
- just_audio (from `.symlinks/plugins/just_audio/ios`)
- local_auth_darwin (from `.symlinks/plugins/local_auth_darwin/darwin`)
- nfc_manager (from `.symlinks/plugins/nfc_manager/ios`)
- open_file_ios (from `.symlinks/plugins/open_file_ios/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
- pointer_interceptor_ios (from `.symlinks/plugins/pointer_interceptor_ios/ios`)
- qr_code_scanner (from `.symlinks/plugins/qr_code_scanner/ios`)
- record_mp3_plus (from `.symlinks/plugins/record_mp3_plus/ios`)
- rive_common (from `.symlinks/plugins/rive_common/ios`)
- safe_device (from `.symlinks/plugins/safe_device/ios`)
- share_plus (from `.symlinks/plugins/share_plus/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- speech_to_text (from `.symlinks/plugins/speech_to_text/darwin`)
- sqflite (from `.symlinks/plugins/sqflite/darwin`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
- wifi_iot (from `.symlinks/plugins/wifi_iot/ios`)
SPEC REPOS:
trunk:
- DKImagePickerController
- DKPhotoGallery
- DTTJailbreakDetection
- Firebase
- FirebaseCore
- FirebaseCoreInternal
- FirebaseInstallations
- FirebaseMessaging
- flutter_sound_core
- FMDB
- GoogleDataTransport
- GoogleUtilities
- MTBBarcodeScanner
- nanopb
- PromisesObjC
- SDWebImage
- SwiftyGif
- Toast
- TOCropViewController
- Try
EXTERNAL SOURCES:
audio_session:
:path: ".symlinks/plugins/audio_session/ios"
audioplayers_darwin:
:path: ".symlinks/plugins/audioplayers_darwin/ios"
device_calendar:
:path: ".symlinks/plugins/device_calendar/ios"
file_picker:
:path: ".symlinks/plugins/file_picker/ios"
firebase_core:
:path: ".symlinks/plugins/firebase_core/ios"
firebase_messaging:
:path: ".symlinks/plugins/firebase_messaging/ios"
Flutter:
:path: Flutter
flutter_keyboard_visibility:
:path: ".symlinks/plugins/flutter_keyboard_visibility/ios"
flutter_local_notifications:
:path: ".symlinks/plugins/flutter_local_notifications/ios"
flutter_sound:
:path: ".symlinks/plugins/flutter_sound/ios"
flutter_timezone:
:path: ".symlinks/plugins/flutter_timezone/ios"
fluttertoast:
:path: ".symlinks/plugins/fluttertoast/ios"
geolocator_apple:
:path: ".symlinks/plugins/geolocator_apple/ios"
image_cropper:
:path: ".symlinks/plugins/image_cropper/ios"
image_picker_ios:
:path: ".symlinks/plugins/image_picker_ios/ios"
just_audio:
:path: ".symlinks/plugins/just_audio/ios"
local_auth_darwin:
:path: ".symlinks/plugins/local_auth_darwin/darwin"
nfc_manager:
:path: ".symlinks/plugins/nfc_manager/ios"
open_file_ios:
:path: ".symlinks/plugins/open_file_ios/ios"
package_info_plus:
:path: ".symlinks/plugins/package_info_plus/ios"
path_provider_foundation:
:path: ".symlinks/plugins/path_provider_foundation/darwin"
permission_handler_apple:
:path: ".symlinks/plugins/permission_handler_apple/ios"
pointer_interceptor_ios:
:path: ".symlinks/plugins/pointer_interceptor_ios/ios"
qr_code_scanner:
:path: ".symlinks/plugins/qr_code_scanner/ios"
record_mp3_plus:
:path: ".symlinks/plugins/record_mp3_plus/ios"
rive_common:
:path: ".symlinks/plugins/rive_common/ios"
safe_device:
:path: ".symlinks/plugins/safe_device/ios"
share_plus:
:path: ".symlinks/plugins/share_plus/ios"
shared_preferences_foundation:
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
speech_to_text:
:path: ".symlinks/plugins/speech_to_text/darwin"
sqflite:
:path: ".symlinks/plugins/sqflite/darwin"
url_launcher_ios:
:path: ".symlinks/plugins/url_launcher_ios/ios"
wifi_iot:
:path: ".symlinks/plugins/wifi_iot/ios"
SPEC CHECKSUMS:
audio_session: 088d2483ebd1dc43f51d253d4a1c517d9a2e7207
audioplayers_darwin: 877d9a4d06331c5c374595e46e16453ac7eafa40
device_calendar: 9cb33f88a02e19652ec7b8b122ca778f751b1f7b
DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
DTTJailbreakDetection: 5e356c5badc17995f65a83ed9483f787a0057b71
file_picker: 09aa5ec1ab24135ccd7a1621c46c84134bfd6655
Firebase: 98e6bf5278170668a7983e12971a66b2cd57fc8c
firebase_core: 2bedc3136ec7c7b8561c6123ed0239387b53f2af
firebase_messaging: 15d114e1a41fc31e4fbabcd48d765a19eec94a38
FirebaseCore: a282032ae9295c795714ded2ec9c522fc237f8da
FirebaseCoreInternal: 154779013b85b4b290fdba38414df475f42e3096
FirebaseInstallations: 6ef4a1c7eb2a61ee1f74727d7f6ce2e72acf1414
FirebaseMessaging: c9ec7b90c399c7a6100297e9d16f8a27fc7f7152
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069
flutter_local_notifications: 4cde75091f6327eb8517fa068a0a5950212d2086
flutter_sound: dde9a913063b65a27ba8fdc2039036b99b136c79
flutter_sound_core: 0c6eb9d5268adc70ff159b3d65fd3d98a82d3a27
flutter_timezone: ffb07bdad3c6276af8dada0f11978d8a1f8a20bb
fluttertoast: 723e187574b149e68e63ca4d39b837586b903cfa
FMDB: 728731dd336af3936ce00f91d9d8495f5718a0e6
geolocator_apple: 9bcea1918ff7f0062d98345d238ae12718acfbc1
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
GoogleUtilities: 26a3abef001b6533cf678d3eb38fd3f614b7872d
image_cropper: 37d40f62177c101ff4c164906d259ea2c3aa70cf
image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1
just_audio: baa7252489dbcf47a4c7cc9ca663e9661c99aafa
local_auth_darwin: 66e40372f1c29f383a314c738c7446e2f7fdadc3
MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
nfc_manager: d7da7cb781f7744b94df5fe9dbca904ac4a0939e
open_file_ios: 461db5853723763573e140de3193656f91990d9e
package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
pointer_interceptor_ios: 508241697ff0947f853c061945a8b822463947c1
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
qr_code_scanner: bb67d64904c3b9658ada8c402e8b4d406d5d796e
record_mp3_plus: be7806da5b5ff9694f8069f401120853c89f3398
rive_common: cbbac3192af00d7341f19dae2f26298e9e37d99e
safe_device: 4539eb6bdbeb4b61a763a51c4e73e6b37dea4e3d
SDWebImage: f84b0feeb08d2d11e6a9b843cb06d75ebf5b8868
share_plus: 8b6f8b3447e494cca5317c8c3073de39b3600d1f
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
speech_to_text: 627d3fd2194770b51abb324ba45c2d39398f24a8
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
Toast: 1f5ea13423a1e6674c4abdac5be53587ae481c4e
TOCropViewController: 80b8985ad794298fb69d3341de183f33d1853654
Try: 5ef669ae832617b3cee58cb2c6f99fb767a4ff96
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
wifi_iot: b5aafd6f9b52f8a357383a1deabab45f31cd602d
PODFILE CHECKSUM: d8654c27146ad2b7c852fbdd93ef1a3785d9310b
COCOAPODS: 1.12.0

@ -2,6 +2,7 @@ class URLs {
URLs._();
static const String appReleaseBuildNumber = "14";
// static const host1 = "https://atomsm.hmg.com"; // production url
static const host1 = "https://atomsmdev.hmg.com"; // local DEV url
// static const host1 = "https://atomsmuat.hmg.com"; // local UAT url
@ -42,51 +43,94 @@ class URLs {
static get getModels => "$_baseUrl/ModelDefinition/GetModelDefinitionAsset"; // get ?client=2
static get getAllRequestsAndCount => "$_baseUrl/CallRequest/GetAllRequestsAndCount"; // get
//service request new flow urls.
static get nurseDashboardCountUrl=> '$_baseUrl/ServiceRequest/GetDashboardNurseCount';
static get nurseDashboardDetailsUrl=> '$_baseUrl/ServiceRequest/GetDashboardNurseDetails';
static get nurseRejectUrl=> '$_baseUrl/ServiceRequest/NurseReject';
static get engineerStopTimer=> '$_baseUrl/ServiceRequest/EngineerStopTimer';
static get nurseConfirmEngineerArrivedUrl=> '$_baseUrl/ServiceRequest/NurseConfirm';
static get nurseConfirmUrl=> '$_baseUrl/ServiceRequest/NurseConfirm';
static get nurseRejectEngineerArrivedUrl=> '$_baseUrl/ServiceRequest/NurseNotArrive';
static get nurseConfirmEngineerArrivalUrl=> '$_baseUrl/ServiceRequest/NurseAccept';
static get engineerDashboardCountUrl=> '$_baseUrl/ServiceRequest/GetDashboardEngineerCount';
static get engineerDashboardDetailsUrl=> '$_baseUrl/ServiceRequest/GetDashboardEngineerDetails';
static get engineerDashboardNotAssignDetails=> '$_baseUrl/ServiceRequest/GetDashboardEngineerNotAssignDetails';
static get engineerDashboardUpcoming=> '$_baseUrl/ServiceRequest/GetDashboardEngineerUpcoming';
static get engineerAcceptUrl=> '$_baseUrl/ServiceRequest/EngineerAccept';
static get engineerAssignHimSelfUrl=> '$_baseUrl/ServiceRequest/AssignEngineerToHimself';
static get engineerRejectUrl=> '$_baseUrl/ServiceRequest/EngineerReject';
static get engineerFixRemotlyUrl=> '$_baseUrl/ServiceRequest/EngineerFixRemotly';
static get engineerNeedVisitUrl=> '$_baseUrl/ServiceRequest/EngineerNeedVisit';
static get engineerUpdateNeedVisitUrl=> '$_baseUrl/ServiceRequest/EngineerUpdateNeedVisit';
static get engineerMarkAsFixUrl=> '$_baseUrl/ServiceRequest/EngineerMarkAsFix';
static get reOrderActivity=> '$_baseUrl/ServiceRequest/ReOrderActivity';
static get engineerConfirmArriveUrl=> '$_baseUrl/ServiceRequest/EngineerConfirmArrive';
static get engineerUpdateWorkOrderUrl=> '$_baseUrl/ServiceRequest/EngineerUpdateWorkOrder';
static get engineerSetReminderUrl=> '$_baseUrl/ServiceRequest/EngineerSetReminder';
static get getWorkOrderByIdUrl=> '$_baseUrl/ServiceRequest/GetWorkOrderById';
static get getQrCodeUrl=> '$_baseUrl/ServiceRequest/GetQRCode';
static get deleteActivitySparePartUrl=> '$_baseUrl/ServiceRequest/DeleteActivitySparePart';
static get deleteActivityMaintenanceUrl=> '$_baseUrl/ServiceRequest/DeleteActivityMaintenance';
static get createActivitySparePartUrl=> '$_baseUrl/ServiceRequest/CreateActivitySparePart';
static get createActivityMaintenanceUrl=> '$_baseUrl/ServiceRequest/CreateActivityMaintenance';
static get createActivityAssetToBeRetiredUrl=> '$_baseUrl/ServiceRequest/CreateActivityAssetToBeRetired';
static get createWorkOrderUrl=> '$_baseUrl/ServiceRequest/CreateWorkOrder';
static get updateActivitySparePartUrl=> '$_baseUrl/ServiceRequest/UpdateActivitySparePart';
static get updateActivityMaintenanceUrl=> '$_baseUrl/ServiceRequest/UpdateActivityMaintenance';
static get assignEngineerToWorkOrderUrl=> '$_baseUrl/ServiceRequest/AssignEngineerToWorkOrder';
static get getArrivalVerificationTypeUrl=> '$_baseUrl/ArrivalVerificationType/GetArrivalVerificationType';
static get sendOtpUrl=> '$_baseUrl/SmsNotification/SendOTP/';
static get verifyOtpUrl=> '$_baseUrl/SmsNotification/VerifyOTP/';
static get nurseDashboardCountUrl => '$_baseUrl/ServiceRequest/GetDashboardNurseCount';
static get nurseDashboardDetailsUrl => '$_baseUrl/ServiceRequest/GetDashboardNurseDetails';
static get nurseRejectUrl => '$_baseUrl/ServiceRequest/NurseReject';
static get engineerStopTimer => '$_baseUrl/ServiceRequest/EngineerStopTimer';
static get nurseConfirmEngineerArrivedUrl => '$_baseUrl/ServiceRequest/NurseConfirm';
static get nurseConfirmUrl => '$_baseUrl/ServiceRequest/NurseConfirm';
static get nurseRejectEngineerArrivedUrl => '$_baseUrl/ServiceRequest/NurseNotArrive';
static get nurseConfirmEngineerArrivalUrl => '$_baseUrl/ServiceRequest/NurseAccept';
static get engineerDashboardCountUrl => '$_baseUrl/ServiceRequest/GetDashboardEngineerCount';
static get engineerDashboardDetailsUrl => '$_baseUrl/ServiceRequest/GetDashboardEngineerDetails';
static get engineerDashboardNotAssignDetails => '$_baseUrl/ServiceRequest/GetDashboardEngineerNotAssignDetails';
static get engineerDashboardUpcoming => '$_baseUrl/ServiceRequest/GetDashboardEngineerUpcoming';
static get engineerAcceptUrl => '$_baseUrl/ServiceRequest/EngineerAccept';
static get engineerAssignHimSelfUrl => '$_baseUrl/ServiceRequest/AssignEngineerToHimself';
static get engineerRejectUrl => '$_baseUrl/ServiceRequest/EngineerReject';
static get engineerFixRemotlyUrl => '$_baseUrl/ServiceRequest/EngineerFixRemotly';
static get engineerNeedVisitUrl => '$_baseUrl/ServiceRequest/EngineerNeedVisit';
static get engineerUpdateNeedVisitUrl => '$_baseUrl/ServiceRequest/EngineerUpdateNeedVisit';
static get engineerMarkAsFixUrl => '$_baseUrl/ServiceRequest/EngineerMarkAsFix';
static get reOrderActivity => '$_baseUrl/ServiceRequest/ReOrderActivity';
static get engineerConfirmArriveUrl => '$_baseUrl/ServiceRequest/EngineerConfirmArrive';
static get engineerUpdateWorkOrderUrl => '$_baseUrl/ServiceRequest/EngineerUpdateWorkOrder';
static get engineerSetReminderUrl => '$_baseUrl/ServiceRequest/EngineerSetReminder';
static get getWorkOrderByIdUrl => '$_baseUrl/ServiceRequest/GetWorkOrderById';
static get getQrCodeUrl => '$_baseUrl/ServiceRequest/GetQRCode';
static get deleteActivitySparePartUrl => '$_baseUrl/ServiceRequest/DeleteActivitySparePart';
static get deleteActivityMaintenanceUrl => '$_baseUrl/ServiceRequest/DeleteActivityMaintenance';
static get createActivitySparePartUrl => '$_baseUrl/ServiceRequest/CreateActivitySparePart';
static get createActivityMaintenanceUrl => '$_baseUrl/ServiceRequest/CreateActivityMaintenance';
static get createActivityAssetToBeRetiredUrl => '$_baseUrl/ServiceRequest/CreateActivityAssetToBeRetired';
static get createWorkOrderUrl => '$_baseUrl/ServiceRequest/CreateWorkOrder';
static get updateActivitySparePartUrl => '$_baseUrl/ServiceRequest/UpdateActivitySparePart';
static get updateActivityMaintenanceUrl => '$_baseUrl/ServiceRequest/UpdateActivityMaintenance';
static get assignEngineerToWorkOrderUrl => '$_baseUrl/ServiceRequest/AssignEngineerToWorkOrder';
static get uploadWorkOrderAttachmentsUrl => '$_baseUrl/ServiceRequest/UploadAttachmentsWorkOrder';
static get getArrivalVerificationTypeUrl => '$_baseUrl/ArrivalVerificationType/GetArrivalVerificationType';
static get sendOtpUrl => '$_baseUrl/SmsNotification/SendOTP/';
static get verifyOtpUrl => '$_baseUrl/SmsNotification/VerifyOTP/';
// 08051
//Swipe module Api..
static get swipeUrl=> '$_baseUrl/Swipe/Swipe';
static get getSwipeLastTransactionUrl=> '$_baseUrl/Swipe/GetLastTransaction';
static get getSwipeTransactionHistoryUrl=> '$_baseUrl/Swipe/GetTransactions';
static get swipeUrl => '$_baseUrl/Swipe/Swipe';
static get getSwipeLastTransactionUrl => '$_baseUrl/Swipe/GetLastTransaction';
static get getSwipeTransactionHistoryUrl => '$_baseUrl/Swipe/GetTransactions';
//Recurrent plan Api...
static get getRecurrentPlanByIdUrl=> '$_baseUrl/PlanRecurrentTasks/GetPlanRecurrentTaskById';
static get updateRecurrentPlanUrl=> '$_baseUrl/PlanRecurrentTasks/UpdateTaskByEngineer';
static get getRecurrentPlanByIdUrl => '$_baseUrl/PlanRecurrentTasks/GetPlanRecurrentTaskById';
static get updateRecurrentPlanUrl => '$_baseUrl/PlanRecurrentTasks/UpdateTaskByEngineer';
//Task request apis ...
static get getTaskTypeByUserUrl=> '$_baseUrl/TaskTypes/GetTaskTypesByUser';
@ -159,11 +203,17 @@ class URLs {
static get getPpmService => "$_baseUrl/Lookups/GetLookup?lookupEnum=34"; // get for ppm po reason, in mobile there is no use of it.
static get getServiceReportReasons => "$_baseUrl/Lookups/GetLookupReason?lookupEnum=505";
static get getServiceReportRejectionReasons => "$_baseUrl/Lookups/GetLookup?lookupEnum=1303";
static get getServiceReportReasonsNew => "$_baseUrl/Lookups/GetLookupReasonNew?lookupEnum=505";
static get getServiceReportRetirementType => "$_baseUrl/Lookups/GetLookup?lookupEnum=415";
static get getVisitReminderTimeValue => "$_baseUrl/Lookups/GetLookup?lookupEnum=1211";
static get getServiceReportActivityStatus => "$_baseUrl/Lookups/GetLookup?lookupEnum=1302";
static get getServiceReportTypes => "$_baseUrl/Lookups/GetLookup?lookupEnum=501"; // get
static get getServiceReportTypesForWO => "$_baseUrl/Lookups/GetLookup?lookupEnum=34"; // get
static get getServiceReportStatus => "$_baseUrl/Lookups/GetLookup?lookupEnum=521"; // get
@ -171,30 +221,39 @@ class URLs {
static get getAssetTypes => "$_baseUrl/Lookups/GetLookup?lookupEnum=500"; // get
static get getPersonRoles => "$_baseUrl/Lookups/GetLookup?lookupEnum=36"; // get
static get getPartNumber => "$_baseUrl/PartCatalog/GetPartAutoComplete"; // get
static get getSparePartAvailableQuantity => "$_baseUrl/SparePart/GetAvailablityQtyForSparePartByPartId"; // get
static get getServiceReportPriority => "$_baseUrl/Lookups/GetLookup?lookupEnum=4"; // get
static get getServiceReportDefectTypes => "$_baseUrl/Lookups/GetLookup?lookupEnum=601"; // get
static get getCallRequestForWorkOrder => "$_baseUrl/CallRequest/GetCallRequestForWorkOrder"; // get
static get attachmentBaseUrl => "https://atomsmdev.hmg.com/v2/mobile/Files/DownloadFile?fileName=";
//gas refill
static get getGasTypes => "$_baseUrl/Lookups/GetLookup?lookupEnum=606"; // get
// todo check edits with backend
static get getGasCylinderSize => "$_baseUrl/Lookups/GetLookup?lookupEnum=608"; // get
static get getGasCylinderType => "$_baseUrl/Lookups/GetLookup?lookupEnum=607"; // get
static get getGasStatus => "$_baseUrl/Lookups/GetLookup?lookupEnum=609"; // get
static get requestGasRefill => "$_baseUrl/GazRefill/AddGazRefill"; // get
static get requestGasRefill => "$_baseUrl/GasRefill/AddGasRefillFromMobile"; // get
static get updateGasRefill => "$_baseUrl/GazRefill/UpdateGazRefill"; // get
static get getGasRefill => "$_baseUrl/GazRefill/GetGazRefills"; // get
static get getGasRefillById => "$_baseUrl/GazRefill/GetGazRefillById"; // get
// static get getGasRefillById => "$_baseUrl/GazRefill/GetGazRefillById"; // get older endpoint..
static get getGasRefillById => "$_baseUrl/GasRefill/GetGasRefillById"; // get
static get getGazRefillComments => "$_baseUrl/GazRefill/GetHistoryComments"; // get
static get addGazRefillComment => "$_baseUrl/GazRefill/AddHistoryComment"; // add
static get updateGasRefillByEngineer => "$_baseUrl/GasRefill/UpdateGasRefillByEngineer"; // update
//device transfer
static get requestDeviceTransfer => "$_baseUrl/AssetTransfer/AddAssetTransfer"; // get
static get updateDeviceTransfer => "$_baseUrl/AssetTransfer/UpdateAssetTransfer"; // get
// static get updateDeviceTransfer => "$_baseUrl/AssetTransfer/UpdateAssetTransfer"; // get
static get getDeviceTransfer => "$_baseUrl/AssetTransfer/GetAssetTransfers"; // get
static get getAssetTransferById => "$_baseUrl/AssetTransfer/GetAssetTransferById"; // get
// static get getAssetTransferById => "$_baseUrl/AssetTransfer/GetAssetTransferById"; // get
static get getAssetTransferStatus => "$_baseUrl/Lookups/GetLookup?lookupEnum=406"; // get
//Asset transfer new Apis
static get getAssetTransferById => "$_baseUrl/AssetTransfer/GetAssetTransferNewById"; // get
static get createAssetTransferRequest => "$_baseUrl/AssetTransfer/AddAssetTransferMobileNew"; // post
static get updateDeviceTransfer => "$_baseUrl/AssetTransfer/UpdateEngineerAssetTransferNew"; // get
// employee
static get getEmployees => "$_baseUrl/Lookups/GetLookup?lookupEnum=33"; // get
static get getEngineers => "$_baseUrl/Account/GetUserByRoleValue?value=R-6"; // get

@ -4,7 +4,6 @@ import 'package:flutter/widgets.dart';
import 'package:http/http.dart';
import 'package:test_sa/controllers/api_routes/api_manager.dart';
import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/models/all_requests_and_count_model.dart';
import 'package:test_sa/models/enums/user_types.dart';
import 'package:test_sa/models/ppm/recurrent_wo.dart';
@ -62,7 +61,7 @@ class AllRequestsProvider extends ChangeNotifier {
// AllRequestsAndCount? get completedRequests => _completedRequests;
AllRequestsAndCount? get requestDetailList => _requestDetailList;
RecurrentWoData? _recurrentWoData=RecurrentWoData();
RecurrentWoData? _recurrentWoData = RecurrentWoData();
RecurrentWoData? get recurrentWoData => _recurrentWoData;
@ -201,6 +200,15 @@ class AllRequestsProvider extends ChangeNotifier {
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
recurrentWoData = RecurrentWoData.fromJson(json.decode(response.body)["data"]);
recurrentWoData?.planRecurrentMedicalTaskRooms?.forEach((element) {
element.planRecurrentMedicalTaskRoomTabs?.forEach((tabs) {
tabs.planRecurrentMedicalTaskRoomTabAttributes?.forEach((attribute) {
if (attribute.attribute?.type == "bool" && attribute.attributeValue == null) {
attribute.attributeValue = "true";
}
});
});
});
notifyListeners();
}
isLoading = false;

@ -6,8 +6,10 @@ import 'package:http/http.dart';
import 'package:test_sa/controllers/api_routes/api_manager.dart';
import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/models/device/asset.dart';
import 'package:test_sa/models/device/asset_transfer.dart';
import 'package:test_sa/models/service_request/pending_service_request_model.dart';
import 'package:test_sa/models/user.dart';
import '../../../models/hospital.dart';
@ -120,15 +122,27 @@ class AssetTransferProvider extends ChangeNotifier {
}
}
Future<PendingAssetServiceRequest?> checkAssetPendingRequest(int assetId) async {
Response response;
try {
response = await ApiManager.instance.post(URLs.CheckIfAssetHasAnotherServiceRequest + "?assetId=$assetId",body: {});
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {}
return PendingAssetServiceRequest.fromJson(json.decode(response.body)["data"]);
} catch (error) {
"Please Try Again\n$error".addTranslation.showToast;
return null;
}
}
Future<void> createRequest({
required BuildContext context,
required AssetTransfer assetDestination,
required Asset asset,
required AssetTransfer model,
}) async {
Response response;
try {
showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
response = await ApiManager.instance.post(URLs.requestDeviceTransfer, body: assetDestination.transferBody(asset: asset));
response = await ApiManager.instance.post(URLs.createAssetTransferRequest, body: model.toCreateAssetTransferJson());
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
if (items != null) {
@ -148,29 +162,15 @@ class AssetTransferProvider extends ChangeNotifier {
}
}
Future<int> updateRequest(BuildContext context, {required AssetTransfer assetTransfer, required bool isSender}) async {
Future<int> updateRequest(BuildContext context, {required AssetTransfer model}) async {
Response response;
try {
showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
response = await ApiManager.instance.put(URLs.updateDeviceTransfer, body: assetTransfer.toJson());
//print(response.body);
// print("${newModel.engSignature}.png");
// response = await post(
// Uri.parse("$host${URLs.updateDeviceTransfer}/$requestId"),
// body: body,
// );
response = await ApiManager.instance.post(URLs.updateDeviceTransfer, body: model.toEngineerUpdateJson());
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
reset();
// Fluttertoast.showToast(msg: context.translation.successfulRequestMessage);
Navigator.of(context).pop();
// oldModel.fromDeviceTransfer(
// DeviceTransfer.fromJson(
// json.decode(utf8.decode(response.bodyBytes))[0]
// )
// );
notifyListeners();
} else {
Fluttertoast.showToast(msg: "${context.translation.failedToCompleteRequest} :${json.decode(response.body)['message']}");
@ -184,8 +184,5 @@ class AssetTransferProvider extends ChangeNotifier {
}
}
bool _isLocalUrl(String? url) {
if (url?.isEmpty ?? true) return false;
return url!.startsWith("/") || url.startsWith("file://") || url.substring(1).startsWith(':\\');
}
}

@ -1,5 +1,6 @@
import 'dart:convert';
import 'dart:developer';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
@ -9,6 +10,7 @@ import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/models/hospital.dart';
import 'package:test_sa/models/new_models/gas_refill_model.dart';
import 'package:test_sa/models/timer_model.dart';
import 'package:test_sa/models/user.dart';
import '../../../new_views/common_widgets/app_lazy_loading.dart';
@ -44,12 +46,15 @@ class GasRefillProvider extends ChangeNotifier {
// failed _loading = false
bool isLoading = false;
Future<GasRefillModel?> getGasRefillObjectById(num id) async {
try {
Response response = await ApiManager.instance.get(URLs.getGasRefillById + "?gazRefillId=$id");
Response response = await ApiManager.instance.get(URLs.getGasRefillById + "?gasRefillId=$id");
if (response.statusCode >= 200 && response.statusCode < 300) {
return GasRefillModel.fromJson(json.decode(response.body)["data"]);
return GasRefillModel.fromJson(json.decode(response.body)["data"]);
} else {
return null;
}
@ -58,6 +63,7 @@ class GasRefillProvider extends ChangeNotifier {
}
}
/// return -2 if request in progress
/// return -1 if error happen when sending request
/// return state code if request complete may be 200, 404 or 403
@ -105,20 +111,14 @@ class GasRefillProvider extends ChangeNotifier {
}
}
Future<void> createModel({
Future<void> addGasRefillRequest({
required BuildContext context,
required User user,
required GasRefillModel model,
}) async {
late Response response;
try {
showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
final Map<String, dynamic> body = {
"uid": user.id.toString(),
"token": user.token ?? "",
};
body.addAll(model.toJson());
response = await ApiManager.instance.post(URLs.requestGasRefill, body: body);
response = await ApiManager.instance.post(URLs.requestGasRefill, body: model.toJson());
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
if (items != null) {
@ -137,6 +137,23 @@ class GasRefillProvider extends ChangeNotifier {
}
}
Future<int> updateGasRefill({required int status, required GasRefillModel model}) async {
isLoading = true;
Response response;
try {
response = await ApiManager.instance.post(URLs.updateGasRefillByEngineer, body: model.toUpdateEngineerPayload(status: status));
stateCode = response.statusCode;
isLoading = false;
notifyListeners();
return response.statusCode;
} catch (error) {
isLoading = false;
stateCode = -1;
notifyListeners();
return -1;
}
}
Future<int> updateModel({
required String host,
required User user,
@ -145,7 +162,7 @@ class GasRefillProvider extends ChangeNotifier {
}) async {
Map<String, dynamic> body = {
"id": newModel.id,
"gazRefillNo": newModel.gazRefillNo ?? "",
"gasRefillNo": newModel.gasRefillNo ?? "",
"status": newModel.status?.toJson(),
//"expectedDate": newModel.expectedDate?.toIso8601String(),
"expectedTime": newModel.expectedDate,
@ -164,7 +181,7 @@ class GasRefillProvider extends ChangeNotifier {
"comment": newModel.comment,
};
body["gazRefillDetails"] = newModel.gazRefillDetails!
body["gasRefillDetails"] = newModel.gasRefillDetails!
.map((model) => {
"gasType": model.gasType?.toJson(),
"cylinderSize": model.cylinderSize?.toJson(),

@ -96,11 +96,29 @@ class PartsProvider extends ChangeNotifier {
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
List categoriesListJson = json.decode(response.body)["data"];
page = categoriesListJson.map((part) => SparePart.fromJson(part)).toList();
page = categoriesListJson.map((part) => SparePart.fromJson(part,false)).toList();
}
return page;
} catch (error) {
return [];
}
}
// Implement this only for spare part request for now show and search on display name ....
Future<List<SparePart>> getPartsListByDisplayName({num? assetId, String? displayName}) async {
late Response response;
try {
response = await ApiManager.instance.post(URLs.getPartNumber, body: {"displayName": displayName, });
List<SparePart> page = [];
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
List categoriesListJson = json.decode(response.body)["data"];
page = categoriesListJson.map((part) => SparePart.fromJson(part,true)).toList();
}
return page;
} catch (error) {
return [];
}
}
}

@ -22,6 +22,14 @@ class PpmProvider extends ChangeNotifier {
PlanPreventiveVisit? _planPreventiveVisit;
late int _totalTabs = 4;
TabController? tabController;
bool _isReadOnly = false;
bool get isReadOnly => _isReadOnly;
set isReadOnly(bool value) {
_isReadOnly = value;
notifyListeners();
}
int get totalTabs => _totalTabs;
@ -155,6 +163,11 @@ class PpmProvider extends ChangeNotifier {
if (response.statusCode >= 200 && response.statusCode < 300) {
ppmPlanAttachments = [];
planPreventiveVisit = PlanPreventiveVisit.fromJson(json.decode(response.body)["data"]);
if(planPreventiveVisit?.visitStatus?.value! == 1 || planPreventiveVisit?.visitStatus?.value == 3){
isReadOnly =true;
}else{
isReadOnly =false;
}
isLoading = false;
notifyListeners();
return planPreventiveVisit;

@ -367,16 +367,16 @@ class CategoryTabs {
if (userType == UsersTypes.engineer) {
// tabs.add(CategoryTabs(label: 'Upcoming', tag: 0, id: 0));
// tabs.add(CategoryTabs('Open', 1));
tabs.add(CategoryTabs(label: 'UnAssigned Open', tag: 1, id: 1));
tabs.add(CategoryTabs(label: 'Assigned Open', tag: 1, id: 2));
tabs.add(CategoryTabs(label: 'UnAssigned', tag: 1, id: 1));
tabs.add(CategoryTabs(label: 'Open', tag: 1, id: 2));
tabs.add(CategoryTabs(label: 'In Progress', tag: 2, id: 3));
tabs.add(CategoryTabs(label: 'Completed', tag: 3, id: 4));
return tabs;
}
tabs.add(CategoryTabs(label: 'Open Request', tag: 1, id: 2));
tabs.add(CategoryTabs(label: 'Open', tag: 1, id: 2));
tabs.add(CategoryTabs(label: 'In Progress', tag: 2, id: 3));
tabs.add(CategoryTabs(label: 'Upcoming', tag: 3, id: 1));
tabs.add(CategoryTabs(label: 'Pending Acknowledgement', tag: 3, id: 1));
tabs.add(CategoryTabs(label: 'Canceled', tag: 6, id: 4));
return tabs;
}

@ -151,10 +151,9 @@
//
import 'package:flutter/material.dart';
import 'package:pie_chart/pie_chart.dart';
import 'package:provider/provider.dart';
import 'package:syncfusion_flutter_charts/charts.dart';
import 'package:test_sa/dashboard_latest/dashboard_provider.dart';
import 'package:test_sa/controllers/providers/api/all_requests_provider.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
@ -212,46 +211,44 @@ class ProgressFragment extends StatelessWidget {
child: Stack(
alignment: Alignment.center,
children: [
SfCircularChart(
tooltipBehavior: TooltipBehavior(
enable: true,
// elevation: 2,
color: context.isDark ? const Color(0xFF111427) : const Color(0xffF7F9FB),
textStyle: context.isDark ? null : const TextStyle(color: Colors.black87, fontSize: 12),
PieChart(
dataMap: {for (var v in chartData) v.x: v.y},
animationDuration: const Duration(milliseconds: 800),
chartLegendSpacing: 32,
chartRadius: MediaQuery.of(context).size.width / 3.2,
colorList: chartData.map((element) => element.color).toList(),
initialAngleInDegree: 270,
chartType: ChartType.ring,
ringStrokeWidth: 32,
centerWidget: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
context.translation.total,
style: AppTextStyles.heading5.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
),
Text(
"$total",
style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20),
),
],
),
legendOptions: const LegendOptions(
showLegendsInRow: false,
legendPosition: LegendPosition.right,
showLegends: true,
legendTextStyle: TextStyle(
fontWeight: FontWeight.w500,
),
legend: const Legend(
//isVisible: true,
),
series: <CircularSeries>[
DoughnutSeries<ChartData, String>(
dataSource: chartData,
radius: "100%",
innerRadius: "60%",
pointColorMapper: (ChartData data, _) => data.color,
xValueMapper: (ChartData data, _) => data.x,
yValueMapper: (ChartData data, _) => data.y,
dataLabelMapper: (ChartData data, _) => data.x,
dataLabelSettings: DataLabelSettings(
margin: const EdgeInsets.all(8),
isVisible: true,
textStyle: TextStyle(color: context.isDark ? Colors.white : AppColor.neutral20, fontSize: 12, fontWeight: FontWeight.w500),
labelPosition: ChartDataLabelPosition.outside,
),
)
]).toShimmer(isShow: snapshot.isAllCountLoading, radius: 250).paddingAll(0).toShadowContainer(context),
Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
context.translation.total,
style: AppTextStyles.heading5.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
),
Text(
"$total",
style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20),
),
],
),
),
chartValuesOptions: const ChartValuesOptions(
showChartValueBackground: false,
showChartValues: false,
showChartValuesInPercentage: false,
showChartValuesOutside: false,
decimalPlaces: 1,
),
).toShimmer(isShow: snapshot.isAllCountLoading, radius: 250).paddingAll(0).toShadowContainer(context),
],
),
),

@ -164,13 +164,14 @@ extension CapExtension on String {
String get allInCaps => toUpperCase();
String get cleanupWhitespace => replaceAll(RegExp(r"\s+"), " ");
String get capitalizeFirstOfEach => trim().isNotEmpty
? trim().toLowerCase().split(" ").map((str) {
return str.trim()?.inCaps ?? "";
}).join(" ")
: "";
String get cleanupWhitespace => this;//replaceAll(RegExp(r"\s+"), " ");
String get capitalizeFirstOfEach => this;
//trim().isNotEmpty
// ? trim().toLowerCase().split(" ").map((str) {
// return str.trim()?.inCaps ?? "";
// }).join(" ")
// : "";
}
extension FilesExtension on String {

@ -4,6 +4,7 @@ import 'package:shimmer/shimmer.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/new_views/swipe_module/dialoge/acknowledge_work_dialog.dart';
import '../new_views/app_style/app_color.dart';
@ -54,6 +55,26 @@ extension WidgetExtensions on Widget {
Widget toExpanded({int flex = 1}) => Expanded(flex: flex, child: this);
Widget handlePopScope({required BuildContext cxt, required VoidCallback onSave, bool? showPopUp =true}) {
return showPopUp! ? PopScope(
canPop: false,
onPopInvokedWithResult: (didPop, result) {
if (didPop) {
return;
}
showDialog(
context: cxt,
builder: (BuildContext cxt) => AcknowledgeWorkDialog(
onSave: () => onSave(),
onDiscard: () {
Navigator.of(cxt).pop();
},
),
);
},
child: this): this;
}
Widget toShimmer({bool isShow = true, double radius = 20}) => isShow
? Shimmer.fromColors(
baseColor: const Color(0xffe8eff0),

@ -560,6 +560,16 @@
"installationBuilding": "مبنى التركيب",
"installationFloor": "طابق التركيب",
"installationDepartment": "قسم التركيب",
"acknowledge": "إقرار"
"acknowledge": "إقرار",
"transferAsset": "نقل الأصل",
"createAssetTransferRequest": "إنشاء طلب نقل أصل",
"arrivedDate": "تاريخ الوصول",
"closedDate": "تاريخ الإغلاق",
"since": "منذ",
"rejectionDetails": "تفاصيل الرفض",
"part": "جزء",
"closedDate": "تاريخ الإغلاق",
"creationDate": "تاريخ الإنشاء"
}

@ -563,5 +563,15 @@
"installationBuilding": "Installation Building",
"installationFloor": "Installation Floor",
"installationDepartment": "Installation Department",
"acknowledge": "Acknowledge"
"acknowledge": "Acknowledge",
"transferAsset": "Transfer Asset",
"createAssetTransferRequest": "Create Asset Transfer Request",
"telephone": "Telephone",
"arrivedDate": "Arrived Date",
"closedDate": "Closed Date",
"since": "Since",
"rejectionDetails": "Rejection Details",
"part": "Part",
"closedDate": "Closed Date",
"creationDate": "Creation Date"
}

@ -70,9 +70,10 @@ import 'package:test_sa/service_request_latest/service_request_detail_provider.d
import 'package:test_sa/service_request_latest/views/nurse/create_new_request_view.dart';
import 'package:test_sa/views/pages/device_transfer/asset_filter_screen.dart';
import 'package:test_sa/views/pages/device_transfer/asset_search_screen.dart';
import 'package:test_sa/views/pages/device_transfer/request_device_transfer.dart';
import 'package:test_sa/views/pages/device_transfer/create__asset_transfer_request.dart';
import 'package:test_sa/views/pages/device_transfer/track_device_transfer.dart';
import 'package:test_sa/views/pages/sub_workorder/create_sub_workorder_page.dart';
import 'package:test_sa/views/pages/user/gas_refill/gas_refill_form.dart';
import 'package:test_sa/views/pages/user/gas_refill/request_gas_refill.dart';
import 'package:test_sa/views/pages/user/gas_refill/track_gas_refill.dart';
import 'package:test_sa/views/pages/user/notifications/notifications_page.dart';
@ -308,6 +309,7 @@ class MyApp extends StatelessWidget {
CreateTaskView.id: (_) => const CreateTaskView(),
//ReportIssuesPage.id: (_) => ReportIssuesPage(),
RequestGasRefill.id: (_) => const RequestGasRefill(),
GasRefillForm.id: (_) => const GasRefillForm(),
CreateServiceRequestPage.id: (_) => const CreateServiceRequestPage(),
CreateNewRequest.id: (_) => const CreateNewRequest(),
// SingleHospitalPicker.id: (_) => SingleHospitalPicker(),
@ -318,7 +320,7 @@ class MyApp extends StatelessWidget {
// PreventiveMaintenanceVisitsPage.id: (_) => PreventiveMaintenanceVisitsPage(),
PpmPage.id: (_) => const PpmPage(),
TrackGasRefillPage.id: (_) => const TrackGasRefillPage(),
RequestDeviceTransfer.id: (_) => const RequestDeviceTransfer(),
CreateAssetTransferRequest.id: (_) => const CreateAssetTransferRequest(),
TrackDeviceTransferPage.id: (_) => const TrackDeviceTransferPage(),
// todo remove this class after work

@ -2,86 +2,100 @@ import 'package:flutter/src/widgets/framework.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/models/device/asset.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/models/new_models/assistant_employee.dart';
import 'package:test_sa/models/ppm/ppm.dart';
import 'package:test_sa/models/timer_model.dart';
import 'asset_transfer_attachment.dart';
class AssetTransfer {
AssetTransfer(
{this.id,
this.transferNo,
this.transferCode,
this.assetId,
this.destSiteId,
this.destBuildingId,
this.destFloorId,
this.destDepartmentId,
this.destRoomId,
this.senderSiteId,
this.senderBuildingId,
this.senderFloorId,
this.senderDepartmentId,
this.senderRoom,
this.senderAssignedEmployeeId,
this.senderMachineStatusId,
this.senderComment,
this.comment,
this.receiverEndUserId,
this.receiverEndUserName,
this.senderStartDate,
this.senderEndDate,
this.senderWorkingHours,
this.senderTravelingHours,
this.senderEngSignature,
this.senderAttachments,
this.receiverAssignedEmployeeId,
this.receiverMachineStatusId,
this.receiverComment,
this.receiverStartDate,
this.receiverEndDate,
this.receiverWorkingHours,
this.receiverTravelingHours,
this.receiverEngSignature,
this.receiverAttachments,
this.assetNumber,
this.assetName,
this.manufacturerName,
this.modelName,
this.assetSerialNo,
this.destDepartmentName,
this.destBuildingName,
this.applied,
this.extensionNo,
this.name,
this.employeeId,
this.createdDate,
this.createdOn,
this.destFloorName,
this.destSiteName,
this.manufacturerId,
this.modelId,
this.modifiedOn,
this.receiverAssignedEmployeeName,
this.receiverEngSignatureUrl,
this.receiverMachineStatusName,
this.senderAssignedEmployeeName,
this.senderBuildingName,
this.senderDepartmentName,
this.senderEngSignatureUrl,
this.senderFloorName,
this.senderMachineStatusName,
this.senderSiteName,
this.supplierId,
this.supplierName,
this.senderVisitTimers,
this.receiverVisitTimers,
this.tbsTimer});
AssetTransfer({
this.id,
this.transferNo,
this.transferType,
this.transferCode,
this.assetId,
this.destSiteId,
this.destBuildingId,
this.destFloorId,
this.destDepartmentId,
this.destRoomId,
this.senderSiteId,
this.senderBuildingId,
this.senderFloorId,
this.senderDepartmentId,
this.senderRoom,
this.senderAssignedEmployeeId,
this.senderMachineStatusId,
this.senderComment,
this.comment,
this.receiverEndUserId,
this.receiverEndUserName,
this.senderStartDate,
this.senderEndDate,
this.senderWorkingHours,
this.senderTravelingHours,
this.senderEngSignature,
this.senderAttachments,
this.receiverAssignedEmployeeId,
this.receiverMachineStatusId,
this.receiverComment,
this.receiverStartDate,
this.receiverEndDate,
this.receiverWorkingHours,
this.receiverTravelingHours,
this.receiverEngSignature,
this.receiverAttachments,
this.attachments,
this.assetNumber,
this.assetName,
this.manufacturerName,
this.modelName,
this.assetSerialNo,
this.destDepartmentName,
this.destBuildingName,
this.applied,
this.isSender,
this.extensionNo,
this.name,
this.employeeId,
this.createdDate,
this.createdOn,
this.destFloorName,
this.destSiteName,
this.manufacturerId,
this.modelId,
this.modifiedOn,
this.receiverAssignedEmployeeName,
this.receiverEngSignatureUrl,
this.receiverMachineStatusName,
this.senderAssignedEmployeeName,
this.senderBuildingName,
this.senderDepartmentName,
this.senderEngSignatureUrl,
this.senderFloorName,
this.senderMachineStatusName,
this.senderSiteName,
this.supplierId,
this.supplierName,
this.senderVisitTimers,
this.receiverVisitTimers,
this.assetTransferEngineerTimers,
this.tbsTimer,
this.timerModelList,
this.assistantEmployees,
this.modelAssistantEmployees,
this.assetTransferAssistantEmployeesReceiver,
this.assetTransferAssistantEmployeesSender,
this.statusValue,
});
AssetTransfer.fromJson(dynamic json) {
id = json['id'];
transferNo = json['transferNo'];
transferCode = json['transferCode'];
transferType = json["transferType"] == null ? null : Lookup.fromJson(json["transferType"]);
assetId = json['assetId'];
destSiteId = json['destSiteId'];
destBuildingId = json['destBuildingId'];
@ -130,6 +144,19 @@ class AssetTransfer {
receiverVisitTimers!.add(VisitTimers.fromJson(v));
});
}
if (json['assetTransferAssistantEmployeesSender'] != null) {
assetTransferAssistantEmployeesSender = [];
json['assetTransferAssistantEmployeesSender'].forEach((v) {
assetTransferAssistantEmployeesSender!.add(AssetTransferAssistantEmployees.fromJson(v));
});
}
if (json['assetTransferAssistantEmployeesReceiver'] != null) {
assetTransferAssistantEmployeesReceiver = [];
json['assetTransferAssistantEmployeesReceiver'].forEach((v) {
assetTransferAssistantEmployeesReceiver!.add(AssetTransferAssistantEmployees.fromJson(v));
});
}
tbsTimer = TimerModel();
// try {
// receiverTimer = TimerModel(startAt: DateTime.tryParse(receiverStartDate ?? ""), endAt: DateTime.tryParse(receiverEndDate ?? ""));
@ -151,6 +178,13 @@ class AssetTransfer {
receiverAttachments!.add(AssetTransferAttachment.fromJson(v));
});
}
if (senderAttachments != null) {
attachments = senderAttachments;
} else if (receiverAttachments != null) {
attachments = receiverAttachments;
}
print('sender attachment i got is ${senderAttachments?.length}');
assetNumber = json['assetNumber'];
assetName = json['assetName'];
manufacturerName = json['manufacturerName'];
@ -186,6 +220,8 @@ class AssetTransfer {
num? id;
num? transferNo;
String? transferCode;
int? statusValue;
Lookup? transferType;
String? assetSerialNo;
num? assetId;
String? assetNumber;
@ -216,6 +252,7 @@ class AssetTransfer {
String? senderTravelingHours;
String? senderEngSignature;
List<AssetTransferAttachment>? senderAttachments;
List<AssetTransferAttachment>? attachments;
String? receiverAssignedEmployeeId;
num? receiverMachineStatusId;
String? receiverComment;
@ -242,6 +279,7 @@ class AssetTransfer {
String? receiverMachineStatusName;
String? receiverEngSignatureUrl;
bool? applied;
bool? isSender;
dynamic extensionNo;
String? employeeId;
String? name;
@ -250,12 +288,21 @@ class AssetTransfer {
String? modifiedOn;
List<VisitTimers>? senderVisitTimers;
List<VisitTimers>? receiverVisitTimers;
List<VisitTimers>? assetTransferEngineerTimers;
List<TimerModel>? timerModelList = [];
List<AssistantEmployees>? assistantEmployees;
List<AssetTransferAssistantEmployees>? assetTransferAssistantEmployeesSender;
List<AssetTransferAssistantEmployees>? assetTransferAssistantEmployeesReceiver;
AssetTransferAssistantEmployees? modelAssistantEmployees;
TimerModel? tbsTimer = TimerModel();
AssetTransfer copyWith(
{num? id,
num? transferNo,
String? transferCode,
Lookup? transferType,
num? assetId,
num? destSiteId,
num? destBuildingId,
@ -326,6 +373,7 @@ class AssetTransfer {
id: id ?? this.id,
transferNo: transferNo ?? this.transferNo,
transferCode: transferCode ?? this.transferCode,
transferType: transferType ?? this.transferType,
assetId: assetId ?? this.assetId,
destSiteId: destSiteId ?? this.destSiteId,
destBuildingId: destBuildingId ?? this.destBuildingId,
@ -375,10 +423,10 @@ class AssetTransfer {
receiverMachineStatusName: receiverMachineStatusName ?? this.receiverMachineStatusName,
receiverEngSignatureUrl: receiverEngSignatureUrl ?? this.receiverEngSignatureUrl,
applied: applied ?? this.applied,
extensionNo: extensionNo??this.extensionNo,
employeeId: employeeId??this.employeeId,
name: name??this.name,
createdDate: createdDate??this.createdDate,
extensionNo: extensionNo ?? this.extensionNo,
employeeId: employeeId ?? this.employeeId,
name: name ?? this.name,
createdDate: createdDate ?? this.createdDate,
createdOn: createdOn ?? this.createdOn,
modifiedOn: modifiedOn ?? this.modifiedOn,
assetSerialNo: assetSerialNo ?? this.assetSerialNo,
@ -472,6 +520,48 @@ class AssetTransfer {
return map;
}
Map<String, dynamic> toCreateAssetTransferJson() {
final map = <String, dynamic>{};
map['id'] = id;
map['assetId'] = assetId;
map['transferTypeId'] = transferType?.id;
map['destSiteId'] = destSiteId;
map['destSiteId'] = destSiteId;
map['destBuildingId'] = destBuildingId;
map['destFloorId'] = destFloorId;
map['destDepartmentId'] = destDepartmentId;
map['destRoomId'] = destRoomId;
map['comment'] = comment;
if (attachments != null) {
map['attachments'] = attachments!.map((v) => v.toJson()).toList();
}
return map;
}
Map<String, dynamic> toEngineerUpdateJson() {
final map = <String, dynamic>{};
map['id'] = id;
map['statusValue'] = statusValue;
map['isSender'] = isSender;
map['techComment'] = isSender! ? senderComment : receiverComment;
map['assetTransferAssistantEmployees'] = modelAssistantEmployees;
map['assetTransferEngineerTimers'] = assetTransferEngineerTimers;
if (attachments != null) {
map['attachments'] = attachments!.map((v) => v.toJson()).toList();
}
if (assetTransferEngineerTimers != null) {
map['assetTransferEngineerTimers'] = assetTransferEngineerTimers!.map((v) => v.toJson()).toList();
}
if (modelAssistantEmployees != null) {
if (modelAssistantEmployees!.employeeId != null) {
map['assetTransferAssistantEmployees'] = [modelAssistantEmployees!.toJson()];
} else {
map['assetTransferAssistantEmployees'] = [];
}
}
return map;
}
Map<String, dynamic> transferBody({Asset? asset}) {
final map = <String, dynamic>{};
map['id'] = 0;
@ -526,6 +616,7 @@ class AssetTransfer {
if (assetTransfer == null) return;
id = assetTransfer.id;
transferNo = assetTransfer.transferNo;
transferType = assetTransfer.transferType;
transferCode = assetTransfer.transferCode;
assetId = assetTransfer.assetId;
destSiteId = assetTransfer.destSiteId;
@ -591,6 +682,8 @@ class AssetTransfer {
manufacturerName = assetTransfer.manufacturerName;
senderVisitTimers = assetTransfer.senderVisitTimers;
receiverVisitTimers = assetTransfer.receiverVisitTimers;
assetTransferAssistantEmployeesReceiver = assetTransfer.assetTransferAssistantEmployeesReceiver;
assetTransferAssistantEmployeesSender = assetTransfer.assetTransferAssistantEmployeesSender;
}
Future<bool> validate(BuildContext context) async {
@ -613,3 +706,42 @@ class AssetTransfer {
return true;
}
}
class AssetTransferAssistantEmployees {
DateTime? startDate;
DateTime? endDate;
double? workingHours;
String? techComment;
String? employeeId;
String? employeeNumber;
String? employeeName;
String? email;
String? mobileNo;
dynamic extension;
AssetTransferAssistantEmployees(
{this.startDate, this.endDate, this.workingHours, this.techComment, this.employeeId, this.employeeName, this.employeeNumber, this.email, this.extension, this.mobileNo});
AssetTransferAssistantEmployees.fromJson(Map<String, dynamic> json) {
startDate = json['startDate'] != null ? DateTime.parse(json['startDate']) : null;
endDate = json['endDate'] != null ? DateTime.parse(json['endDate']) : null;
workingHours = json['workingHours'];
techComment = json['techComment'];
employeeId = json['employeeId'];
employeeNumber = json['employeeNumber'];
employeeName = json['employeeName'];
email = json['email'];
mobileNo = json['mobileNo'];
extension = json['extension'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['startDate'] = startDate?.toIso8601String();
data['endDate'] = endDate?.toIso8601String();
data['workingHours'] = workingHours;
data['techComment'] = techComment;
data['employeeId'] = employeeId;
return data;
}
}

@ -12,7 +12,6 @@ class ActivityMaintenanceHelperModel {
//remove this
int? lastSituationId;
Lookup? lastSituation;
Lookup? activityStatus;
DateTime? startTime;
DateTime? endTime;

@ -41,6 +41,14 @@ class WorkOrderHelperModel {
}
return data;
}
Map<String, dynamic> toUploadAttachmentJson(int? workOrderId,List<WorkOrderAttachments>? workOrderAttachments) {
final Map<String, dynamic> data = <String, dynamic>{};
data['workOrderId'] = workOrderId;
if (workOrderAttachments != null) {
data['workOrderAttachments'] = workOrderAttachments!.map((v) => v.toJson()).toList();
}
return data;
}
}
class WorkOrderAttachments {
@ -73,6 +81,7 @@ class EngineerUpdateWorkOrderHelperModel {
Lookup? failureReason;
FaultDescription? faultDescription;
String? solution;
String? callResponse;
EngineerUpdateWorkOrderHelperModel({
this.workOrderId,
@ -85,6 +94,7 @@ class EngineerUpdateWorkOrderHelperModel {
this.serviceType,
this.solution,
this.returnToService,
this.callResponse,
});
Map<String, dynamic> toJson() {
@ -96,6 +106,7 @@ class EngineerUpdateWorkOrderHelperModel {
data['loanAssetId'] = loanAssetId;
data['failureReasonId'] = failureReason?.id;
data['faultDescriptionId'] = faultDescription?.id;
data['callResponse'] = callResponse;
return data;
}
}

@ -1,5 +1,6 @@
import 'package:test_sa/models/base.dart';
import 'package:test_sa/models/new_models/assigned_employee.dart';
// int? id;
// String? userId;
// DateTime? startDate;
@ -7,9 +8,9 @@ import 'package:test_sa/models/new_models/assigned_employee.dart';
// int? workingHours;
// String? technicalComment;
class AssistantEmployees extends Base {
String? userId;
AssistantEmployees({
this.id,
this.user,

@ -12,37 +12,77 @@ import 'package:test_sa/models/new_models/site.dart';
import 'package:test_sa/models/timer_model.dart';
class GasRefillModel {
GasRefillModel(
{this.id,
this.gazRefillNo,
this.expectedDate,
this.expectedTime,
this.startDate,
this.startTime,
this.endDate,
this.endTime,
this.engSignature,
this.nurseSignature,
this.workingHours,
this.extensionNo,
this.employeeId,
this.name,
this.createdDate,
this.site,
this.building,
this.floor,
this.department,
this.assignedEmployee,
this.status,
this.comment,
this.gazRefillDetails,
this.localEngineerSignature,
this.localNurseSignature,
this.timer});
GasRefillModel({
this.id,
this.gasRefillNo,
this.expectedDate,
this.expectedTime,
this.startDate,
this.startTime,
this.endDate,
this.endTime,
this.engSignature,
this.nurseSignature,
this.workingHours,
this.extensionNo,
this.employeeId,
this.name,
this.createdDate,
this.site,
this.building,
this.floor,
this.department,
this.assignedEmployee,
this.status,
this.comment,
this.techComment,
this.gasRefillDetails,
this.localEngineerSignature,
this.localNurseSignature,
this.timer,
this.timerModelList,
this.gasRefillTimers,
this.gasRefillAttachments,
this.statusValue,
});
num? id; // Now nullable
String? gasRefillNo; // Now nullable
String? expectedDate; // Now nullable
String? expectedTime; // Now nullable
String? startDate; // Now nullable
String? startTime; // Now nullable
String? endDate; // Now nullable
String? endTime; // Now nullable
String? engSignature; // Now nullable
String? nurseSignature; // Now nullable
double? workingHours;
dynamic extensionNo;
String? employeeId;
String? name;
String? createdDate;
Site? site; // Now nullable
Building? building; // Now nullable
Floor? floor; // Now nullable
Department? department; // Now nullable
AssignedEmployee? assignedEmployee; // Now nullable
Lookup? status; // Now nullable
String? comment; // Now nullable
String? techComment; // Now nullable
List<GasRefillDetails>? gasRefillDetails; // Now nullable
Uint8List? localNurseSignature; // Now nullable
Uint8List? localEngineerSignature; // Now nullable
TimerModel? timer = TimerModel();
//TODO need to check when api provided..
List<TimerModel>? timerModelList = [];
List<GasRefillTimer>? gasRefillTimers = [];
List<GasRefillAttachments>? gasRefillAttachments;
int? statusValue;
GasRefillModel.fromJson(dynamic json) {
id = json['id'];
gazRefillNo = json['gazRefillNo'];
gasRefillNo = json['gasRefillNo'];
expectedDate = json['expectedDate'];
expectedTime = json['expectedTime'];
startDate = json['startDate'];
@ -50,28 +90,44 @@ class GasRefillModel {
endDate = json['endDate'];
endTime = json['endTime'];
comment = json['comment'];
techComment = json['techComment'];
workingHours = json['workingHours'];
extensionNo = json['extensionNo'];
employeeId = json['employeeId'];
name = json['name'];
createdDate = json['createdDate'];
try {
final DateTime? sd = DateTime.tryParse(startDate ?? "");
final DateTime? st = DateTime.tryParse(startTime ?? "");
final DateTime? ed = DateTime.tryParse(endDate ?? "");
final DateTime? et = DateTime.tryParse(endTime ?? "");
timer = TimerModel(
startAt: st == null ? sd : sd?.add(Duration(hours: st.hour, minutes: st.minute, seconds: st.second)), // Handle potential null 'sd'
endAt: et == null ? ed : ed?.add(Duration(hours: et.hour, minutes: et.minute, seconds: et.second)), // Handle potential null 'ed'
);
if (timer!.endAt != null && timer!.startAt != null) {
// Use '!' since timer could be null after initialization
timer!.durationInSecond = (timer!.endAt!.difference(timer!.startAt!)).inSeconds;
workingHours = (((timer!.durationInSecond ?? 0) / 60) / 60);
}
} catch (e) {
print(e);
if (json['gasRefillTimers'] != null) {
gasRefillTimers = <GasRefillTimer>[];
json['gasRefillTimers'].forEach((v) {
gasRefillTimers?.add(GasRefillTimer.fromJson(v));
});
workingHours = json['gasRefillTimers'].fold(0.0, (sum, item) => (sum ?? 0) + DateTime.parse(item['endDate']).difference(DateTime.parse(item['startDate'])).inSeconds) ?? 0;
}
if (json['gasRefillAttachments'] != null) {
gasRefillAttachments = <GasRefillAttachments>[];
json['gasRefillAttachments'].forEach((v) {
gasRefillAttachments!.add(GasRefillAttachments.fromJson(v));
});
}
// try {
// final DateTime? sd = DateTime.tryParse(startDate ?? "");
// final DateTime? st = DateTime.tryParse(startTime ?? "");
// final DateTime? ed = DateTime.tryParse(endDate ?? "");
// final DateTime? et = DateTime.tryParse(endTime ?? "");
// timer = TimerModel(
// startAt: st == null ? sd : sd?.add(Duration(hours: st.hour, minutes: st.minute, seconds: st.second)), // Handle potential null 'sd'
// endAt: et == null ? ed : ed?.add(Duration(hours: et.hour, minutes: et.minute, seconds: et.second)), // Handle potential null 'ed'
// );
// if (timer!.endAt != null && timer!.startAt != null) {
// // Use '!' since timer could be null after initialization
// timer!.durationInSecond = (timer!.endAt!.difference(timer!.startAt!)).inSeconds;
// workingHours = (((timer!.durationInSecond ?? 0) / 60) / 60);
// }
// } catch (e) {
// print(e);
// }
engSignature = json['engSignature'];
nurseSignature = json['nurseSignature'];
site = json['site'] != null ? Site.fromJson(json['site']) : null;
@ -80,129 +136,93 @@ class GasRefillModel {
department = json['department'] != null ? Department.fromJson(json['department']) : null;
assignedEmployee = json['assignedEmployee'] != null ? AssignedEmployee.fromJson(json['assignedEmployee']) : null;
status = json['status'] != null ? Lookup.fromJson(json['status']) : null;
if (json['gazRefillDetails'] != null) {
gazRefillDetails = [];
json['gazRefillDetails'].forEach((v) {
gazRefillDetails!.add(GasRefillDetails.fromJson(v)); // Use '!' since gazRefillDetails is initialized here
if (json['gasRefillDetails'] != null) {
gasRefillDetails = [];
json['gasRefillDetails'].forEach((v) {
gasRefillDetails!.add(GasRefillDetails.fromJson(v)); // Use '!' since gasRefillDetails is initialized here
});
}
}
num? id; // Now nullable
String? gazRefillNo; // Now nullable
String? expectedDate; // Now nullable
String? expectedTime; // Now nullable
String? startDate; // Now nullable
String? startTime; // Now nullable
String? endDate; // Now nullable
String? endTime; // Now nullable
String? engSignature; // Now nullable
String? nurseSignature; // Now nullable
num? workingHours;
dynamic extensionNo;
String? employeeId;
String? name;
String? createdDate;
Site? site; // Now nullable
Building? building; // Now nullable
Floor? floor; // Now nullable
Department? department; // Now nullable
AssignedEmployee? assignedEmployee; // Now nullable
Lookup? status; // Now nullable
String? comment; // Now nullable
List<GasRefillDetails>? gazRefillDetails; // Now nullable
Uint8List? localNurseSignature; // Now nullable
Uint8List? localEngineerSignature; // Now nullable
TimerModel? timer; // Now nullable
GasRefillModel copyWith({
num? id, // Parameters are now nullable
String? gazRefillNo,
String? expectedDate,
String? expectedTime,
String? startDate,
String? startTime,
String? endDate,
String? endTime,
String? engSignature,
String? nurseSignature,
num? workingHours,
num? extensionNo,
num? employeeId,
String? name,
String? createdDate,
Site? site,
Building? building,
Floor? floor,
Department? department,
AssignedEmployee? assignedEmployee,
Lookup? status,
String? comment,
List<GasRefillDetails>? gazRefillDetails,
TimerModel? timer,
}) =>
GasRefillModel(
id: id ?? this.id,
gazRefillNo: gazRefillNo ?? this.gazRefillNo,
expectedDate: expectedDate ?? this.expectedDate,
expectedTime: expectedTime ?? this.expectedTime,
startDate: startDate ?? this.startDate,
startTime: startTime ?? this.startTime,
endDate: endDate ?? this.endDate,
endTime: endTime ?? this.endTime,
engSignature: engSignature ?? this.engSignature,
nurseSignature: nurseSignature ?? this.nurseSignature,
workingHours: workingHours ?? this.workingHours,
site: site ?? this.site,
building: building ?? this.building,
floor: floor ?? this.floor,
department: department ?? this.department,
assignedEmployee: assignedEmployee ?? this.assignedEmployee,
status: status ?? this.status,
comment: comment ?? this.comment,
gazRefillDetails: gazRefillDetails ?? this.gazRefillDetails,
timer: timer ?? this.timer,
);
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['id'] = id ?? 0;
map['gazRefillNo'] = "GR-${DateTime.now().toString().split(" ").first}";
map['expectedDate'] = expectedDate;
map['expectedTime'] = expectedTime;
map['startDate'] = startDate;
map['startTime'] = startTime;
map['endDate'] = endDate;
map['endTime'] = endTime;
map['engSignature'] = engSignature;
map['nurseSignature'] = nurseSignature;
map['workingHours'] = workingHours;
map['extensionNo'] = extensionNo;
map['employeeId'] = employeeId;
map['name'] = name;
map['createdDate'] = createdDate;
map['comment'] = comment;
map['gasTypeId'] = gasRefillDetails?[0].gasType?.id;
map['cylinderTypeId'] = gasRefillDetails?[0].cylinderType?.id;
map['cylinderSizeId'] = gasRefillDetails?[0].cylinderSize?.id;
map['requestedQty'] = gasRefillDetails?[0].requestedQty;
if (site != null) {
map['site'] = site?.toJson(addBuildings: false); // Use '?.' for null safety
map['siteId'] = site?.id; // Use '?.' for null safety
}
if (building != null) {
map['building'] = building?.toJson(addFloor: false); // Use '?.' for null safety
map['buildingId'] = building?.id; // Use '?.' for null safety
}
if (floor != null) {
map['floor'] = floor?.toJson(addDepartments: false); // Use '?.' for null safety
map['floorId'] = floor?.id; // Use '?.' for null safety
}
if (department != null) {
map['department'] = department?.toJson(); // Use '?.' for null safety
map['departmentId'] = department?.id; // Use '?.' for null safety
}
if (assignedEmployee != null) {
map['assignedEmployee'] = assignedEmployee?.toJson(); // Use '?.' for null safety
map['comment'] = comment;
if (gasRefillAttachments != null) {
map['gasRefillAttachments'] = gasRefillAttachments?.map((v) => v.toJson()).toList();
}
if (status != null) {
map['status'] = status?.toJson(); // Use '?.' for null safety
//older code.....
// map['gasRefillNo'] = "GR-${DateTime.now().toString().split(" ").first}";
// map['expectedTime'] = expectedTime;
//
// map['startDate'] = startDate;
// map['startTime'] = startTime;
// map['endDate'] = endDate;
// map['endTime'] = endTime;
// map['engSignature'] = engSignature;
// map['nurseSignature'] = nurseSignature;
// map['workingHours'] = workingHours;
// map['extensionNo'] = extensionNo;
// map['employeeId'] = employeeId;
// map['name'] = name;
// map['createdDate'] = createdDate;
// map['comment'] = comment;
// if (site != null) {
// map['site'] = site?.toJson(addBuildings: false); // Use '?.' for null safety
// }
// if (building != null) {
// map['building'] = building?.toJson(addFloor: false); // Use '?.' for null safety
// }
// if (floor != null) {
// map['floor'] = floor?.toJson(addDepartments: false); // Use '?.' for null safety
// }
// if (department != null) {
// map['department'] = department?.toJson(); // Use '?.' for null safety
// }
// if (assignedEmployee != null) {
// map['assignedEmployee'] = assignedEmployee?.toJson(); // Use '?.' for null safety
// }
// if (status != null) {
// map['status'] = status?.toJson(); // Use '?.' for null safety
// }
// if (gasRefillDetails != null) {
// map['gasRefillDetails'] = gasRefillDetails!.map((v) => v.toJson()).toList(); // Use '!' since gasRefillDetails could be null
// }
return map;
}
Map<String, dynamic> toUpdateEngineerPayload({required int status}) {
final map = <String, dynamic>{};
map['id'] = id ?? 0;
map['deliveredQty'] = gasRefillDetails?[0].deliverdQty;
map['statusValue'] = status;
map['techComment'] = techComment;
if (gasRefillTimers != null) {
map['gasRefillTimers'] = gasRefillTimers?.map((v) => v.toJson()).toList();
}
if (gazRefillDetails != null) {
map['gazRefillDetails'] = gazRefillDetails!.map((v) => v.toJson()).toList(); // Use '!' since gazRefillDetails could be null
if (gasRefillAttachments != null) {
map['gasRefillAttachments'] = gasRefillAttachments?.map((v) => v.toJson()).toList();
}
return map;
}
@ -227,9 +247,9 @@ class GasRefillModel {
id = model.id;
//userId = model.userId;
site = model.site;
gazRefillNo = model.gazRefillNo;
gasRefillNo = model.gasRefillNo;
status = Lookup.fromStatus(model.status);
gazRefillDetails = model.gazRefillDetails;
gasRefillDetails = model.gasRefillDetails;
building = model.building;
floor = model.floor;
department = model.department;
@ -246,8 +266,63 @@ class GasRefillModel {
extensionNo = model.extensionNo;
employeeId = model.employeeId;
name = model.name;
techComment = model.techComment;
gasRefillAttachments = model.gasRefillAttachments;
createdDate = model.createdDate;
workingHours = model.workingHours;
gasRefillTimers=model.gasRefillTimers;
}
GasRefillModel copyWith({
num? id, // Parameters are now nullable
String? gasRefillNo,
String? expectedDate,
String? expectedTime,
String? startDate,
String? startTime,
String? endDate,
String? endTime,
String? engSignature,
String? nurseSignature,
double? workingHours,
num? extensionNo,
num? employeeId,
String? name,
String? createdDate,
Site? site,
Building? building,
Floor? floor,
Department? department,
AssignedEmployee? assignedEmployee,
Lookup? status,
String? comment,
List<GasRefillDetails>? gasRefillDetails,
List<GasRefillTimer>? gasRefillTimer,
TimerModel? timer,
}) =>
GasRefillModel(
id: id ?? this.id,
gasRefillNo: gasRefillNo ?? this.gasRefillNo,
expectedDate: expectedDate ?? this.expectedDate,
expectedTime: expectedTime ?? this.expectedTime,
startDate: startDate ?? this.startDate,
startTime: startTime ?? this.startTime,
endDate: endDate ?? this.endDate,
endTime: endTime ?? this.endTime,
engSignature: engSignature ?? this.engSignature,
nurseSignature: nurseSignature ?? this.nurseSignature,
workingHours: workingHours ?? this.workingHours,
site: site ?? this.site,
building: building ?? this.building,
floor: floor ?? this.floor,
department: department ?? this.department,
assignedEmployee: assignedEmployee ?? this.assignedEmployee,
status: status ?? this.status,
comment: comment ?? this.comment,
gasRefillDetails: gasRefillDetails ?? this.gasRefillDetails,
timer: timer ?? this.timer,
gasRefillTimers: gasRefillTimer ?? this.gasRefillTimers,
);
}
class GasRefillDetails {
@ -331,3 +406,50 @@ class GasRefillDetails {
return true;
}
}
class GasRefillTimer {
int? id;
String? startDate;
String? endDate;
dynamic workingHours;
GasRefillTimer({this.id, this.startDate, this.endDate, this.workingHours});
GasRefillTimer.fromJson(Map<String, dynamic> json) {
id = json['id'];
startDate = json['startDate'];
endDate = json['endDate'];
workingHours = json['workingHours'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['startDate'] = startDate;
data['endDate'] = endDate;
data['workingHours'] = workingHours;
return data;
}
}
class GasRefillAttachments {
int? id;
num? gasRefillId;
String? attachmentName;
GasRefillAttachments({this.id, this.attachmentName, this.gasRefillId});
GasRefillAttachments.fromJson(Map<String, dynamic> json) {
id = json['id'];
gasRefillId = json['gasRefillId'];
attachmentName = json['attachmentName'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['gasRefillId'] = gasRefillId;
data['attachmentName'] = attachmentName;
return data;
}
}

@ -84,6 +84,13 @@ class WorkOrderData {
required this.totalWorkingHours,
this.needAVisitComment,
this.needAVisitDateTime,
this.iHaveArrivedDate,
this.rejectReason,
this.closedDate,
this.since,
this.cmFrame,
this.rejectComment,
this.callResponse,
required this.workOrderHistory,
required this.activities,
required this.activityAssetToBeRetireds,
@ -127,9 +134,18 @@ class WorkOrderData {
Lookup? failureReasone;
FaultDescription? faultDescription;
Lookup? solution;
Lookup? cmFrame;
//cmComments
String? totalWorkingHours;
DateTime? needAVisitDateTime;
String? needAVisitComment;
String? iHaveArrivedDate;
String? closedDate;
Lookup? rejectReason;
String? rejectComment; // need to replace with reject comments.
String? callResponse; // need to replace with reject comments.
int? since;
List<WorkOrderHistory> workOrderHistory;
List<Activities> activities;
List<dynamic> activityAssetToBeRetireds;
@ -150,6 +166,13 @@ class WorkOrderData {
floor: json["floor"] == null ? null : Lookup.fromJson(json["floor"]),
department: json["department"] == null ? null : AssetGroup.fromJson(json["department"]),
room: json["room"],
rejectComment: json["rejectComment"],
callResponse: json["callResponse"],
iHaveArrivedDate: json["iHaveArrivedDate"],
closedDate: json["closedDate"],
cmFrame: json["cmFrame"] == null ? null : Lookup.fromJson(json["cmFrame"]),
rejectReason: json["rejectReason"] == null ? null : Lookup.fromJson(json["rejectReason"]),
since: json['since'],
assetType: json["assetType"] == null ? null : Lookup.fromJson(json["assetType"]),
assignedEmployee: json["assignedEmployee"] == null ? null : WorkOrderAssignedEmployee.fromJson(json["assignedEmployee"]),
lastActivityStatus: json["lastActivityStatus"] != null ? Lookup.fromJson(json["lastActivityStatus"]) : null,
@ -174,7 +197,7 @@ class WorkOrderData {
failureReasone: json["failureReasone"] == null ? null : Lookup.fromJson(json["failureReasone"]),
faultDescription: json["faultDescription"] == null ? null : FaultDescription.fromJson(json["faultDescription"]),
solution: json["solution"] == null ? null : Lookup.fromJson(json["solution"]),
totalWorkingHours: (json["totalWorkingHours"] ??"").toString(),
totalWorkingHours: (json["totalWorkingHours"] ?? "").toString(),
workOrderHistory: json["workOrderHistory"] == null ? [] : List<WorkOrderHistory>.from(json["workOrderHistory"]!.map((x) => WorkOrderHistory.fromJson(x))),
activities: json["activities"] == null ? [] : List<Activities>.from(json["activities"]!.map((x) => Activities.fromJson(x))),
needAVisitDateTime: DateTime.tryParse(json["needAVisitDateTime"] ?? ""),
@ -281,7 +304,7 @@ class WorkOrderAssignedEmployee {
required this.languageId,
});
dynamic userId;
String userId;
String? userName;
String? email;
int? languageId;
@ -357,7 +380,7 @@ class Activities {
activityStatus = json['activityStatus'] != null ? Lookup.fromJson(json['activityStatus']) : null;
activityMaintenance = json['activityMaintenance'] != null ? ActivityMaintenance.fromJson(json['activityMaintenance']) : null;
if (activityMaintenance != null) {
activityType = 'Maintenance Request';
activityType = 'CM Activity';
}
activitySparePart = json['activitySparePart'] != null ? ActivitySparePart.fromJson(json['activitySparePart']) : null;
@ -504,9 +527,9 @@ class WorkOrderContactPerson {
String? name;
String? employeeId;
String? position;
dynamic extension;
String? extension;
String? email;
dynamic mobilePhone;
String ?mobilePhone;
WorkOrderAssignedEmployee? contactUser;
factory WorkOrderContactPerson.fromJson(Map<String, dynamic> json) {
@ -619,6 +642,7 @@ class ActivityMaintenance {
String? supplierStartTime;
String? supplierEndTime;
double? supplierWorkingHours;
String? activityType;
List<ActivityMaintenanceAssistantEmployees>? assistantEmployees;
List<ActivityMaintenanceTimers>? activityMaintenanceTimers;
@ -638,6 +662,7 @@ class ActivityMaintenance {
this.supplierEngineer,
this.supplierStartTime,
this.supplierEndTime,
this.activityType,
this.supplierWorkingHours,
this.assistantEmployees});
@ -647,6 +672,7 @@ class ActivityMaintenance {
startTime = json['startTime'];
endTime = json['endTime'];
workingHours = json['workingHours'];
activityType = json['activityType'];
travelHours = json['travelHours'];
lastSituation = json['lastSituation'] != null ? Lookup.fromJson(json['lastSituation']) : null;
repairLocation = json['repairLocation'] != null ? Lookup.fromJson(json['repairLocation']) : null;

@ -3,6 +3,7 @@ import 'dart:io';
import 'package:flutter/widgets.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/models/device/asset.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/models/service_request/supplier_details.dart';
import 'package:test_sa/models/timer_model.dart';
@ -24,6 +25,8 @@ class PlanPreventiveVisit {
String? departmentName;
String? roomName;
String? fromDate;
String? creationDate;
String? closedDate;
String? toDate;
AssignedEmployee? assignedEmployee;
DateTime? acutalDateOfVisit;
@ -65,6 +68,8 @@ class PlanPreventiveVisit {
this.departmentName,
this.roomName,
this.fromDate,
this.creationDate,
this.closedDate,
this.toDate,
this.assignedEmployee,
this.acutalDateOfVisit,
@ -105,6 +110,8 @@ class PlanPreventiveVisit {
departmentName = json['departmentName'];
roomName = json['roomName'];
fromDate = json['fromDate'];
creationDate = json['creationDate'];
closedDate = json['closedDate'];
toDate = json['toDate'];
assignedEmployee = json['assignedEmployee'] != null ? AssignedEmployee.fromJson(json['assignedEmployee']) : null;
acutalDateOfVisit = json['acutalDateOfVisit'] != null ? DateTime.parse(json['acutalDateOfVisit']) : null;
@ -526,27 +533,27 @@ class PlanPreventiveVisit {
// }
// }
class Asset {
num? id;
String? assetNumber;
String? assetSerialNo;
Asset({this.id, this.assetNumber, this.assetSerialNo});
Asset.fromJson(Map<String, dynamic> json) {
id = json['id'];
assetNumber = json['assetNumber'];
assetSerialNo = json['assetSerialNo'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = Map<String, dynamic>();
data['id'] = this.id;
data['assetNumber'] = this.assetNumber;
data['assetSerialNo'] = this.assetSerialNo;
return data;
}
}
// class Asset {
// num? id;
// String? assetNumber;
// String? assetSerialNo;
//
// Asset({this.id, this.assetNumber, this.assetSerialNo});
//
// Asset.fromJson(Map<String, dynamic> json) {
// id = json['id'];
// assetNumber = json['assetNumber'];
// assetSerialNo = json['assetSerialNo'];
// }
//
// Map<String, dynamic> toJson() {
// final Map<String, dynamic> data = Map<String, dynamic>();
// data['id'] = this.id;
// data['assetNumber'] = this.assetNumber;
// data['assetSerialNo'] = this.assetSerialNo;
// return data;
// }
// }
class AssignedEmployee {
String? userId;
@ -776,136 +783,136 @@ class PreventiveVisitSuppliers {
}
}
class Supplier {
int? id;
String? suppliername;
String? name;
String? website;
String? email;
String? code;
int? suppNo;
String? suppStatusId;
String? cityId;
String? person;
String? comment;
String? zipcode;
String? contact;
List<String>? telephones;
List<String>? faxes;
List<String>? addresses;
List<String>? attachments;
List<SuppPersons>? suppPersons;
List<String>? suppTCodes;
Supplier(
{this.id,
this.suppliername,
this.name,
this.website,
this.email,
this.code,
this.suppNo,
this.suppStatusId,
this.cityId,
this.person,
this.comment,
this.zipcode,
this.contact,
this.telephones,
this.faxes,
this.addresses,
this.attachments,
this.suppPersons,
this.suppTCodes});
Supplier.fromJson(Map<String, dynamic> json) {
id = json['id'];
suppliername = json['suppliername'];
name = json['name'];
website = json['website'];
email = json['email'];
code = json['code'];
suppNo = json['suppNo'];
suppStatusId = json['suppStatusId'];
cityId = json['cityId'];
person = json['person'];
comment = json['comment'];
zipcode = json['zipcode'];
contact = json['contact'];
if (json['telephones'] != null) {
telephones = <String>[];
json['telephones'].forEach((v) {
telephones!.add(v);
});
}
if (json['faxes'] != null) {
faxes = <String>[];
json['faxes'].forEach((v) {
faxes!.add(v);
});
}
if (json['addresses'] != null) {
addresses = <String>[];
json['addresses'].forEach((v) {
addresses!.add(v);
});
}
if (json['attachments'] != null) {
attachments = <String>[];
json['attachments'].forEach((v) {
attachments!.add(v);
});
}
if (json['suppPersons'] != null) {
suppPersons = <SuppPersons>[];
json['suppPersons'].forEach((v) {
suppPersons!.add(SuppPersons.fromJson(v));
});
}
if (json['suppTCodes'] != null) {
suppTCodes = <String>[];
json['suppTCodes'].forEach((v) {
suppTCodes!.add(v);
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['suppliername'] = suppliername;
data['name'] = name;
data['website'] = website;
data['email'] = email;
data['code'] = code;
data['suppNo'] = suppNo;
data['suppStatusId'] = suppStatusId;
data['cityId'] = cityId;
data['person'] = person;
data['comment'] = comment;
data['zipcode'] = zipcode;
data['contact'] = contact;
if (telephones != null) {
data['telephones'] = telephones!.map((v) => v).toList();
}
if (faxes != null) {
data['faxes'] = faxes!.map((v) => v).toList();
}
if (addresses != null) {
data['addresses'] = addresses!.map((v) => v).toList();
}
if (attachments != null) {
data['attachments'] = attachments!.map((v) => v).toList();
}
if (suppPersons != null) {
data['suppPersons'] = suppPersons!.map((v) => v.toJson()).toList();
}
if (suppTCodes != null) {
data['suppTCodes'] = suppTCodes!.map((v) => v).toList();
}
return data;
}
}
// class Supplier {
// int? id;
// String? suppliername;
// String? name;
// String? website;
// String? email;
// String? code;
// int? suppNo;
// String? suppStatusId;
// String? cityId;
// String? person;
// String? comment;
// String? zipcode;
// String? contact;
// List<String>? telephones;
// List<String>? faxes;
// List<String>? addresses;
// List<String>? attachments;
// List<SuppPersons>? suppPersons;
// List<String>? suppTCodes;
//
// Supplier(
// {this.id,
// this.suppliername,
// this.name,
// this.website,
// this.email,
// this.code,
// this.suppNo,
// this.suppStatusId,
// this.cityId,
// this.person,
// this.comment,
// this.zipcode,
// this.contact,
// this.telephones,
// this.faxes,
// this.addresses,
// this.attachments,
// this.suppPersons,
// this.suppTCodes});
//
// Supplier.fromJson(Map<String, dynamic> json) {
// id = json['id'];
// suppliername = json['suppliername'];
// name = json['name'];
// website = json['website'];
// email = json['email'];
// code = json['code'];
// suppNo = json['suppNo'];
// suppStatusId = json['suppStatusId'];
// cityId = json['cityId'];
// person = json['person'];
// comment = json['comment'];
// zipcode = json['zipcode'];
// contact = json['contact'];
// if (json['telephones'] != null) {
// telephones = <String>[];
// json['telephones'].forEach((v) {
// telephones!.add(v);
// });
// }
// if (json['faxes'] != null) {
// faxes = <String>[];
// json['faxes'].forEach((v) {
// faxes!.add(v);
// });
// }
// if (json['addresses'] != null) {
// addresses = <String>[];
// json['addresses'].forEach((v) {
// addresses!.add(v);
// });
// }
// if (json['attachments'] != null) {
// attachments = <String>[];
// json['attachments'].forEach((v) {
// attachments!.add(v);
// });
// }
// if (json['suppPersons'] != null) {
// suppPersons = <SuppPersons>[];
// json['suppPersons'].forEach((v) {
// suppPersons!.add(SuppPersons.fromJson(v));
// });
// }
// if (json['suppTCodes'] != null) {
// suppTCodes = <String>[];
// json['suppTCodes'].forEach((v) {
// suppTCodes!.add(v);
// });
// }
// }
//
// Map<String, dynamic> toJson() {
// final Map<String, dynamic> data = <String, dynamic>{};
// data['id'] = id;
// data['suppliername'] = suppliername;
// data['name'] = name;
// data['website'] = website;
// data['email'] = email;
// data['code'] = code;
// data['suppNo'] = suppNo;
// data['suppStatusId'] = suppStatusId;
// data['cityId'] = cityId;
// data['person'] = person;
// data['comment'] = comment;
// data['zipcode'] = zipcode;
// data['contact'] = contact;
// if (telephones != null) {
// data['telephones'] = telephones!.map((v) => v).toList();
// }
// if (faxes != null) {
// data['faxes'] = faxes!.map((v) => v).toList();
// }
// if (addresses != null) {
// data['addresses'] = addresses!.map((v) => v).toList();
// }
// if (attachments != null) {
// data['attachments'] = attachments!.map((v) => v).toList();
// }
// if (suppPersons != null) {
// data['suppPersons'] = suppPersons!.map((v) => v.toJson()).toList();
// }
// if (suppTCodes != null) {
// data['suppTCodes'] = suppTCodes!.map((v) => v).toList();
// }
// return data;
// }
// }
// class SuppPersons {
// int? id;
@ -949,14 +956,14 @@ class PreventiveVisitKits {
PreventiveVisitKits.fromJson(Map<String, dynamic> json) {
id = json['id'];
partCatalogItem = json['partCatalogItem'] != null ? PartCatalogItem.fromJson(json['partCatalogItem']) : null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = Map<String, dynamic>();
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
if (partCatalogItem != null) {
// data['partCatalogItem'] = partCatalogItem!.toJson();
data['partCatalogItemId'] = partCatalogItem?.id;
}
return data;

@ -53,6 +53,7 @@ class RecurrentWoData {
TimerModel? recurrentWoTimerModel = TimerModel();
double? totalWorkingHours = 0.0;
List<TimerModel>? timerModelList = [];
String? comment;
RecurrentWoData(
{this.id,
@ -70,6 +71,7 @@ class RecurrentWoData {
this.planRecurrentMedicalTaskRooms,
this.planRecurrentTaskTimers,
this.timerModelList,
this.comment,
this.totalWorkingHours});
RecurrentWoData.fromJson(Map<String, dynamic> json) {
@ -84,6 +86,7 @@ class RecurrentWoData {
floor = json["floor"] == null ? null : Lookup.fromJson(json["floor"]);
department = json["department"] == null ? null : Lookup.fromJson(json["department"]);
room = json["room"] == null ? null : Lookup.fromJson(json["room"]);
comment = json["comment"];
if (json['planRecurrentMedicalTaskRooms'] != null) {
planRecurrentMedicalTaskRooms = <PlanRecurrentMedicalTaskRooms>[];
json['planRecurrentMedicalTaskRooms'].forEach((v) {
@ -114,6 +117,7 @@ class RecurrentWoData {
}
data['id'] = id;
data['statusValue'] = status;
data['comment'] = comment;
if (planRecurrentTaskTimers != null) {
data['planRecurrentTaskTimers'] = planRecurrentTaskTimers!.map((v) => v.toJson()).toList();
@ -289,7 +293,7 @@ class PlanRecurrentMedicalTaskRoomTabAttributes {
PlanRecurrentMedicalTaskRoomTabAttributes.fromJson(Map<String, dynamic> json) {
id = json['id'];
attribute = json['attribute'] != null ? Attribute.fromJson(json['attribute']) : null;
attributeValue = json['attributeValue'] ?? (json['attribute']['type'] == 'bool' ? (json['attributeValue']?.toString() == 'true') : json['attributeValue']);
attributeValue = json['attributeValue'];
}
Map<String, dynamic> toJson() {

@ -5,7 +5,7 @@ class SparePartsWorkOrders extends Base {
SparePartsWorkOrders.fromJson(dynamic json) {
id = json['id'];
sparePart = json['sparePart'] != null ? SparePart.fromJson(json['sparePart']) : null;
sparePart = json['sparePart'] != null ? SparePart.fromJson(json['sparePart'],true) : null;
qty = json['qty'];
returnQty = json['returnQty'];
@ -40,35 +40,84 @@ class SparePart extends Base {
this.partNo,
this.partName,
this.oracleCode,
this.displayName,
this.assetId,
}) : super(identifier: id?.toString(), name: partName);
SparePart.fromJson(dynamic json) {
SparePart.fromJson(dynamic json,bool ?isDisplayName) {
id = json['id'];
identifier = id?.toString();
partNo = json['partNo'];
partName = json['partName'];
displayName = json['displayName'];
oracleCode = json['oracleCode'];
name = partName;
name = isDisplayName!=null&&isDisplayName?displayName: partName;
assetId = json['assetId'];
}
num? id;
String? partNo;
String? partName;
String? displayName;
String? oracleCode;
num? assetId;
SparePart copyWith({num? id, String? partNo, String? partName, num? assetId,String?oracleCode}) =>
SparePart(id: id ?? this.id,oracleCode: oracleCode?? this.oracleCode, partNo: partNo ?? this.partNo, partName: partName ?? this.partName, assetId: assetId ?? this.assetId);
SparePart copyWith({num? id, String? partNo, String? partName, num? assetId,String?oracleCode,String ?displayName}) =>
SparePart(id: id ?? this.id,oracleCode: oracleCode?? this.oracleCode, partNo: partNo ?? this.partNo, partName: partName ?? this.partName, assetId: assetId ?? this.assetId,displayName: displayName??this.displayName);
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['id'] = id;
map['partNo'] = partNo;
map['partName'] = partName;
map['displayName'] = displayName;
map['oracleCode'] = oracleCode;
map['assetId'] = assetId;
return map;
}
}
class StoreAvailability {
final int ?id;
final int? storeId;
final int ?availablityQty;
final String? siteName;
final String ?storeName;
final int? requestedQty;
final bool? alreadyRequestFromThisStore;
StoreAvailability({
this.id,
this.storeId,
this.availablityQty,
this.siteName,
this.storeName,
this.requestedQty,
this.alreadyRequestFromThisStore,
});
factory StoreAvailability.fromJson(Map<String, dynamic> json) {
return StoreAvailability(
id: json['id'] ?? 0,
storeId: json['storeId'] ?? 0,
availablityQty: json['availablityQty'] ?? 0,
siteName: json['siteName'] ?? '',
storeName: json['storeName'] ?? '',
requestedQty: json['requestedQty'] ?? 0,
alreadyRequestFromThisStore: json['alreadyRequestFromThisStore'] ?? false,
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'storeId': storeId,
'availablityQty': availablityQty,
'siteName': siteName,
'storeName': storeName,
'requestedQty': requestedQty,
'alreadyRequestFromThisStore': alreadyRequestFromThisStore,
};
}
}

@ -47,6 +47,7 @@ class AppColor {
static const Color white60 = Color(0xffEFEFEF);
static const Color white70 = Color(0xffF1F1F1);
static const Color white80 = Color(0xffF2F4FA);
static const Color white90 = Color(0xffBFD1E4);
static const Color white936 = Color(0xff212936);
//black
@ -79,6 +80,7 @@ class AppColor {
static const Color orange50 = Color(0xffCC9B14);
static const Color orange60 = Color(0xff886400);
static const Color orange70 = Color(0xffFFC945);
static const Color orange80 = Color(0xff65531B);
// static Color greenStatus(BuildContext context) => context.isDark ? const Color(0xff1FA269) : green50;
static Color greenStatus(BuildContext context) => context.isDark ? const Color(0xff54C166) : green70.withOpacity(.5);
@ -136,6 +138,27 @@ class AppColor {
return Colors.white;
}
}
static Color getActivityTypeBgColor(String type) {
switch (type) {
case "Internal":
return neutral50;
case "External":
return white90;
default:
return primary10;
}
}
static Color getActivityTypeTextColor(String type) {
switch (type) {
case "Internal":
return white10;
case "External":
return black10;
default:
return Colors.white;
}
}
static Color getHistoryLogStatusColorByName(String status) {
switch ((status).toLowerCase()) {

@ -15,6 +15,7 @@ class AppFilledButton extends StatelessWidget {
final Color? textColor;
final bool showBorder;
final double radius;
final int height;
final bool disableButton;
const AppFilledButton(
@ -25,6 +26,7 @@ class AppFilledButton extends StatelessWidget {
this.icon,
this.fontSize,
this.loading = false,
this.height = 56,
this.showBorder = false,
this.disableButton = false,
this.buttonColor,
@ -36,7 +38,7 @@ class AppFilledButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
height: 56.toScreenHeight,
height: height.toScreenHeight,
width: maxWidth ? double.infinity : null,
alignment: Alignment.center,
decoration: BoxDecoration(

@ -9,7 +9,7 @@ import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/enums/user_types.dart';
import 'package:test_sa/models/user.dart';
import 'package:test_sa/new_views/pages/new_gas_refill_request_page.dart';
import 'package:test_sa/views/pages/device_transfer/request_device_transfer.dart';
import 'package:test_sa/views/pages/device_transfer/create__asset_transfer_request.dart';
import 'package:test_sa/views/pages/user/requests/create_service_request_page.dart';
import '../app_style/app_color.dart';
@ -40,7 +40,7 @@ class _AppFloatingActionButtonState extends State<AppFloatingActionButton> {
final elements = [
if (user.type == UsersTypes.normal_user) fabItem(context.translation.gasRefillRequest, "gas_refill_request", NewGasRefillRequestPage.routeName),
if (user.type == UsersTypes.normal_user) const Divider().defaultStyle(context).paddingOnly(top: 16, bottom: 16),
if (user.type == UsersTypes.normal_user) fabItem(context.translation.transferRequest, "transfer_request", RequestDeviceTransfer.id),
if (user.type == UsersTypes.normal_user) fabItem(context.translation.transferRequest, "transfer_request", CreateAssetTransferRequest.id),
if (user.type == UsersTypes.normal_user) const Divider().defaultStyle(context).paddingOnly(top: 16, bottom: 16),
if (user.type == UsersTypes.normal_user) fabItem(context.translation.serviceRequest, "service_request", CreateServiceRequestPage.id),
];

@ -4,6 +4,7 @@ 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/new_views/pages/land_page/land_page.dart';
import 'package:test_sa/new_views/swipe_module/dialoge/acknowledge_work_dialog.dart';
import '../app_style/app_color.dart';
@ -12,8 +13,10 @@ class DefaultAppBar extends StatelessWidget implements PreferredSizeWidget {
final List<Widget>? actions;
final Function? onBackPress;
final bool showHomeActionButton;
final VoidCallback? onWillPopScope;
final TextStyle? titleStyle;
const DefaultAppBar({this.title, this.onBackPress, this.actions, this.showHomeActionButton = false, Key? key}) : super(key: key);
const DefaultAppBar({this.title, this.onBackPress, this.onWillPopScope, this.actions,this.titleStyle, this.showHomeActionButton = false, Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
@ -40,6 +43,18 @@ class DefaultAppBar extends StatelessWidget implements PreferredSizeWidget {
title: Row(
children: [
const Icon(Icons.arrow_back_ios).onPress(() {
if (onWillPopScope != null) {
showDialog(
context: context,
builder: (BuildContext cxt) => AcknowledgeWorkDialog(
onSave: onWillPopScope!,
onDiscard: () {
Navigator.of(cxt).pop();
},
),
);
return;
}
if (onBackPress != null) {
onBackPress!();
} else {
@ -49,7 +64,7 @@ class DefaultAppBar extends StatelessWidget implements PreferredSizeWidget {
10.width,
Text(
title ?? "",
style: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
style:titleStyle?? AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
).expanded,
],
),

@ -8,6 +8,7 @@ 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';
import 'package:test_sa/views/pages/device_transfer/create__asset_transfer_request.dart';
class CreateRequestTypeBottomSheet extends StatelessWidget {
final bool isEngineer;
@ -65,7 +66,7 @@ class CreateRequestTypeBottomSheet extends StatelessWidget {
icon: 'add_icon',
label: context.translation.deviceTransfer,
onTap: () async {
Navigator.pushReplacementNamed(context, RequestDeviceTransfer.id);
Navigator.pushReplacementNamed(context, CreateAssetTransferRequest.id);
},
),
listCard(

@ -1,9 +1,11 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/user_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/enums/user_types.dart';
import 'package:test_sa/models/search_all_requests_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';
@ -43,6 +45,7 @@ class _AllRequestsFilterPageState extends State<AllRequestsFilterPage> {
@override
Widget build(BuildContext context) {
bool isEngineer = (Provider.of<UserProvider>(context, listen: false).user?.type) == UsersTypes.engineer;
if (search == null) {
search = SearchAllRequestsModel(
requestNumber: SearchByRequestNumberModel(context, controller: TextEditingController()),
@ -59,14 +62,17 @@ class _AllRequestsFilterPageState extends State<AllRequestsFilterPage> {
context.translation.gasRefill: 2,
context.translation.deviceTransfer: 3,
context.translation.preventiveMaintenance: 4,
context.translation.recurrentWo: 5,
};
if (isEngineer) {
types.addAll({context.translation.recurrentWo: 5});
}
final statuses = {
context.translation.allRequests: 0,
"All WO": 0,
context.translation.open: 1,
context.translation.inProgress: 2,
context.translation.completed: 4,
context.translation.closed: 3,
"Canceled": 5,
};
return Scaffold(
appBar: DefaultAppBar(
@ -99,7 +105,7 @@ class _AllRequestsFilterPageState extends State<AllRequestsFilterPage> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
context.translation.requestStatus.heading5(context),
"WO Status".heading5(context),
8.height,
RequestsTypeFilter(
initialValues: search?.statuses ?? [],
@ -116,7 +122,7 @@ class _AllRequestsFilterPageState extends State<AllRequestsFilterPage> {
},
),
16.height,
context.translation.typeOfRequest.heading5(context),
"Type of WO".heading5(context),
8.height,
RequestsTypeFilter(
initialValues: search?.typeTransaction ?? [],
@ -155,25 +161,25 @@ class _AllRequestsFilterPageState extends State<AllRequestsFilterPage> {
],
),
16.height,
"Archived Requests".heading5(context),
// 8.height,
Row(
children: [
Checkbox(
value: search?.isArchived ?? false,
activeColor: AppColor.blueStatus(context),
onChanged: (value) {
if (search?.isArchived != value) {
search?.isArchived = value!;
}
if (mounted) setState(() {});
}),
"View Archived Requests".bodyText(context).expanded,
],
).onPress(() {
search?.isArchived = !search!.isArchived;
setState(() {});
}),
// "Archived WO".heading5(context),
// // 8.height,
// Row(
// children: [
// Checkbox(
// value: search?.isArchived ?? false,
// activeColor: AppColor.blueStatus(context),
// onChanged: (value) {
// if (search?.isArchived != value) {
// search?.isArchived = value!;
// }
// if (mounted) setState(() {});
// }),
// "View Archived Requests".bodyText(context).expanded,
// ],
// ).onPress(() {
// search?.isArchived = !search!.isArchived;
// setState(() {});
// }),
],
).paddingOnly(start: 16, end: 16),
).expanded,

@ -21,7 +21,9 @@ class GasRefillItemView extends StatelessWidget {
@override
Widget build(BuildContext context) {
if (requestData != null) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [

@ -49,10 +49,11 @@ class PpmItemView extends StatelessWidget {
8.height,
(requestData?.typeTransaction ?? context.translation.ppmRequest).heading5(context),
8.height,
'${context.translation.assetName}: ${requestData!.assetName}'.bodyText(context),
'${context.translation.assetNumber}: ${requestData!.assetNumber}'.bodyText(context),
// '${context.translation.assetSN}: ${request.assetSN}'.bodyText(context),//todo ask ahmed
// '${context.translation.code}: ${request.code}'.bodyText(context),
'${context.translation.requestNo}: ${requestData!.requestNo}'.bodyText(context),
'PM No: ${requestData!.requestNo}'.bodyText(context),
16.height,
Row(
mainAxisSize: MainAxisSize.min,
@ -99,10 +100,11 @@ class PpmItemView extends StatelessWidget {
8.height,
(requestDetails?.nameOfType ?? context.translation.ppmRequest).heading5(context),
8.height,
'${context.translation.assetName}: ${requestDetails!.assetName}'.bodyText(context),
'${context.translation.assetNumber}: ${requestDetails!.assetNo}'.bodyText(context),
'${context.translation.assetSN}: ${requestDetails!.assetSN}'.bodyText(context),
// '${context.translation.code}: ${request.code}'.bodyText(context),
'${context.translation.requestNo}: ${requestDetails!.requestNo}'.bodyText(context),
'PM No: ${requestDetails!.requestNo}'.bodyText(context),
16.height,
Row(
mainAxisSize: MainAxisSize.min,

@ -52,7 +52,7 @@ class RecurrentWoItemView extends StatelessWidget {
// '${context.translation.assetNumber}: ${requestData!.assetNumber}'.bodyText(context),
// '${context.translation.assetSN}: ${request.assetSN}'.bodyText(context),//todo ask ahmed
// '${context.translation.code}: ${request.code}'.bodyText(context),
'${context.translation.requestNo}: ${requestData!.requestNo}'.bodyText(context),
'${context.translation.taskNo}: ${requestData!.requestNo}'.bodyText(context),
16.height,
Row(
mainAxisSize: MainAxisSize.min,
@ -102,7 +102,7 @@ class RecurrentWoItemView extends StatelessWidget {
// '${context.translation.taskNo}: ${requestDetails!.id}'.bodyText(context),
'${context.translation.site}: ${requestDetails!.site}'.bodyText(context),
// '${context.translation.code}: ${request.code}'.bodyText(context),
'${context.translation.requestNo}: ${requestDetails!.requestNo}'.bodyText(context),
'${context.translation.taskNo}: ${requestDetails!.requestNo}'.bodyText(context),
16.height,
Row(
mainAxisSize: MainAxisSize.min,

@ -52,12 +52,14 @@ class ServiceRequestItemView extends StatelessWidget {
8.height,
(requestData?.typeTransaction ?? context.translation.correctiveMaintenance).heading5(context),
8.height,
'${context.translation.assetName}: ${requestData!.assetName?.cleanupWhitespace.capitalizeFirstOfEach}'.bodyText(context),
'CM Number: ${requestData!.requestNo}'.bodyText(context),
'${context.translation.assetNumber}: ${requestData?.assetNumber}'.bodyText(context),
'${context.translation.assetName}: ${requestData?.assetName?.cleanupWhitespace.capitalizeFirstOfEach}'.bodyText(context),
// '${context.translation.assetNumber}: ${request.assetNo}'.bodyText(context),
// '${context.translation.requestType}: ${requestData!.requestTypeName}'.bodyText(context),
'${context.translation.requestNo}: ${requestData!.requestNo}'.bodyText(context),
if (requestData?.statusName == 'Canceled') ...[
'${context.translation.rejectionReason}: ${requestData!.rejectReason}'.bodyText(context),
'${context.translation.rejectionReason}: ${requestData?.rejectReason}'.bodyText(context),
],
8.height,
Row(
@ -110,10 +112,11 @@ class ServiceRequestItemView extends StatelessWidget {
8.height,
(requestDetails!.nameOfType ?? context.translation.correctiveMaintenance).heading5(context),
8.height,
'${context.translation.assetName}: ${requestDetails!.assetName?.cleanupWhitespace.capitalizeFirstOfEach}'.bodyText(context),
// '${context.translation.requestType}: ${requestDetails!.requestType}'.bodyText(context),
'CM Number: ${requestDetails!.requestNo}'.bodyText(context),
'${context.translation.assetNumber}: ${requestDetails!.assetNo}'.bodyText(context),
'${context.translation.requestType}: ${requestDetails!.requestType}'.bodyText(context),
'${context.translation.requestNo}: ${requestDetails!.requestNo}'.bodyText(context),
'${context.translation.assetName}: ${requestDetails!.assetName?.cleanupWhitespace.capitalizeFirstOfEach}'.bodyText(context),
8.height,
Row(
// mainAxisSize: MainAxisSize.min,

@ -1,7 +1,10 @@
import 'dart:convert';
import 'dart:developer';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/user_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';
@ -14,12 +17,17 @@ import 'package:test_sa/models/new_models/gas_refill_model.dart';
import 'package:test_sa/models/new_models/site.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/gas_request_providers/cylinder_size_provider.dart';
import 'package:test_sa/providers/gas_request_providers/cylinder_type_provider.dart';
import 'package:test_sa/providers/gas_request_providers/gas_types_provider.dart';
import 'package:test_sa/providers/gas_request_providers/site_provider.dart';
import 'package:test_sa/providers/loading_list_notifier.dart';
import 'package:test_sa/service_request_latest/utilities/service_request_utils.dart';
import 'package:test_sa/service_request_latest/views/components/action_button/footer_action_button.dart';
import 'package:test_sa/views/widgets/images/multi_image_picker.dart';
import '../../controllers/providers/api/gas_refill_provider.dart';
import '../common_widgets/default_app_bar.dart';
@ -36,6 +44,9 @@ class _NewGasRefillRequestPageState extends State<NewGasRefillRequestPage> {
late GasRefillDetails _currentDetails;
late GasRefillModel _gasModel;
Lookup? _requestedQuantity;
final TextEditingController _commentController = TextEditingController();
GasRefillProvider? _gasRefillProvider;
List<File> _files = [];
static List<Lookup> gasQuantity = [
Lookup(name: "1", id: 1, value: 1),
@ -48,8 +59,10 @@ class _NewGasRefillRequestPageState extends State<NewGasRefillRequestPage> {
@override
void initState() {
super.initState();
_gasRefillProvider ??= Provider.of<GasRefillProvider>(context, listen: false);
_gasModel =GasRefillModel();
_currentDetails = GasRefillDetails();
_gasModel = GasRefillModel(gazRefillDetails: []);
_gasModel = GasRefillModel(gasRefillDetails: []);
}
@override
@ -59,39 +72,33 @@ class _NewGasRefillRequestPageState extends State<NewGasRefillRequestPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: DefaultAppBar(title: context.translation.newGasRefillRequest),
body: Column(
children: [
12.height,
SingleChildScrollView(
child: Column(
children: [
16.height,
SingleItemDropDownMenu<Lookup, GasTypesProvider>(
context: context,
title: context.translation.gasType,
initialValue: _currentDetails.gasType,
backgroundColor: AppColor.neutral100,
showShadow: false,
showAsBottomSheet: true,
onSelect: (value) {
_currentDetails.gasType = value;
},
),
8.height,
SingleItemDropDownMenu<Lookup, NullableLoadingProvider>(
context: context,
title: context.translation.quantity,
initialValue: _requestedQuantity,
staticData: gasQuantity,
onSelect: (value) {
_requestedQuantity = value;
_currentDetails.requestedQty = value?.value;
},
),
8.height,
SingleItemDropDownMenu<Lookup, CylinderTypesProvider>(
context: context,
title: context.translation.cylinderType,
initialValue: _currentDetails.cylinderType,
backgroundColor: AppColor.neutral100,
showShadow: false,
onSelect: (value) {
_currentDetails.cylinderType = value;
},
@ -102,136 +109,153 @@ class _NewGasRefillRequestPageState extends State<NewGasRefillRequestPage> {
title: context.translation.cylinderSize,
initialValue: _currentDetails.cylinderSize,
showAsBottomSheet: true,
backgroundColor: AppColor.neutral100,
showShadow: false,
onSelect: (value) {
_currentDetails.cylinderSize = value;
},
),
8.height,
SingleItemDropDownMenu<Site, SiteProvider>(
SingleItemDropDownMenu<Lookup, NullableLoadingProvider>(
context: context,
title: context.translation.site,
initialValue: _gasModel.site,
title: context.translation.quantity,
showAsBottomSheet: true,
initialValue: _requestedQuantity,
staticData: gasQuantity,
backgroundColor: AppColor.neutral100,
showShadow: false,
onSelect: (value) {
setState(() {
_gasModel.site = value;
_gasModel.building = null;
_gasModel.floor = null;
_gasModel.department = null;
});
_requestedQuantity = value;
_currentDetails.requestedQty = value?.value;
},
),
8.height,
SingleItemDropDownMenu<Building, NullableLoadingProvider>(
context: context,
title: context.translation.building,
initialValue: _gasModel.building,
enabled: _gasModel.site?.buildings?.isNotEmpty ?? false,
staticData: _gasModel.site?.buildings ?? [],
showAsBottomSheet: true,
onSelect: (value) {
setState(() {
_gasModel.building = value;
_gasModel.floor = null;
_gasModel.department = null;
});
},
Row(
children: [
SingleItemDropDownMenu<Site, SiteProvider>(
context: context,
title: context.translation.site,
initialValue: _gasModel.site,
showAsBottomSheet: true,
backgroundColor: AppColor.neutral100,
showShadow: false,
onSelect: (value) {
setState(() {
_gasModel.site = value;
_gasModel.building = null;
_gasModel.floor = null;
_gasModel.department = null;
});
},
).expanded,
8.width,
SingleItemDropDownMenu<Building, NullableLoadingProvider>(
context: context,
title: context.translation.building,
initialValue: _gasModel.building,
enabled: _gasModel.site?.buildings?.isNotEmpty ?? false,
staticData: _gasModel.site?.buildings ?? [],
showAsBottomSheet: true,
backgroundColor: AppColor.neutral100,
showShadow: false,
onSelect: (value) {
setState(() {
_gasModel.building = value;
_gasModel.floor = null;
_gasModel.department = null;
});
},
).expanded,
],
),
8.height,
SingleItemDropDownMenu<Floor, NullableLoadingProvider>(
context: context,
title: context.translation.floor,
initialValue: _gasModel.floor,
enabled: _gasModel.building?.floors?.isNotEmpty ?? false,
staticData: _gasModel.building?.floors ?? [],
showAsBottomSheet: true,
onSelect: (value) {
setState(() {
_gasModel.floor = value;
_gasModel.department = null;
});
},
Row(
children: [
SingleItemDropDownMenu<Floor, NullableLoadingProvider>(
context: context,
title: context.translation.floor,
initialValue: _gasModel.floor,
enabled: _gasModel.building?.floors?.isNotEmpty ?? false,
staticData: _gasModel.building?.floors ?? [],
showAsBottomSheet: true,
backgroundColor: AppColor.neutral100,
showShadow: false,
onSelect: (value) {
setState(() {
_gasModel.floor = value;
_gasModel.department = null;
});
},
).expanded,
8.width,
SingleItemDropDownMenu<Department, NullableLoadingProvider>(
context: context,
title: context.translation.department,
initialValue: _gasModel.department,
enabled: _gasModel.floor?.departments?.isNotEmpty ?? false,
staticData: _gasModel.floor?.departments ?? [],
showAsBottomSheet: true,
backgroundColor: AppColor.neutral100,
showShadow: false,
onSelect: (value) {
_gasModel.department = value;
},
).expanded,
],
),
8.height,
SingleItemDropDownMenu<Department, NullableLoadingProvider>(
context: context,
title: context.translation.department,
initialValue: _gasModel.department,
enabled: _gasModel.floor?.departments?.isNotEmpty ?? false,
staticData: _gasModel.floor?.departments ?? [],
showAsBottomSheet: true,
onSelect: (value) {
_gasModel.department = value;
AppTextFormField(
labelText: context.translation.callComments,
labelStyle: AppTextStyles.tinyFont.copyWith(color: AppColor.neutral120),
textInputType: TextInputType.multiline,
alignLabelWithHint: true,
backgroundColor: AppColor.neutral100,
showShadow: false,
controller: _commentController,
onChange: (value){
_gasModel.comment = value;
},
onSaved: (value) {},
),
8.height,
if (_gasModel.gazRefillDetails?.isEmpty ?? true)
AppFilledButton(
label: context.translation.add,
maxWidth: true,
textColor: Colors.white,
buttonColor: context.isDark ? AppColor.neutral60 : AppColor.neutral50,
onPressed: _add,
),
ListView.builder(
shrinkWrap: true,
itemCount: _gasModel.gazRefillDetails?.length,
padding: const EdgeInsets.only(top: 12, bottom: 24),
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
(_gasModel.gazRefillDetails![index].gasType?.name ?? "").heading5(context),
8.height,
("${context.translation.quantity}: ${_gasModel.gazRefillDetails![index].requestedQty}").bodyText(context),
("${context.translation.cylinderSize}: ${_gasModel.gazRefillDetails![index].cylinderSize?.name}").bodyText(context),
("${context.translation.cylinderType}: ${_gasModel.gazRefillDetails![index].cylinderType?.name}").bodyText(context),
],
),
Container(
height: 48.toScreenWidth,
width: 48.toScreenWidth,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(100),
border: Border.all(color: context.isDark ? AppColor.neutral50 : AppColor.neutral30),
),
padding: EdgeInsets.symmetric(vertical: 12.toScreenHeight),
child: "trash".toSvgAsset(fit: BoxFit.fitHeight, color: context.isDark ? AppColor.red40 : AppColor.red50),
).onPress(() {
_delete(index);
}),
],
),
const Divider().defaultStyle(context),
("${context.translation.site}: ${_gasModel.site?.custName}").bodyText(context),
("${context.translation.building}: ${_gasModel.building?.name}").bodyText(context),
("${context.translation.floor}: ${_gasModel.floor?.name}").bodyText(context),
("${context.translation.department}: ${_gasModel.department?.departmentName}").bodyText(context),
],
).toShadowContainer(context);
},
MultiFilesPicker(
label: context.translation.attachFiles,
files:_files,
buttonColor: AppColor.black10,
onlyImages: false,
buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.neutral120),
),
],
),
).toShadowContainer(context, padding: 10).paddingOnly(start: 16, end: 16, top: 16),
).expanded,
16.height,
AppFilledButton(label: context.translation.submitRequest, maxWidth: true, onPressed: _submit),
FooterActionButton.footerContainer(child: AppFilledButton(label: context.translation.submitRequest, maxWidth: true, onPressed: _submit)),
],
).paddingOnly(start: 16, end: 16, bottom: 24),
),
);
}
Future<void> _submit() async {
if (_currentDetails.gasType==null) {
Fluttertoast.showToast(msg: context.translation.youHaveToAddRequests);
return;
}
_gasModel.gasRefillDetails=[];
_gasModel.gasRefillDetails?.add(_currentDetails);
_gasModel.gasRefillAttachments = [];
for (var item in _files) {
_gasModel.gasRefillAttachments?.add(GasRefillAttachments(
id: 0, gasRefillId: _gasModel.id ?? 0, attachmentName: ServiceRequestUtils.isLocalUrl(item.path) ? "${item.path.split("/").last}|${base64Encode(item.readAsBytesSync())}" : item.path));
}
await _gasRefillProvider?.addGasRefillRequest(
context: context,
model: _gasModel,
);
}
void _add() async {
if (_currentDetails.validate(context) && _gasModel.validate(context)) {
_gasModel.gazRefillDetails!.add(_currentDetails);
_gasModel.gasRefillDetails!.add(_currentDetails);
_currentDetails = GasRefillDetails();
_requestedQuantity = null;
setState(() {});
@ -239,19 +263,62 @@ class _NewGasRefillRequestPageState extends State<NewGasRefillRequestPage> {
}
void _delete(index) {
_gasModel.gazRefillDetails!.remove(_gasModel.gazRefillDetails![index]);
_gasModel.gasRefillDetails!.remove(_gasModel.gasRefillDetails![index]);
setState(() {});
}
Future<void> _submit() async {
if (_gasModel.gazRefillDetails?.isEmpty ?? true) {
Fluttertoast.showToast(msg: context.translation.youHaveToAddRequests);
return;
}
await Provider.of<GasRefillProvider>(context, listen: false).createModel(
context: context,
user: Provider.of<UserProvider>(context, listen: false).user!,
model: _gasModel,
);
}
//older code....
// if (_gasModel.gasRefillDetails?.isEmpty ?? true)
// AppFilledButton(
// label: context.translation.add,
// maxWidth: true,
// textColor: Colors.white,
// buttonColor: context.isDark ? AppColor.neutral60 : AppColor.neutral50,
// onPressed: _add,
// ),
// ListView.builder(
// shrinkWrap: true,
// itemCount: _gasModel.gasRefillDetails?.length,
// padding: const EdgeInsets.only(top: 12, bottom: 24),
// physics: const NeverScrollableScrollPhysics(),
// itemBuilder: (context, index) {
// return Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// (_gasModel.gasRefillDetails![index].gasType?.name ?? "").heading5(context),
// 8.height,
// ("${context.translation.quantity}: ${_gasModel.gasRefillDetails![index].requestedQty}").bodyText(context),
// ("${context.translation.cylinderSize}: ${_gasModel.gasRefillDetails![index].cylinderSize?.name}").bodyText(context),
// ("${context.translation.cylinderType}: ${_gasModel.gasRefillDetails![index].cylinderType?.name}").bodyText(context),
// ],
// ),
// Container(
// height: 48.toScreenWidth,
// width: 48.toScreenWidth,
// decoration: BoxDecoration(
// borderRadius: BorderRadius.circular(100),
// border: Border.all(color: context.isDark ? AppColor.neutral50 : AppColor.neutral30),
// ),
// padding: EdgeInsets.symmetric(vertical: 12.toScreenHeight),
// child: "trash".toSvgAsset(fit: BoxFit.fitHeight, color: context.isDark ? AppColor.red40 : AppColor.red50),
// ).onPress(() {
// _delete(index);
// }),
// ],
// ),
// const Divider().defaultStyle(context),
// ("${context.translation.site}: ${_gasModel.site?.custName}").bodyText(context),
// ("${context.translation.building}: ${_gasModel.building?.name}").bodyText(context),
// ("${context.translation.floor}: ${_gasModel.floor?.name}").bodyText(context),
// ("${context.translation.department}: ${_gasModel.department?.departmentName}").bodyText(context),
// ],
// ).toShadowContainer(context);
// },
// ),
}

@ -0,0 +1,67 @@
import 'package:flutter/material.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/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
class AcknowledgeWorkDialog extends StatelessWidget {
final String? title;
final String? message;
final String? okTitle;
final VoidCallback onSave;
final VoidCallback onDiscard;
const AcknowledgeWorkDialog(
{Key? key, this.title, this.message = "To prevent the risk of losing your changes, Please confirm Save or Discard", this.okTitle, required this.onSave, required this.onDiscard})
: super(key: key);
@override
Widget build(BuildContext context) {
return Dialog(
backgroundColor: Colors.white,
shape: const RoundedRectangleBorder(),
insetPadding: const EdgeInsets.only(left: 21, right: 21),
child: Padding(
padding: const EdgeInsets.only(left: 20, right: 20, top: 18, bottom: 28),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
const Text(
"Confirm",
style: TextStyle(fontSize: 24, fontWeight: FontWeight.w600, color: Colors.black87, height: 35 / 24, letterSpacing: -0.96),
).paddingOnly(top: 16, bottom: 8),
message != null ? message!.heading5(context).custom(color: AppColor.neutral50) : const SizedBox(),
28.height,
Row(
children: [
AppFilledButton(
label: "Discard",
buttonColor: Colors.white54,
textColor: AppColor.red30,
height: 40,
showBorder: true,
onPressed: () {
Navigator.of(context).pop();
onDiscard();
},
).expanded,
16.width,
AppFilledButton(
label: "Save",
onPressed: () {
Navigator.of(context).pop();
onSave();
},
height: 40,
buttonColor: AppColor.green70,
).expanded,
],
),
],
),
),
);
}
}

@ -6,13 +6,13 @@ import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
class ConfirmDialog extends StatelessWidget {
final String ?title;
final String ?message;
final String ?okTitle;
final VoidCallback ?onTap;
final VoidCallback ?onCloseTap;
final String? title;
final String? message;
final String? okTitle;
final VoidCallback? onTap;
final VoidCallback? onCloseTap;
const ConfirmDialog({Key ?key, this.title, this.message, this.okTitle, this.onTap, this.onCloseTap}) : super(key: key);
const ConfirmDialog({Key? key, this.title, this.message, this.okTitle, this.onTap, this.onCloseTap}) : super(key: key);
@override
Widget build(BuildContext context) {
@ -45,7 +45,7 @@ class ConfirmDialog extends StatelessWidget {
)
],
),
message!=null?message!.heading5(context).custom(color: AppColor.neutral70):const SizedBox(),
message != null ? message!.heading5(context).custom(color: AppColor.neutral70) : const SizedBox(),
28.height,
AppFilledButton(
label: okTitle ?? "OK",

@ -1,6 +1,7 @@
import 'dart:async';
import 'dart:convert';
import 'dart:developer';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:http/src/response.dart';
@ -13,7 +14,9 @@ import 'package:test_sa/models/helper_data_models/workorder/work_order_helper_mo
import 'package:test_sa/models/new_models/arrival_verification_type_model.dart';
import 'package:test_sa/models/new_models/dashboard_detail.dart';
import 'package:test_sa/models/new_models/work_order_detail_model.dart';
import 'package:test_sa/models/service_request/spare_parts.dart';
import 'package:test_sa/models/service_request/supplier_details.dart';
import 'package:test_sa/service_request_latest/utilities/service_request_utils.dart';
class ServiceRequestDetailProvider extends ChangeNotifier {
final pageItemNumber = 10;
@ -102,6 +105,15 @@ class ServiceRequestDetailProvider extends ChangeNotifier {
AssetRetiredHelperModel? assetRetiredHelperModel = AssetRetiredHelperModel();
ActivityMaintenanceHelperModel? activityMaintenanceHelperModel = ActivityMaintenanceHelperModel();
SparePartHelperModel? sparePartHelperModel;
List<StoreAvailability> _storeAvailability= [];
List<StoreAvailability> get storeAvailability => _storeAvailability;
set storeAvailability(List<StoreAvailability> value) {
_storeAvailability = value;
notifyListeners();
}
FixRemotelyHelperModel? fixRemotelyHelperModel = FixRemotelyHelperModel();
NeedVisitHelperModel? needVisitHelperModel = NeedVisitHelperModel();
NurseActionHelperModel? nurseActionHelperModel;
@ -183,7 +195,15 @@ class ServiceRequestDetailProvider extends ChangeNotifier {
notifyListeners();
}
//create workOrder nurse .....
bool _isReadOnlyRequest = false;
bool get isReadOnlyRequest => _isReadOnlyRequest;
set isReadOnlyRequest(bool value) {
_isReadOnlyRequest = value;
notifyListeners();
} //create workOrder nurse .....
Future<int> createWorkOrder() async {
isLoading = true;
notifyListeners();
@ -213,6 +233,39 @@ class ServiceRequestDetailProvider extends ChangeNotifier {
notifyListeners();
final response = await ApiManager.instance.get(URLs.getWorkOrderByIdUrl + "?workOrderId=$id");
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
currentWorkOrder = WorkOrderDetail.fromJson(json.decode(response.body));
//need to check on value as id changed on different env.
if (currentWorkOrder?.data?.status?.value == 3 || currentWorkOrder?.data?.status?.value == 5 || currentWorkOrder?.data?.status?.value == 6) {
isReadOnlyRequest = true;
} else {
isReadOnlyRequest = false;
}
}
isLoading = false;
notifyListeners();
} catch (e) {
log("getWorkOrder [error] : $e");
isLoading = false;
notifyListeners();
return null;
}
}
//upload workorder attachment by engineer..
Future addWorkOrderAttachment({required int woId, required List<File> attachments}) async {
try {
List<WorkOrderAttachments> woAttachments = [];
for (var file in attachments) {
String fileName = ServiceRequestUtils.isLocalUrl(file.path) ? ("${file.path.split("/").last}|${base64Encode(File(file.path).readAsBytesSync())}") : file.path;
woAttachments.add(WorkOrderAttachments(id: 0, name: fileName));
}
isLoading = true;
notifyListeners();
final response = await ApiManager.instance.post(URLs.uploadWorkOrderAttachmentsUrl, body: WorkOrderHelperModel().toUploadAttachmentJson(woId, woAttachments));
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
currentWorkOrder = WorkOrderDetail.fromJson(json.decode(response.body));
}
@ -700,6 +753,33 @@ class ServiceRequestDetailProvider extends ChangeNotifier {
}
}
Future<void> getStoreAvailabilityById({required num? partId}) async {
try {
isLoading = true;
notifyListeners();
final response = await ApiManager.instance.post(
URLs.getSparePartAvailableQuantity + "?PartId=$partId",
body: {},
);
print('response i got is ${response.body}');
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
final List<dynamic> data = json.decode(response.body)["data"];
storeAvailability = data.map((item) => StoreAvailability.fromJson(item)).toList();
}
isLoading = false;
notifyListeners();
} catch (e) {
log("getStoreAvalivility [error] : $e");
isLoading = false;
notifyListeners();
}
}
Future<int> deleteActivitySparePart({required int id, required int workOrderId}) async {
isLoading = true;
notifyListeners();

@ -457,7 +457,6 @@ class ConfirmArrivalNotificationModel {
this.accept,
});
// Factory constructor to create an instance from a Map (e.g., JSON)
factory ConfirmArrivalNotificationModel.fromJson(Map<String, dynamic> json) {
return ConfirmArrivalNotificationModel(
transactionType: json['transactionType'],

@ -8,6 +8,7 @@ import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/enums/user_types.dart';
import 'package:test_sa/models/enums/work_order_next_step.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/new_models/work_order_detail_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';
@ -34,10 +35,10 @@ class FooterActionButton {
{required WorkOrderNextStepEnum workOrderNextStepStatus,
List<Activities> activities = const [],
required BuildContext context,
Lookup? status,
required UserProvider userProvider,
bool isEmpIsAssigned = false}) {
ServiceRequestDetailProvider requestDetailProvider = Provider.of<ServiceRequestDetailProvider>(context, listen: false);
bool showMarkAsFixedButton = activities.isEmpty ? false : activities.any((object) => object.activityStatus!.value == 14 || object.activityStatus!.value == 19);
if (userProvider.user?.type == UsersTypes.engineer) {
if (workOrderNextStepStatus == WorkOrderNextStepEnum.assignToMe && isEmpIsAssigned) return const SizedBox();
@ -56,8 +57,39 @@ class FooterActionButton {
case WorkOrderNextStepEnum.markedAsFixed:
break;
// TODO: Handle this case.
case WorkOrderNextStepEnum.endWorkFlow:
if (requestDetailProvider.isReadOnlyRequest) {
return footerContainer(
child: AppFilledButton(
label: context.translation.activities,
buttonColor: AppColor.neutral50,
onPressed: () async {
Navigator.push(context, MaterialPageRoute(builder: (context) => const ActivitiesListView()));
},
),
);
}
return footerContainer(
child: AppFilledButton(
label: context.translation.close,
// maxWidth: true,
buttonColor: AppColor.primary10,
onPressed: () async {
Navigator.pop(context);
},
));
case WorkOrderNextStepEnum.nTakeAction:
// const SizedBox().flushBar(context: context, title: context.translation.youMarkedThisIssueAsFixedWaitingForTheRequesterToConfirm, message: '');
if (requestDetailProvider.isReadOnlyRequest) {
return footerContainer(
child: AppFilledButton(
label: context.translation.activities,
buttonColor: AppColor.neutral50,
onPressed: () async {
Navigator.push(context, MaterialPageRoute(builder: (context) => const ActivitiesListView()));
},
),
);
}
return footerContainer(
child: AppFilledButton(
label: context.translation.close,

@ -68,7 +68,7 @@ class _ActivitiesListViewState extends State<ActivitiesListView> {
//backgroundColor: const Color(0xfff8f9fb),
body: Consumer<ServiceRequestDetailProvider>(builder: (context, ServiceRequestDetailProvider requestDetailProvider, child) {
activities = requestDetailProvider.currentWorkOrder!.data!.activities;
requestDetailProvider.lastVisitedRequestActivityId = (activities.isNotEmpty? activities.last.id :-1)!;
requestDetailProvider.lastVisitedRequestActivityId = (activities.isNotEmpty ? activities.last.id : -1)!;
if (activities.isNotEmpty && (activities.last.activityStatus!.value == 14 || activities.last.activityStatus!.value == 19)) {
disableNewActivity = true;
} else {
@ -165,7 +165,7 @@ class _ActivitiesListViewState extends State<ActivitiesListView> {
// backgroundColor: AppColor.getHistoryLogStatusColorByName(activity.activityStatus!.name!),
backgroundColor: AppColor.primary10,
),
"drag_icon".toSvgAsset(height: 12, width: 23, color: AppColor.neutral160),
// "drag_icon".toSvgAsset(height: 12, width: 23, color: AppColor.neutral160),
if (userProvider.user!.type == UsersTypes.engineer && requestDetailProvider.currentWorkOrder?.data?.status?.value != 5 && requestDetailProvider.currentWorkOrder?.data?.status?.value != 3)
Row(
crossAxisAlignment: CrossAxisAlignment.start,
@ -225,11 +225,6 @@ class _ActivitiesListViewState extends State<ActivitiesListView> {
style: AppTextStyles.bodyText2.copyWith(color: AppColor.neutral120),
),
2.height,
//TODO description text not in api.
// Text(
// '${context.translation.date}: ${activity.currentSituation?.date}',
// style: AppTextStyles.bodyText2.copyWith(color: AppColor.neutral120),
// ),
if (activity.activitySparePart?.comment?.isNotEmpty ?? false) ...[
const Divider().defaultStyle(context),
2.height,
@ -245,11 +240,26 @@ class _ActivitiesListViewState extends State<ActivitiesListView> {
],
],
).toShadowContainer(context, padding: 12, showShadow: false).onPress(() {
//TODO write onview detail method..
// Navigator.push(
// context,
// MaterialPageRoute(builder: (context) => WorkOrderDetailsPage(workOrder: activity, serviceRequest: ServiceRequest())),
// );
// if(requestDetailProvider.currentWorkOrder?.data?.status?.id ==3498){
// requestDetailProvider.sparePartHelperModel = SparePartHelperModel(
// id: activity.id,
// workOrderId: requestDetailProvider.currentWorkOrder?.data?.requestId,
// comment: activity.activitySparePart?.comment,
// sparePartAttachments: activity.activitySparePart?.acitiySparePartAttachments ?? [],
// activityStatus: activity.activityStatus,
// sparePart: SparePart(
// id: activity.activitySparePart?.partCatalogItem?.id,
// partName: activity.activitySparePart?.partCatalogItem?.partName,
// partNo: activity.activitySparePart?.partCatalogItem?.partNumber,
// oracleCode: activity.activitySparePart?.partCatalogItem?.oracleCode),
// quantity: activity.activitySparePart?.quantity,
// activityStatusId: activity.activityStatus?.id,
// );
// requestDetailProvider.updateSparePartHelperModel(requestDetailProvider.sparePartHelperModel);
// Navigator.of(context).push(MaterialPageRoute(
// builder: (_) => const SparePartRequest(),
// ));
// }
});
}
@ -265,14 +275,27 @@ class _ActivitiesListViewState extends State<ActivitiesListView> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
//TODO will be here when fixed from backend..
StatusLabel(
label: activity.activityStatus?.name,
textColor: AppColor.white10,
// textColor: AppColor.getHistoryLogStatusTextColorByName(activity.activityStatus!.name!),
// backgroundColor: AppColor.getHistoryLogStatusColorByName(activity.activityStatus!.name!),
backgroundColor: AppColor.primary10,
Row(
children: [
StatusLabel(
label: activity.activityStatus?.name,
textColor: AppColor.white10,
// textColor: AppColor.getHistoryLogStatusTextColorByName(activity.activityStatus!.name!),
// backgroundColor: AppColor.getHistoryLogStatusColorByName(activity.activityStatus!.name!),
backgroundColor: AppColor.primary10,
),
5.width,
StatusLabel(
label: activity.activityMaintenance?.activityType,
// textColor: AppColor.white10,
textColor: AppColor.getActivityTypeTextColor(activity.activityMaintenance?.activityType??''),
backgroundColor: AppColor.getActivityTypeBgColor(activity.activityMaintenance?.activityType??''),
// backgroundColor: AppColor.primary10,
),
],
),
"drag_icon".toSvgAsset(height: 12, width: 23, color: AppColor.neutral160),
// "drag_icon".toSvgAsset(height: 12, width: 23, color: AppColor.neutral160),
if (userProvider.user!.type == UsersTypes.engineer && requestDetailProvider.currentWorkOrder?.data?.status?.value != 5 && requestDetailProvider.currentWorkOrder?.data?.status?.value != 3)
Row(
crossAxisAlignment: CrossAxisAlignment.start,
@ -308,7 +331,7 @@ class _ActivitiesListViewState extends State<ActivitiesListView> {
style: AppTextStyles.bodyText2.copyWith(color: AppColor.neutral120),
),
2.height,
if (activity.activityMaintenance?.assignedEmployee != null && activity.activityMaintenance!.assistantEmployees!.isNotEmpty) ...[
if (activity.activityMaintenance?.assistantEmployees != null && activity.activityMaintenance!.assistantEmployees!.isNotEmpty) ...[
Text(
'${context.translation.assistantEmployee}: ${activity.activityMaintenance?.assistantEmployees?.first.user?.userName}',
style: AppTextStyles.bodyText2.copyWith(color: AppColor.neutral120),
@ -329,8 +352,21 @@ class _ActivitiesListViewState extends State<ActivitiesListView> {
style: AppTextStyles.bodyText2.copyWith(color: AppColor.neutral120),
),
],
//need to add all info here...
// if(requestDetailProvider.currentWorkOrder?.data?.status?.id==3498)...[
// const Divider().defaultStyle(context),
// 2.height,
// // Text(
// // activity.activityMaintenance?.technicalComment ?? "",
// // style: AppTextStyles.bodyText2.copyWith(color: AppColor.neutral120),
// // ),
// ]
],
).toShadowContainer(context, padding: 12, showShadow: false);
).toShadowContainer(context, padding: 12, showShadow: false).onPress(() {
if (requestDetailProvider.isReadOnlyRequest) {
onEditMaintenanceRequestPress(context: context, requestDetailProvider: requestDetailProvider, activity: activity);
}
});
}
void onEditMaintenanceRequestPress({required BuildContext context, required ServiceRequestDetailProvider requestDetailProvider, required Activities activity}) async {
@ -391,7 +427,7 @@ class _ActivitiesListViewState extends State<ActivitiesListView> {
}
Navigator.of(context).push(MaterialPageRoute(
builder: (_) => const MaintenanceRequestForm(),
builder: (_) => MaintenanceRequestForm(),
));
}
}
@ -410,3 +446,14 @@ class ReorderWidget extends StatelessWidget {
);
}
}
class DummyClass extends StatelessWidget {
const DummyClass({super.key});
@override
Widget build(BuildContext context) {
return const Placeholder();
}
}

@ -27,27 +27,41 @@ class AssetDetailCard extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
StatusLabel(
label: requestDetailProvider.engineerUpdateWorkOrderHelperModel?.equipmentStatus?.name,
id: requestDetailProvider.engineerUpdateWorkOrderHelperModel!.equipmentStatus!.id ?? 0,
radius: 4,
textColor: AppColor.white10,
backgroundColor: AppColor.getEquipmentStatusColor(context, requestDetailProvider.engineerUpdateWorkOrderHelperModel!.equipmentStatus!.id ?? 0),
Row(
children: [
StatusLabel(
label: requestDetailProvider.engineerUpdateWorkOrderHelperModel?.equipmentStatus?.name,
id: requestDetailProvider.engineerUpdateWorkOrderHelperModel!.equipmentStatus!.id ?? 0,
radius: 4,
textColor: AppColor.white10,
backgroundColor: AppColor.getEquipmentStatusColor(context, requestDetailProvider.engineerUpdateWorkOrderHelperModel!.equipmentStatus!.id ?? 0),
),
5.width,
StatusLabel(
label: requestDetailProvider.engineerUpdateWorkOrderHelperModel?.serviceType?.name,
id: requestDetailProvider.engineerUpdateWorkOrderHelperModel?.serviceType?.id ?? 0,
radius: 4,
textColor: AppColor.getActivityTypeTextColor(requestDetailProvider.engineerUpdateWorkOrderHelperModel!.serviceType?.name ?? ''),
backgroundColor: AppColor.getActivityTypeBgColor(requestDetailProvider.engineerUpdateWorkOrderHelperModel!.serviceType?.name ?? ''),
),
],
),
"edit_icon".toSvgAsset(height: 21, width: 21).onPress(() async{
requestDetailProvider.refreshTimer = false;
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => VerifyAssetDetails(
isEdit: true,
)));
requestDetailProvider.refreshTimer = true;
}),
//hide if status is closed or complete .
if (!requestDetailProvider.isReadOnlyRequest)
"edit_icon".toSvgAsset(height: 21, width: 21).onPress(() async {
requestDetailProvider.refreshTimer = false;
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => VerifyAssetDetails(
isEdit: true,
)));
requestDetailProvider.refreshTimer = true;
}),
]),
6.height,
Text(
context.translation.assetSituation,
"Work Order Details",
style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
),
Text(

@ -704,7 +704,7 @@ class ServiceRequestBottomSheet {
);
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => const MaintenanceRequestForm()),
MaterialPageRoute(builder: (context) => MaintenanceRequestForm()),
);
break;
}
@ -837,14 +837,14 @@ class ServiceRequestBottomSheet {
}
static bool validateAssetSituation(ServiceRequestDetailProvider requestDetailProvider) {
if (requestDetailProvider.engineerUpdateWorkOrderHelperModel!.equipmentStatus != null) {
if (requestDetailProvider.engineerUpdateWorkOrderHelperModel!.equipmentStatus!.value == 1 || requestDetailProvider.engineerUpdateWorkOrderHelperModel!.equipmentStatus!.value == 2) {
if (requestDetailProvider.engineerUpdateWorkOrderHelperModel!.returnToService == null) {
Fluttertoast.showToast(msg: "Return to service is required ", toastLength: Toast.LENGTH_LONG);
return false;
}
}
}
// if (requestDetailProvider.engineerUpdateWorkOrderHelperModel!.equipmentStatus != null) {
// if (requestDetailProvider.engineerUpdateWorkOrderHelperModel!.equipmentStatus!.value == 1 || requestDetailProvider.engineerUpdateWorkOrderHelperModel!.equipmentStatus!.value == 2) {
// if (requestDetailProvider.engineerUpdateWorkOrderHelperModel!.returnToService == null) {
// Fluttertoast.showToast(msg: "Return to service is required ", toastLength: Toast.LENGTH_LONG);
// return false;
// }
// }
// }
return true;
}

@ -1,3 +1,5 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/api_routes/urls.dart';
@ -19,13 +21,28 @@ import 'package:test_sa/service_request_latest/views/components/asset_detail_car
import 'package:test_sa/service_request_latest/views/components/initial_visit_card.dart';
import 'package:test_sa/service_request_latest/views/components/timer_widget.dart';
import 'package:test_sa/service_request_latest/views/forms/asset_retired/asset_retired.dart';
import 'package:test_sa/views/widgets/images/files_list.dart';
import 'package:test_sa/views/widgets/images/multi_image_picker.dart';
import 'package:test_sa/views/widgets/loaders/no_data_found.dart';
import 'package:test_sa/views/widgets/requests/request_status.dart';
import 'package:test_sa/views/widgets/sound/sound_player.dart';
class ServiceRequestDetailView extends StatelessWidget {
const ServiceRequestDetailView({Key? key}) : super(key: key);
class ServiceRequestDetailView extends StatefulWidget {
ServiceRequestDetailView({Key? key}) : super(key: key);
@override
State<ServiceRequestDetailView> createState() => _ServiceRequestDetailViewState();
}
class _ServiceRequestDetailViewState extends State<ServiceRequestDetailView> {
List<File> _workOrderAttachments = [];
@override
void initState() {
ServiceRequestDetailProvider requestDetailProvider = Provider.of<ServiceRequestDetailProvider>(context, listen: false);
_workOrderAttachments = requestDetailProvider.currentWorkOrder?.data?.workOrderAttachments.map((e) => File(e.name ?? '')).toList() ?? [];
// _workOrderAttachments = requestDetailProvider.currentWorkOrder?.data?.workOrderAttachments.map((e) => AttachmentModel(e.id??0, File(e.name ?? ''))).toList() ?? [];
super.initState();
}
@override
Widget build(BuildContext context) {
@ -45,31 +62,34 @@ class ServiceRequestDetailView extends StatelessWidget {
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
workOrderDetailCard(context, requestProvider.currentWorkOrder!.data!, _userProvider),
workOrderDetailCard(context, requestProvider.currentWorkOrder!.data!, _userProvider, requestProvider),
initialVisitCard(requestDetailProvider: requestProvider, userProvider: _userProvider),
assetDetailCard(requestDetailProvider: requestProvider, userProvider: _userProvider),
12.height,
contactInfoCard(context, requestProvider.currentWorkOrder!.data!),
20.height,
],
),
).expanded,
FooterActionButton.requestDetailsFooterWidget(
workOrderNextStepStatus: requestProvider.currentWorkOrder!.data!.nextStep!.workOrderNextStepEnum!,
// workOrderNextStepStatus: WorkOrderNextStepEnum.eNeedVisit,
status: requestProvider.currentWorkOrder?.data?.status,
isEmpIsAssigned: requestProvider.currentWorkOrder!.data!.assignedEmployee != null,
activities: requestProvider.currentWorkOrder!.data?.activities ?? [],
userProvider: _userProvider,
context: context),
],
),
if (requestProvider.timer != null && requestProvider.timer!.isActive) ...[
const TimerWidget(),
]
//no need to show timer as discussed with backend
// if (requestProvider.timer != null && requestProvider.timer!.isActive) ...[
// const TimerWidget(),
// ]
],
);
});
}
Widget workOrderDetailCard(BuildContext context, WorkOrderData workOrder, UserProvider userProvider) {
Widget workOrderDetailCard(BuildContext context, WorkOrderData workOrder, UserProvider userProvider, ServiceRequestDetailProvider requestProvider) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -100,6 +120,15 @@ class ServiceRequestDetailView extends StatelessWidget {
textColor: AppColor.getHistoryLogStatusTextColorByName(workOrder.status!.name!),
backgroundColor: AppColor.getHistoryLogStatusColorByName(workOrder.status!.name!),
),
if (workOrder.since != null) ...[
8.width,
StatusLabel(
radius: 4,
label: '${workOrder.since} days',
textColor: AppColor.neutral50,
backgroundColor: AppColor.orange30,
),
],
1.width.expanded,
Column(
crossAxisAlignment: CrossAxisAlignment.end,
@ -191,9 +220,18 @@ class ServiceRequestDetailView extends StatelessWidget {
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
Text(
'Date/Time: ${workOrder.requestedDate!.toString().toServiceRequestDetailsFormat}',
'Requested Date: ${workOrder.requestedDate!.toString().toServiceRequestDetailsFormat}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120),
),
Text(
'${context.translation.arrivedDate}: ${workOrder.iHaveArrivedDate != null ? workOrder.iHaveArrivedDate.toString().toServiceRequestDetailsFormat : '-'}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120),
),
Text(
'${context.translation.closedDate}: ${workOrder.closedDate != null ? workOrder.closedDate!.toString().toServiceRequestDetailsFormat : '-'}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120),
),
const Divider().defaultStyle(context),
//... call response details starts here....
@ -215,13 +253,40 @@ class ServiceRequestDetailView extends StatelessWidget {
'${context.translation.activityStatus}: ${workOrder.lastActivityStatus?.name ?? "-"}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
Text(
'${context.translation.callResponse}: ${workOrder.callResponse ?? "-"}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
// Text(
// '${context.translation.since}: ${workOrder.since != null ? '${workOrder.since} days' : '-'}',
// style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
// ),
8.height,
if (workOrder.rejectReason != null) ...[
const Divider().defaultStyle(context),
8.height,
Text(
context.translation.rejectionDetails,
style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
),
8.height,
Text(
'${context.translation.rejectionReason}: ${workOrder.rejectReason?.name ?? '-'}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
8.height,
Text(
'${context.translation.comment}: ${workOrder.rejectComment ?? '-'}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
],
8.height,
if ((workOrder.comments ?? "").isNotEmpty) ...[
const Divider().defaultStyle(context),
8.height,
Text(
"Call Comment",
context.translation.callComments,
style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
),
8.height,
@ -230,11 +295,23 @@ class ServiceRequestDetailView extends StatelessWidget {
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
],
if (workOrder.workOrderAttachments.isNotEmpty ?? false) ...[
if (!requestProvider.isReadOnlyRequest) ...[
8.height,
const Divider().defaultStyle(context),
FilesList(images: workOrder.workOrderAttachments.map((toElement) => URLs.getFileUrl(toElement.name ?? '') ?? '').toList()),
MultiFilesPicker(
label: context.translation.attachments,
files: _workOrderAttachments,
// attachment: _workOrderAttachments,
buttonColor: AppColor.primary10,
onlyImages: false,
buttonIcon: 'quotation_icon'.toSvgAsset(color: AppColor.primary10),
onChange: (attachment) {
requestProvider.addWorkOrderAttachment(woId: workOrder.requestId!, attachments: _workOrderAttachments);
},
),
],
if (workOrder.voiceNote?.isNotEmpty ?? false) ...[
const Divider().defaultStyle(context),
16.height,
@ -308,6 +385,55 @@ class ServiceRequestDetailView extends StatelessWidget {
).toShadowContainer(context, padding: 0);
}
Widget contactInfoCard(BuildContext context, WorkOrderData workOrder) {
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Contact Info",
style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
),
8.height,
ListView.separated(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
padding: EdgeInsets.zero,
itemBuilder: (cxt, index) => Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'${workOrder.workOrderContactPerson[index].name ?? '-'}',
style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
),
Text(
'${context.translation.employeeId}: ${workOrder.workOrderContactPerson[index].employeeId ?? '-'}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
Text(
'${context.translation.telephone}: ${workOrder.workOrderContactPerson[index].mobilePhone ?? '-'}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
Text(
'Job: ${workOrder.workOrderContactPerson[index].position ?? '-'}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
Text(
'${context.translation.email}: ${workOrder.workOrderContactPerson[index].email ?? '-'}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
Text(
'Extension: ${workOrder.workOrderContactPerson[index].extension ?? '-'}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
],
),
separatorBuilder: (cxt, index) => const Divider().defaultStyle(context),
itemCount: workOrder.workOrderContactPerson.length),
],
).toShadowContainer(context, padding: 16);
}
Widget assetRetiredButton({required BuildContext context}) {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 16.toScreenHeight, vertical: 12.toScreenWidth),
@ -347,7 +473,8 @@ class ServiceRequestDetailView extends StatelessWidget {
}
Widget assetDetailCard({required ServiceRequestDetailProvider requestDetailProvider, required UserProvider userProvider}) {
if (userProvider.user?.type == UsersTypes.engineer && requestDetailProvider.currentWorkOrder?.data?.nextStep!.workOrderNextStepEnum == WorkOrderNextStepEnum.activity) {
if ((userProvider.user?.type == UsersTypes.engineer && requestDetailProvider.currentWorkOrder?.data?.nextStep!.workOrderNextStepEnum == WorkOrderNextStepEnum.activity) ||
requestDetailProvider.isReadOnlyRequest) {
WorkOrderData currentWorkOrderData = requestDetailProvider.currentWorkOrder!.data!;
requestDetailProvider.engineerUpdateWorkOrderHelperModel = EngineerUpdateWorkOrderHelperModel(
workOrderId: currentWorkOrderData.requestId,

@ -1,7 +1,6 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
@ -14,6 +13,7 @@ import 'package:test_sa/models/new_models/work_order_detail_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_lazy_loading.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/loading_list_notifier.dart';
import 'package:test_sa/providers/service_request_providers/equipment_status_provider.dart';
@ -75,6 +75,7 @@ class _VerifyAssetDetailsState extends State<VerifyAssetDetails> with TickerProv
solution: currentWorkOrderData.faultDescription?.workPerformed,
returnToService: currentWorkOrderData.returnToService,
serviceType: currentWorkOrderData.serviceType,
callResponse: currentWorkOrderData.callResponse,
);
if (currentWorkOrderData.assetLoan != null) {
loanAvailabilityAsset = Asset(
@ -215,12 +216,27 @@ class _VerifyAssetDetailsState extends State<VerifyAssetDetails> with TickerProv
}
},
),
12.height,
context.translation.solutions.heading6(context).custom(color: AppColor.neutral50),
if (requestDetailProvider.engineerUpdateWorkOrderHelperModel?.solution != null) ...[
12.height,
context.translation.solutions.heading6(context).custom(color: AppColor.neutral50),
8.height,
requestDetailProvider.engineerUpdateWorkOrderHelperModel?.solution != null
? requestDetailProvider.engineerUpdateWorkOrderHelperModel!.solution!.bodyText2(context).custom(color: AppColor.neutral120,align: TextAlign.justify)
: const SizedBox(),
],
8.height,
requestDetailProvider.engineerUpdateWorkOrderHelperModel?.solution != null
? requestDetailProvider.engineerUpdateWorkOrderHelperModel!.solution!.bodyText2(context).custom(color: AppColor.neutral120)
: const SizedBox(),
AppTextFormField(
labelText: context.translation.callResponse,
backgroundColor: AppColor.neutral100,
initialValue: requestDetailProvider.engineerUpdateWorkOrderHelperModel?.callResponse,
textAlign: TextAlign.center,
labelStyle: AppTextStyles.textFieldLabelStyle,
showShadow: false,
onChange: (value){
requestDetailProvider.engineerUpdateWorkOrderHelperModel?.callResponse = value;
},
style: Theme.of(context).textTheme.titleMedium,
),
],
).toShadowContainer(context).paddingAll(16),
).expanded,

@ -39,6 +39,11 @@ class _AssistantEmployeeCardState extends State<AssistantEmployeeCard> {
Future<void> getInitialData() async {
final user = Provider.of<UserProvider>(context, listen: false).user!;
ServiceRequestDetailProvider requestDetailProvider = Provider.of<ServiceRequestDetailProvider>(context, listen: false);
if( requestDetailProvider.isReadOnlyRequest){
isExpanded = true;
setState(() {
});
}
isCurrentUserIsAssistantEmp = (user.userID != requestDetailProvider.currentWorkOrder?.data?.assignedEmployee?.userId);
// if (isCurrentUserIsAssistantEmp) {
@ -122,7 +127,7 @@ class _AssistantEmployeeCardState extends State<AssistantEmployeeCard> {
requestDetailProvider.updateActivityMaintenanceHelperModel(requestDetailProvider.activityMaintenanceHelperModel);
ServiceRequestUtils.calculateAndAssignWorkingHours(
startTime: requestDetailProvider.activityMaintenanceHelperModel?.modelAssistantEmployees?.startDate,
endTime: requestDetailProvider.activityMaintenanceHelperModel?.modelAssistantEmployees?.startDate,
endTime: requestDetailProvider.activityMaintenanceHelperModel?.modelAssistantEmployees?.endDate,
workingHoursController: _workingHoursController,
updateModel: (hours){
requestDetailProvider.activityMaintenanceHelperModel!.modelAssistantEmployees!.workingHours=hours;

@ -0,0 +1,546 @@
// // import 'package:flutter/material.dart';
// // import 'package:fluttertoast/fluttertoast.dart';
// // import 'package:provider/provider.dart';
// // import 'package:test_sa/controllers/providers/api/user_provider.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/lookup.dart';
// // import 'package:test_sa/models/plan_preventive_visit/plan_preventive_visit_model.dart';
// // import 'package:test_sa/models/ppm/ppm_calibration_tools.dart';
// // import 'package:test_sa/models/service_request/supplier_details.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/loading_list_notifier.dart';
// // import 'package:test_sa/providers/ppm_service_provider.dart';
// // import 'package:test_sa/providers/work_order/vendor_provider.dart';
// // import 'package:test_sa/service_request_latest/utilities/service_request_utils.dart';
// // import 'package:test_sa/views/widgets/pentry/calibration_tool_asset_picker.dart';
// //
// // import '../../../../../new_views/app_style/app_color.dart';
// // import '../../../../widgets/date_and_time/date_picker.dart';
// //
// // class AssistantEmployeeList extends StatefulWidget {
// // final List<PreventiveVisitSuppliers>? models;
// //
// // const AssistantEmployeeList({Key? key, this.models = const <PreventiveVisitSuppliers>[]}) : super(key: key);
// //
// // @override
// // State<AssistantEmployeeList> createState() => _AssistantEmployeeListState();
// // }
// //
// // class _AssistantEmployeeListState extends State<AssistantEmployeeList> {
// // final TextEditingController _workingHoursController = TextEditingController();
// //
// // @override
// // Widget build(BuildContext context) {
// // return ListView.builder(
// // itemCount: widget.models!.length + 1,
// // padding: const EdgeInsets.only(left: 16, right: 16, top: 8, bottom: 16),
// // itemBuilder: (context, index) {
// // if (index == widget.models!.length) {
// // return AppFilledButton(
// // label: "Add More External Details".addTranslation,
// // maxWidth: true,
// // textColor: AppColor.black10,
// // buttonColor: context.isDark ? AppColor.neutral60 : AppColor.white10,
// // icon: Icon(Icons.add_circle, color: AppColor.blueStatus(context)),
// // showIcon: true,
// // onPressed: () async {
// // // if (widget.models?.isNotEmpty ?? false) {
// // // if (widget.models!.last.assetId == null) {
// // // await Fluttertoast.showToast(msg: "${context.translation.youHaveToSelect} ${context.translation.assetNumber}");
// // // return;
// // // }
// // // if (widget.models!.last.calibrationDateOfTesters == null) {
// // // await Fluttertoast.showToast(msg: "${context.translation.youHaveToSelect} ${context.translation.date}");
// // // return;
// // // }
// // // }
// // // widget.models!.add(PpmCalibrationTools(id: 0));
// // // setState(() {});
// // },
// // );
// // }
// // final model = widget.models![index];
// // // _workingHoursController.text = model.workingHours != null ? model.workingHours.toString() : '';
// // return Container(
// // padding: const EdgeInsets.all(16),
// // margin: EdgeInsets.only(bottom: 16.toScreenHeight),
// // decoration: BoxDecoration(
// // color: AppColor.background(context),
// // borderRadius: BorderRadius.circular(20),
// // boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.03), blurRadius: 14)],
// // ),
// // child: Column(
// // crossAxisAlignment: CrossAxisAlignment.start,
// // children: [
// // Row(
// // mainAxisAlignment: MainAxisAlignment.spaceBetween,
// // children: [
// // (index == 0 ? "1 /4 . External Details" : "").heading5(context),
// // "trash".toSvgAsset(height: 20, width: 15).onPress(() {
// // widget.models!.remove(model);
// //
// // setState(() {});
// // }),
// // ],
// // ),
// // 16.height,
// // SingleItemDropDownMenu<SupplierDetails, VendorProvider>(
// // context: context,
// // title: context.translation.supplier,
// // initialValue: model.supplier,
// // backgroundColor: AppColor.neutral100,
// // showAsBottomSheet: true,
// // onSelect: (supplier) {
// // if (supplier != null) {
// // model.supplier = supplier;
// // print('supplier dtails is ${supplier.toJson()}');
// // setState(() {});
// // }
// // },
// // ),
// // 8.height,
// // SingleItemDropDownMenu<SuppPersons, NullableLoadingProvider>(
// // context: context,
// // title: context.translation.supplierEngineer,
// // enabled: model.suppPerson != null,
// // backgroundColor: AppColor.neutral100,
// // initialValue: model.suppPerson,
// // staticData: model.supplier?.suppPersons,
// // showAsBottomSheet: true,
// // onSelect: (suppPerson) {
// // if (suppPerson != null) {
// // model.suppPerson = suppPerson;
// // print('supply person is ${model.suppPerson?.toJson()}');
// // }
// // },
// // ),
// // 8.height,
// // AppTextFormField(
// // labelText: "Telephone",
// // initialValue: model.supplier?.telephones != null && model.supplier!.telephones!.isNotEmpty ? (model.supplier?.telephones?[0].telephone ?? "").toString() : '',
// // textAlign: TextAlign.center,
// // backgroundColor: AppColor.neutral100,
// // style: Theme.of(context).textTheme.titleMedium,
// // textInputType: TextInputType.number,
// // onChange: (value) {
// // model.supplier?.telephones?[0].telephone = value;
// // },
// // ),
// // 8.height,
// // Row(
// // mainAxisSize: MainAxisSize.min,
// // children: [
// // ADatePicker(
// // label: context.translation.startTime,
// // hideShadow: true,
// // backgroundColor: AppColor.neutral100,
// // date: model.startDateTime,
// // formatDateWithTime: true,
// // onDatePicker: (selectedDate) {
// // showTimePicker(
// // context: context,
// // initialTime: TimeOfDay.now(),
// // ).then((selectedTime) {
// // // Handle the selected date and time here.
// // if (selectedTime != null) {
// // DateTime selectedDateTime = DateTime(
// // selectedDate.year,
// // selectedDate.month,
// // selectedDate.day,
// // selectedTime.hour,
// // selectedTime.minute,
// // );
// // setState(() {
// // model.startDateTime = selectedDateTime;
// // });
// // model.endDateTime = null;
// // _workingHoursController.clear();
// // ServiceRequestUtils.calculateAndAssignWorkingHours(
// // startTime: model.startDateTime,
// // endTime: model.endDateTime,
// // workingHoursController: _workingHoursController,
// // updateModel: (hours) {
// // model.workingHours = hours;
// // },
// // );
// // }
// // });
// // },
// // ).expanded,
// // 8.width,
// // ADatePicker(
// // label: context.translation.endTime,
// // hideShadow: true,
// // backgroundColor: AppColor.neutral100,
// // date: model.endDateTime,
// // formatDateWithTime: true,
// // onDatePicker: (selectedDate) {
// // showTimePicker(
// // context: context,
// // initialTime: TimeOfDay.now(),
// // ).then((selectedTime) {
// // // Handle the selected date and time here.
// // if (selectedTime != null) {
// // DateTime selectedDateTime = DateTime(
// // selectedDate.year,
// // selectedDate.month,
// // selectedDate.day,
// // selectedTime.hour,
// // selectedTime.minute,
// // );
// // if (model.startDateTime != null && selectedDateTime.isBefore(model.startDateTime!)) {
// // "End Date time must be greater then start date".showToast;
// // return;
// // }
// // model.endDateTime = selectedDateTime;
// // setState(() {});
// // ServiceRequestUtils.calculateAndAssignWorkingHours(
// // startTime: model.startDateTime,
// // endTime: model.endDateTime,
// // workingHoursController: _workingHoursController,
// // updateModel: (hours) {
// // model.workingHours = hours;
// // },
// // );
// // }
// // });
// // },
// // ).expanded,
// // ],
// // ),
// // 8.height,
// // AppTextFormField(
// // labelText: context.translation.workingHours,
// // backgroundColor: AppColor.neutral80,
// // controller: _workingHoursController,
// // suffixIcon: "clock".toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null).paddingOnly(end: 16),
// // // initialValue: model.workingHours != null ? model.workingHours.toString() : '',
// // textAlign: TextAlign.center,
// // labelStyle: AppTextStyles.textFieldLabelStyle,
// // enable: false,
// // showShadow: false,
// // style: Theme.of(context).textTheme.titleMedium,
// // ),
// // 8.height,
// // ],
// // ),
// // );
// // },
// // );
// // }
// // }
//
// import 'package:flutter/material.dart';
// import 'package:provider/provider.dart';
// import 'package:test_sa/controllers/providers/api/ppm_provider.dart';
// import 'package:test_sa/controllers/providers/api/user_provider.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/new_models/assistant_employee.dart';
// import 'package:test_sa/models/new_models/work_order_detail_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/service_request_latest/service_request_detail_provider.dart';
// import 'package:test_sa/service_request_latest/utilities/service_request_utils.dart';
// import 'package:test_sa/views/widgets/date_and_time/date_picker.dart';
// import 'package:test_sa/views/widgets/status/report/service_report_assistant_employee_menu.dart';
//
// class AssistantEmployeeList extends StatefulWidget {
// final List<ActivityMaintenanceAssistantEmployees>? models;
//
// const AssistantEmployeeList({Key? key, this.models = const <ActivityMaintenanceAssistantEmployees>[]}) : super(key: key);
//
// @override
// State<AssistantEmployeeList> createState() => _AssistantEmployeeListState();
// }
//
// class _AssistantEmployeeListState extends State<AssistantEmployeeList> {
// bool isLoading = false;
//
// //TODO add loader when adding or deleting item..
//
// void _addNewEntry() {
// setState(() {
// // isLoading = true;
// widget.models!.add(ActivityMaintenanceAssistantEmployees());
// // Future.delayed(Duration(seconds: 1)).whenComplete(() {
// // setState(() {
// // isLoading = false;
// // });
// // });
// });
// }
//
// void _removeEntry(int index) {
// setState(() {
// isLoading = true;
// widget.models!.removeAt(index);
// // isLoading = false;
// });
// }
//
// @override
// Widget build(BuildContext context) {
// final ppmProvider = Provider.of<PpmProvider>(context, listen: false);
// return ListView.builder(
// itemCount: widget.models!.length + 1,
// padding: const EdgeInsets.all(16),
// itemBuilder: (context, index) {
// if (index == widget.models!.length) {
// return Visibility(
// visible: !ppmProvider.isReadOnly,
// child: AppFilledButton(
// label: "Add More Assistant Employees".addTranslation,
// maxWidth: true,
// textColor: AppColor.black10,
// buttonColor: context.isDark ? AppColor.neutral60 : AppColor.white10,
// icon: Icon(Icons.add_circle, color: AppColor.blueStatus(context)),
// showIcon: true,
// onPressed: _addNewEntry,
// ),
// );
// }
// // return !isLoading
// // ?
// return AssistantEmployeeItem(
// model: widget.models![index],
// // index: index,
// // onRemove: () => _removeEntry(index),
// );
// // : const ALoading();
// },
// );
// }
// }
// class AssistantEmployeeItem extends StatefulWidget {
// final ActivityMaintenanceAssistantEmployees model;
// const AssistantEmployeeItem({required this.model,super.key});
//
// @override
// State<AssistantEmployeeItem> createState() => _AssistantEmployeeItemState();
// }
//
// class _AssistantEmployeeItemState extends State<AssistantEmployeeItem> {
// bool status = false;
// final TextEditingController _workingHoursController = TextEditingController(text: '');
// bool isCurrentUserIsAssistantEmp = false;
// bool isExpanded = false;
//
// @override
// void initState() {
// // TODO: implement initState
// WidgetsBinding.instance.addPostFrameCallback((_) {
// getInitialData();
// });
// super.initState();
// }
//
// Future<void> getInitialData() async {
// final user = Provider.of<UserProvider>(context, listen: false).user!;
// ServiceRequestDetailProvider requestDetailProvider = Provider.of<ServiceRequestDetailProvider>(context, listen: false);
// if( requestDetailProvider.isReadOnlyRequest){
// isExpanded = true;
// setState(() {
// });
// }
// isCurrentUserIsAssistantEmp = (user.userID != requestDetailProvider.currentWorkOrder?.data?.assignedEmployee?.userId);
//
// // if (isCurrentUserIsAssistantEmp) {
// // // _subWorkOrders.assistantEmployees = [widget.workOrder.assistantEmployees?.first?.copyWith(id: 0)];
// // }
// }
//
// @override
// void dispose() {
// // TODO: implement dispose
// _workingHoursController.dispose();
// super.dispose();
// }
//
// @override
// Widget build(BuildContext context) {
// return Consumer<ServiceRequestDetailProvider>(builder: (context, requestDetailProvider, child) {
// return Column(
// children: [
// SizedBox(
// height: 56.toScreenHeight,
// child: Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// context.translation.assistantEmployee.bodyText(context).custom(color: AppColor.black20),
// Icon(isExpanded ? Icons.arrow_drop_up_outlined : Icons.arrow_drop_down),
// ],
// ),
// ).onPress(() {
// setState(() {
// isExpanded = !isExpanded;
// });
// }),
// isExpanded
// ? Column(
// crossAxisAlignment: CrossAxisAlignment.stretch,
// children: [
// ServiceReportAssistantEmployeeMenu(
// title: context.translation.select,
// backgroundColor: AppColor.neutral100,
// assetId: requestDetailProvider.currentWorkOrder!.data!.asset!.id!,
// initialValue: widget.model.,
// onSelect: (employee) {
// if (employee == null) {
// requestDetailProvider.activityMaintenanceHelperModel?.assistantEmployees = [];
// } else {
// widget.model = [employee.copyWith(id: 0)];
// // requestDetailProvider.activityMaintenanceHelperModel?.modelAssistantEmployees?.user = AssignedEmployee(userId: employee.user?.id, userName: employee.user?.name);
// }
// },
// ),
// 8.height,
// Row(
// mainAxisSize: MainAxisSize.min,
// children: [
// ADatePicker(
// label: context.translation.startTime,
// hideShadow: true,
// backgroundColor: AppColor.neutral100,
// date: requestDetailProvider.activityMaintenanceHelperModel?.modelAssistantEmployees?.startDate,
// formatDateWithTime: true,
// onDatePicker: (selectedDate) {
// showTimePicker(
// context: context,
// initialTime: TimeOfDay.now(),
// ).then((selectedTime) {
// // Handle the selected date and time here.
// if (selectedTime != null) {
// DateTime selectedDateTime = DateTime(
// selectedDate.year,
// selectedDate.month,
// selectedDate.day,
// selectedTime.hour,
// selectedTime.minute,
// );
// requestDetailProvider.activityMaintenanceHelperModel?.modelAssistantEmployees?.startDate = selectedDateTime;
// requestDetailProvider.updateActivityMaintenanceHelperModel(requestDetailProvider.activityMaintenanceHelperModel);
// ServiceRequestUtils.calculateAndAssignWorkingHours(
// startTime: requestDetailProvider.activityMaintenanceHelperModel?.modelAssistantEmployees?.startDate,
// endTime: requestDetailProvider.activityMaintenanceHelperModel?.modelAssistantEmployees?.startDate,
// workingHoursController: _workingHoursController,
// updateModel: (hours){
// requestDetailProvider.activityMaintenanceHelperModel!.modelAssistantEmployees!.workingHours=hours;
// });
// }
// });
// },
// ).expanded,
// 8.width,
// ADatePicker(
// label: context.translation.endTime,
// hideShadow: true,
// backgroundColor: AppColor.neutral100,
// date: requestDetailProvider.activityMaintenanceHelperModel?.modelAssistantEmployees?.endDate,
// formatDateWithTime: true,
// onDatePicker: (selectedDate) {
// showTimePicker(
// context: context,
// initialTime: TimeOfDay.now(),
// ).then((selectedTime) {
// // Handle the selected date and time here.
// if (selectedTime != null) {
// DateTime selectedDateTime = DateTime(
// selectedDate.year,
// selectedDate.month,
// selectedDate.day,
// selectedTime.hour,
// selectedTime.minute,
// );
// if (requestDetailProvider.activityMaintenanceHelperModel?.modelAssistantEmployees?.startDate != null &&
// selectedDateTime.isBefore(requestDetailProvider.activityMaintenanceHelperModel!.modelAssistantEmployees!.startDate!)) {
// "End Date time must be greater then start date".showToast;
// return;
// }
// requestDetailProvider.activityMaintenanceHelperModel?.modelAssistantEmployees?.endDate = selectedDateTime;
// requestDetailProvider.updateActivityMaintenanceHelperModel(requestDetailProvider.activityMaintenanceHelperModel);
// ServiceRequestUtils.calculateAndAssignWorkingHours(
// startTime: requestDetailProvider.activityMaintenanceHelperModel?.modelAssistantEmployees?.startDate,
// endTime: requestDetailProvider.activityMaintenanceHelperModel?.modelAssistantEmployees?.endDate,
// workingHoursController: _workingHoursController,
// updateModel: (hours){
// requestDetailProvider.activityMaintenanceHelperModel!.modelAssistantEmployees!.workingHours=hours;
// });
// }
// });
// },
// ).expanded,
// ],
// ),
// 8.height,
// AppTextFormField(
// labelText: context.translation.workingHours,
// backgroundColor: AppColor.neutral80,
// controller: _workingHoursController,
// suffixIcon: "clock".toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null).paddingOnly(end: 16),
// initialValue: requestDetailProvider.activityMaintenanceHelperModel?.modelAssistantEmployees?.workingHours != null
// ? requestDetailProvider.activityMaintenanceHelperModel!.modelAssistantEmployees!.workingHours.toString()
// : '',
// textAlign: TextAlign.center,
// labelStyle: AppTextStyles.textFieldLabelStyle,
// enable: false,
// showShadow: false,
// style: Theme.of(context).textTheme.titleMedium,
// ),
// 8.height,
// AppTextFormField(
// initialValue: requestDetailProvider.activityMaintenanceHelperModel?.modelAssistantEmployees?.technicalComment,
// labelText: context.translation.technicalComment,
// backgroundColor: AppColor.neutral100,
// showShadow: false,
// labelStyle: AppTextStyles.textFieldLabelStyle,
// alignLabelWithHint: true,
// textInputType: TextInputType.multiline,
// onChange: (value) {
// requestDetailProvider.activityMaintenanceHelperModel?.modelAssistantEmployees?.technicalComment = value;
// },
// onSaved: (value) {
// requestDetailProvider.activityMaintenanceHelperModel?.modelAssistantEmployees?.technicalComment = value;
// },
// ),
// 8.height,
// ],
// )
// : const SizedBox(),
// ],
// );
// });
// }
//
// // //TODO move this to some common place....@waseem
// // double calculateWorkingHours(DateTime? startTime, DateTime? endTime) {
// // if (startTime != null && endTime != null) {
// // Duration difference = endTime.difference(startTime);
// // int hours = difference.inHours;
// // int minutes = difference.inMinutes % 60;
// // return hours.toDouble();
// // } else {
// // return -1;
// // }
// // }
// //
// // assignWorkingHours({required RequestDetailProvider requestDetailProvider}) {
// // double hours = calculateWorkingHours(
// // requestDetailProvider.activityMaintenanceHelperModel?.modelAssistantEmployees?.startDate, requestDetailProvider.activityMaintenanceHelperModel?.modelAssistantEmployees?.endDate);
// // if (hours != -1) {
// // _workingHoursController.text = hours.toString();
// // requestDetailProvider.activityMaintenanceHelperModel?.modelAssistantEmployees?.workingHours = hours;
// // }
// // }
// }
//

@ -42,198 +42,198 @@ class _ExternalMaintenanceRequestState extends State<ExternalMaintenanceRequest>
ServiceRequestDetailProvider requestDetailProvider = Provider.of<ServiceRequestDetailProvider>(context, listen: false);
_workingHoursController.text =
requestDetailProvider.activityMaintenanceHelperModel?.supplierWorkingHour != null ? requestDetailProvider.activityMaintenanceHelperModel!.supplierWorkingHour.toString() : '';
}
@override
Widget build(BuildContext context) {
return Consumer<ServiceRequestDetailProvider>(builder: (context, ServiceRequestDetailProvider requestDetailProvider, child) {
return Column(
children: [
Form(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SingleItemDropDownMenu<SupplierDetails, VendorProvider>(
context: context,
title: context.translation.supplier,
backgroundColor: AppColor.neutral100,
initialValue: requestDetailProvider.activityMaintenanceHelperModel?.supplier,
showAsBottomSheet: true,
onSelect: (supplier) {
if (supplier != null) {
requestDetailProvider.activityMaintenanceHelperModel?.supplier = supplier;
// _subWorkOrders.supplier = supplier;
// log(_subWorkOrders.supplier?.suppPersons?.map((e) => e.personName)?.toString());
setState(() {});
}
},
),
8.height,
Row(
children: [
SingleItemDropDownMenu<SuppPersons, NullableLoadingProvider>(
context: context,
backgroundColor: requestDetailProvider.activityMaintenanceHelperModel?.supplier?.suppliername == null ? AppColor.neutral40 : AppColor.neutral100,
title: context.translation.supplierEngineer,
enabled: requestDetailProvider.activityMaintenanceHelperModel?.supplier?.suppPersons?.isNotEmpty ?? false,
staticData: requestDetailProvider.activityMaintenanceHelperModel?.supplier?.suppPersons,
showAsBottomSheet: true,
initialValue: requestDetailProvider.activityMaintenanceHelperModel?.supEngineer == null
? null
: SuppPersons.fromJson(requestDetailProvider.activityMaintenanceHelperModel?.supEngineer?.toJson()),
onSelect: (suppPerson) {
print(suppPerson?.toJson());
if (suppPerson != null) {
requestDetailProvider.activityMaintenanceHelperModel?.supEngineer = SuppEngineerWorkOrders.fromJson(suppPerson.toJson());
requestDetailProvider.updateActivityMaintenanceHelperModel(requestDetailProvider.activityMaintenanceHelperModel);
// engineer = SuppEngineerWorkOrders(
// id: suppPerson?.supplierId,
// supplierContactId: suppPerson?.id,
// personName: suppPerson?.personName,
// contact: suppPerson?.contact,
// externalEngCode: suppPerson?.externalEngCode,
// email: suppPerson?.email,
// );
setState(() {});
}
},
).expanded,
8.width,
Container(
height: 56.toScreenHeight,
width: 60.toScreenWidth,
decoration: BoxDecoration(
color: requestDetailProvider.activityMaintenanceHelperModel?.supplier?.suppliername == null ? AppColor.neutral40 : AppColor.neutral100,
borderRadius: BorderRadius.circular(10),
boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)],
),
child: Icon(
Icons.add,
color: context.isDark ? null : AppColor.neutral60,
),
).onPress(requestDetailProvider.activityMaintenanceHelperModel?.supplier?.suppliername == null
? null
: () async {
SuppEngineerWorkOrders suppEngineer = (await showModalBottomSheet(
context: context,
useSafeArea: true,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (context) => AddSupplierEngineerBottomSheet(requestDetailProvider.activityMaintenanceHelperModel!.supplier!.id!.toInt()),
)) as SuppEngineerWorkOrders;
requestDetailProvider.activityMaintenanceHelperModel?.supplier?.suppPersons ??= [];
requestDetailProvider.activityMaintenanceHelperModel?.supplier?.suppPersons?.add(SuppPersons.fromJson(suppEngineer.toJson()));
requestDetailProvider.activityMaintenanceHelperModel?.supEngineer = suppEngineer;
setState(() {});
}),
],
),
8.height,
Row(
mainAxisSize: MainAxisSize.min,
children: [
ADatePicker(
label: context.translation.startTime,
hideShadow: true,
backgroundColor: AppColor.neutral100,
date: requestDetailProvider.activityMaintenanceHelperModel?.supplierStartTime,
formatDateWithTime: true,
onDatePicker: (selectedDate) {
showTimePicker(
context: context,
initialTime: TimeOfDay.now(),
).then((selectedTime) {
// Handle the selected date and time here.
if (selectedTime != null) {
DateTime selectedDateTime = DateTime(
selectedDate.year,
selectedDate.month,
selectedDate.day,
selectedTime.hour,
selectedTime.minute,
);
requestDetailProvider.activityMaintenanceHelperModel?.supplierStartTime = selectedDateTime;
requestDetailProvider.activityMaintenanceHelperModel?.supplierEndTime = null;
return IgnorePointer(
ignoring: requestDetailProvider.isReadOnlyRequest,
child: Column(
children: [
Form(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SingleItemDropDownMenu<SupplierDetails, VendorProvider>(
context: context,
title: context.translation.supplier,
backgroundColor: AppColor.neutral100,
initialValue: requestDetailProvider.activityMaintenanceHelperModel?.supplier,
showAsBottomSheet: true,
onSelect: (supplier) {
if (supplier != null) {
requestDetailProvider.activityMaintenanceHelperModel?.supplier = supplier;
// _subWorkOrders.supplier = supplier;
// log(_subWorkOrders.supplier?.suppPersons?.map((e) => e.personName)?.toString());
setState(() {});
}
},
),
8.height,
Row(
children: [
SingleItemDropDownMenu<SuppPersons, NullableLoadingProvider>(
context: context,
backgroundColor: requestDetailProvider.activityMaintenanceHelperModel?.supplier?.suppliername == null ? AppColor.neutral40 : AppColor.neutral100,
title: context.translation.supplierEngineer,
enabled: requestDetailProvider.activityMaintenanceHelperModel?.supplier?.suppPersons?.isNotEmpty ?? false,
staticData: requestDetailProvider.activityMaintenanceHelperModel?.supplier?.suppPersons,
showAsBottomSheet: true,
initialValue: requestDetailProvider.activityMaintenanceHelperModel?.supEngineer == null
? null
: SuppPersons.fromJson(requestDetailProvider.activityMaintenanceHelperModel?.supEngineer?.toJson()),
onSelect: (suppPerson) {
print(suppPerson?.toJson());
if (suppPerson != null) {
requestDetailProvider.activityMaintenanceHelperModel?.supEngineer = SuppEngineerWorkOrders.fromJson(suppPerson.toJson());
requestDetailProvider.updateActivityMaintenanceHelperModel(requestDetailProvider.activityMaintenanceHelperModel);
_workingHoursController.clear();
ServiceRequestUtils.calculateAndAssignWorkingHours(
startTime: requestDetailProvider.activityMaintenanceHelperModel!.supplierStartTime,
endTime: requestDetailProvider.activityMaintenanceHelperModel!.endTime,
workingHoursController: _workingHoursController,
updateModel: (hours) {
requestDetailProvider.activityMaintenanceHelperModel?.supplierWorkingHour = hours;
},
);
// engineer = SuppEngineerWorkOrders(
// id: suppPerson?.supplierId,
// supplierContactId: suppPerson?.id,
// personName: suppPerson?.personName,
// contact: suppPerson?.contact,
// externalEngCode: suppPerson?.externalEngCode,
// email: suppPerson?.email,
// );
setState(() {});
}
});
},
).expanded,
8.width,
ADatePicker(
label: context.translation.endTime,
hideShadow: true,
backgroundColor: AppColor.neutral100,
date: requestDetailProvider.activityMaintenanceHelperModel?.supplierEndTime,
formatDateWithTime: true,
onDatePicker: (selectedDate) {
showTimePicker(
context: context,
initialTime: TimeOfDay.now(),
).then((selectedTime) {
// Handle the selected date and time here.
if (selectedTime != null) {
DateTime selectedDateTime = DateTime(
selectedDate.year,
selectedDate.month,
selectedDate.day,
selectedTime.hour,
selectedTime.minute,
);
if (requestDetailProvider.activityMaintenanceHelperModel!.supplierStartTime != null &&
selectedDateTime.isBefore(requestDetailProvider.activityMaintenanceHelperModel!.supplierStartTime!)) {
"End Date time must be greater then start date".showToast;
return;
},
).expanded,
8.width,
Container(
height: 56.toScreenHeight,
width: 60.toScreenWidth,
decoration: BoxDecoration(
color: requestDetailProvider.activityMaintenanceHelperModel?.supplier?.suppliername == null ? AppColor.neutral40 : AppColor.neutral100,
borderRadius: BorderRadius.circular(10),
boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)],
),
child: Icon(
Icons.add,
color: context.isDark ? null : AppColor.neutral60,
),
).onPress(requestDetailProvider.activityMaintenanceHelperModel?.supplier?.suppliername == null
? null
: () async {
SuppEngineerWorkOrders suppEngineer = (await showModalBottomSheet(
context: context,
useSafeArea: true,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (context) => AddSupplierEngineerBottomSheet(requestDetailProvider.activityMaintenanceHelperModel!.supplier!.id!.toInt()),
)) as SuppEngineerWorkOrders;
requestDetailProvider.activityMaintenanceHelperModel?.supplier?.suppPersons ??= [];
requestDetailProvider.activityMaintenanceHelperModel?.supplier?.suppPersons?.add(SuppPersons.fromJson(suppEngineer.toJson()));
requestDetailProvider.activityMaintenanceHelperModel?.supEngineer = suppEngineer;
setState(() {});
}),
],
),
8.height,
Row(
mainAxisSize: MainAxisSize.min,
children: [
ADatePicker(
label: context.translation.startTime,
hideShadow: true,
backgroundColor: AppColor.neutral100,
date: requestDetailProvider.activityMaintenanceHelperModel?.supplierStartTime,
formatDateWithTime: true,
onDatePicker: (selectedDate) {
showTimePicker(
context: context,
initialTime: TimeOfDay.now(),
).then((selectedTime) {
// Handle the selected date and time here.
if (selectedTime != null) {
DateTime selectedDateTime = DateTime(
selectedDate.year,
selectedDate.month,
selectedDate.day,
selectedTime.hour,
selectedTime.minute,
);
requestDetailProvider.activityMaintenanceHelperModel?.supplierStartTime = selectedDateTime;
requestDetailProvider.activityMaintenanceHelperModel?.supplierEndTime = null;
requestDetailProvider.updateActivityMaintenanceHelperModel(requestDetailProvider.activityMaintenanceHelperModel);
_workingHoursController.clear();
ServiceRequestUtils.calculateAndAssignWorkingHours(
startTime: requestDetailProvider.activityMaintenanceHelperModel!.supplierStartTime,
endTime: requestDetailProvider.activityMaintenanceHelperModel!.endTime,
workingHoursController: _workingHoursController,
updateModel: (hours) {
requestDetailProvider.activityMaintenanceHelperModel?.supplierWorkingHour = hours;
},
);
}
requestDetailProvider.activityMaintenanceHelperModel?.supplierEndTime = selectedDateTime;
requestDetailProvider.updateActivityMaintenanceHelperModel(requestDetailProvider.activityMaintenanceHelperModel);
ServiceRequestUtils.calculateAndAssignWorkingHours(
startTime: requestDetailProvider.activityMaintenanceHelperModel!.supplierStartTime,
endTime: requestDetailProvider.activityMaintenanceHelperModel!.supplierEndTime,
workingHoursController: _workingHoursController,
updateModel: (hours) {
requestDetailProvider.activityMaintenanceHelperModel?.supplierWorkingHour = hours;
},
);
}
});
},
).expanded,
],
),
8.height,
AppTextFormField(
labelText: context.translation.workingHours,
backgroundColor: AppColor.neutral80,
controller: _workingHoursController,
suffixIcon: "clock".toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null).paddingOnly(end: 16),
initialValue:
requestDetailProvider.activityMaintenanceHelperModel?.supplierWorkingHour != null ? requestDetailProvider.activityMaintenanceHelperModel?.supplierWorkingHour.toString() : '',
textAlign: TextAlign.center,
labelStyle: AppTextStyles.textFieldLabelStyle,
enable: false,
showShadow: false,
style: Theme.of(context).textTheme.titleMedium,
),
8.height,
],
),
).toShadowContainer(context).paddingOnly(start: 16, end: 16, top: 12),
],
});
},
).expanded,
8.width,
ADatePicker(
label: context.translation.endTime,
hideShadow: true,
backgroundColor: AppColor.neutral100,
date: requestDetailProvider.activityMaintenanceHelperModel?.supplierEndTime,
formatDateWithTime: true,
onDatePicker: (selectedDate) {
showTimePicker(
context: context,
initialTime: TimeOfDay.now(),
).then((selectedTime) {
// Handle the selected date and time here.
if (selectedTime != null) {
DateTime selectedDateTime = DateTime(
selectedDate.year,
selectedDate.month,
selectedDate.day,
selectedTime.hour,
selectedTime.minute,
);
if (requestDetailProvider.activityMaintenanceHelperModel!.supplierStartTime != null &&
selectedDateTime.isBefore(requestDetailProvider.activityMaintenanceHelperModel!.supplierStartTime!)) {
"End Date time must be greater then start date".showToast;
return;
}
requestDetailProvider.activityMaintenanceHelperModel?.supplierEndTime = selectedDateTime;
requestDetailProvider.updateActivityMaintenanceHelperModel(requestDetailProvider.activityMaintenanceHelperModel);
ServiceRequestUtils.calculateAndAssignWorkingHours(
startTime: requestDetailProvider.activityMaintenanceHelperModel!.supplierStartTime,
endTime: requestDetailProvider.activityMaintenanceHelperModel!.supplierEndTime,
workingHoursController: _workingHoursController,
updateModel: (hours) {
requestDetailProvider.activityMaintenanceHelperModel?.supplierWorkingHour = hours;
},
);
}
});
},
).expanded,
],
),
8.height,
AppTextFormField(
labelText: context.translation.workingHours,
backgroundColor: AppColor.neutral80,
controller: _workingHoursController,
suffixIcon: "clock".toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null).paddingOnly(end: 16),
initialValue:
requestDetailProvider.activityMaintenanceHelperModel?.supplierWorkingHour != null ? requestDetailProvider.activityMaintenanceHelperModel?.supplierWorkingHour.toString() : '',
textAlign: TextAlign.center,
labelStyle: AppTextStyles.textFieldLabelStyle,
enable: false,
showShadow: false,
style: Theme.of(context).textTheme.titleMedium,
),
8.height,
],
),
).toShadowContainer(context).paddingOnly(start: 16, end: 16, top: 12),
],
),
);
});
}
}

@ -1,3 +1,5 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_report_repair_location_provider.dart';
@ -32,6 +34,7 @@ class _InternalMaintenanceRequestState extends State<InternalMaintenanceRequest>
final TextEditingController _travellingHoursController = TextEditingController();
Lookup statusLookup = Lookup.fromJson({"id": 5619, "name": "New", "value": 1});
@override
void initState() {
_requestDetailProvider = Provider.of<ServiceRequestDetailProvider>(context, listen: false);
@ -53,8 +56,6 @@ class _InternalMaintenanceRequestState extends State<InternalMaintenanceRequest>
@override
Widget build(BuildContext context) {
return Consumer<ServiceRequestDetailProvider>(builder: (context, requestDetailProvider, child) {
double totalWorkingHours = _requestDetailProvider?.activityMaintenanceHelperModel?.activityMaintenanceTimers
?.fold(0.0, (sum, item) => (sum ?? 0) + DateTime.parse(item.endTime!).difference(DateTime.parse(item.startTime!)).inSeconds) ??
0;
@ -64,228 +65,231 @@ class _InternalMaintenanceRequestState extends State<InternalMaintenanceRequest>
: requestDetailProvider.activityMaintenanceHelperModel?.id == requestDetailProvider.lastVisitedRequestActivityId;
return SingleChildScrollView(
child: Column(
children: [
Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// SingleItemDropDownMenu<Lookup, ActivityStatusProvider>(
// context: context,
// height: 56.toScreenHeight,
// title: context.translation.activityStatus,
// showShadow: false,
// backgroundColor: AppColor.neutral100,
// initialValue: requestDetailProvider.activityMaintenanceHelperModel?.activityStatus,
// onSelect: (status) {
// print('status i got is ${status?.toJson()}');
// requestDetailProvider.activityMaintenanceHelperModel?.activityStatus = status;
// },
// ),
// 8.height,
SingleItemDropDownMenu<Lookup, LastSituationProvider>(
context: context,
height: 56.toScreenHeight,
title: context.translation.activityStatus,
showShadow: false,
backgroundColor: AppColor.neutral100,
showAsBottomSheet: true,
initialValue: requestDetailProvider.activityMaintenanceHelperModel?.activityStatus,
onSelect: (status) {
if (status != null) {
requestDetailProvider.activityMaintenanceHelperModel?.activityStatus = status;
setState(() {});
}
},
),
8.height,
AppTimer(
label: context.translation.timer,
timer: requestDetailProvider.activityMaintenanceHelperModel?.activityMaintenanceTimerModel,
enabled: enableTimer,
timerProgress: (isRunning) {
print("timerProgress:$isRunning");
},
onChange: (timer) async {
requestDetailProvider.activityMaintenanceHelperModel?.activityMaintenanceTimerModel = timer;
if (timer.startAt != null && timer.endAt != null) {
requestDetailProvider.activityMaintenanceHelperModel?.timerModelList = requestDetailProvider.activityMaintenanceHelperModel?.timerModelList ?? [];
requestDetailProvider.activityMaintenanceHelperModel?.timerModelList!.add(timer);
}
return true;
},
),
// Row(
// mainAxisSize: MainAxisSize.min,
// children: [
// ADatePicker(
// label: context.translation.startTime,
// hideShadow: true,
// backgroundColor: AppColor.neutral100,
// date: requestDetailProvider.activityMaintenanceHelperModel?.startTime,
// formatDateWithTime: true,
// onDatePicker: (selectedDate) {
// showTimePicker(
// context: context,
// initialTime: TimeOfDay.now(),
// ).then((selectedTime) {
// // Handle the selected date and time here.
// if (selectedTime != null) {
// DateTime selectedDateTime = DateTime(
// selectedDate.year,
// selectedDate.month,
// selectedDate.day,
// selectedTime.hour,
// selectedTime.minute,
// );
// requestDetailProvider.activityMaintenanceHelperModel?.startTime = selectedDateTime;
// requestDetailProvider.activityMaintenanceHelperModel?.endTime = null;
// requestDetailProvider.updateActivityMaintenanceHelperModel(requestDetailProvider.activityMaintenanceHelperModel);
// _workingHoursController.clear();
// ServiceRequestUtils.calculateAndAssignWorkingHours(
// startTime: requestDetailProvider.activityMaintenanceHelperModel!.startTime,
// endTime: requestDetailProvider.activityMaintenanceHelperModel!.endTime,
// workingHoursController: _workingHoursController,
// updateModel: (hours) {
// requestDetailProvider.activityMaintenanceHelperModel?.workingHour = hours;
// },
// );
// }
// });
// },
// ).expanded,
// 8.width,
// ADatePicker(
// label: context.translation.endTime,
// hideShadow: true,
// backgroundColor: AppColor.neutral100,
// date: requestDetailProvider.activityMaintenanceHelperModel?.endTime,
// formatDateWithTime: true,
// onDatePicker: (selectedDate) {
// showTimePicker(
// context: context,
// initialTime: TimeOfDay.now(),
// ).then((selectedTime) {
// // Handle the selected date and time here.
// if (selectedTime != null) {
// DateTime selectedDateTime = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute);
// if (requestDetailProvider.activityMaintenanceHelperModel!.startTime != null &&
// selectedDateTime.isBefore(requestDetailProvider.activityMaintenanceHelperModel!.startTime!)) {
// "End Date time must be greater then start date".showToast;
// return;
// }
// requestDetailProvider.activityMaintenanceHelperModel?.endTime = selectedDateTime;
// requestDetailProvider.updateActivityMaintenanceHelperModel(requestDetailProvider.activityMaintenanceHelperModel);
// ServiceRequestUtils.calculateAndAssignWorkingHours(
// startTime: requestDetailProvider.activityMaintenanceHelperModel!.startTime,
// endTime: requestDetailProvider.activityMaintenanceHelperModel!.endTime,
// workingHoursController: _workingHoursController,
// updateModel: (hours) {
// requestDetailProvider.activityMaintenanceHelperModel?.workingHour = hours;
// },
// );
// }
// });
// },
// ).expanded,
// ],
// ),
8.height,
if (totalWorkingHours > 0.0) ...[
Container(
child: IgnorePointer(
ignoring: _requestDetailProvider!.isReadOnlyRequest,
child: Column(
children: [
Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// SingleItemDropDownMenu<Lookup, ActivityStatusProvider>(
// context: context,
// height: 56.toScreenHeight,
// title: context.translation.activityStatus,
// showShadow: false,
// backgroundColor: AppColor.neutral100,
// initialValue: requestDetailProvider.activityMaintenanceHelperModel?.activityStatus,
// onSelect: (status) {
// print('status i got is ${status?.toJson()}');
// requestDetailProvider.activityMaintenanceHelperModel?.activityStatus = status;
// },
// ),
// 8.height,
SingleItemDropDownMenu<Lookup, LastSituationProvider>(
context: context,
height: 56.toScreenHeight,
padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth),
alignment: Alignment.centerLeft,
decoration: BoxDecoration(
color: context.isDark ? AppColor.neutral40 : AppColor.background(context),
borderRadius: BorderRadius.circular(10),
boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Total Working Time",
style: Theme.of(context).textTheme.bodySmall?.copyWith(color: context.isDark ? null : AppColor.neutral20, fontWeight: FontWeight.w500),
),
Text(
" ${ServiceRequestUtils.formatTimerDuration(totalWorkingHours.round())}",
style: Theme.of(context).textTheme.bodyMedium,
),
],
title: context.translation.activityStatus,
showShadow: false,
backgroundColor: AppColor.neutral100,
showAsBottomSheet: true,
initialValue: requestDetailProvider.activityMaintenanceHelperModel?.activityStatus,
onSelect: (status) {
if (status != null) {
requestDetailProvider.activityMaintenanceHelperModel?.activityStatus = status;
setState(() {});
}
},
),
8.height,
AppTimer(
label: context.translation.timer,
timer: requestDetailProvider.activityMaintenanceHelperModel?.activityMaintenanceTimerModel,
enabled: enableTimer,
timerProgress: (isRunning) {
print("timerProgress:$isRunning");
},
onChange: (timer) async {
requestDetailProvider.activityMaintenanceHelperModel?.activityMaintenanceTimerModel = timer;
if (timer.startAt != null && timer.endAt != null) {
requestDetailProvider.activityMaintenanceHelperModel?.timerModelList = requestDetailProvider.activityMaintenanceHelperModel?.timerModelList ?? [];
requestDetailProvider.activityMaintenanceHelperModel?.timerModelList!.add(timer);
}
return true;
},
),
// Row(
// mainAxisSize: MainAxisSize.min,
// children: [
// ADatePicker(
// label: context.translation.startTime,
// hideShadow: true,
// backgroundColor: AppColor.neutral100,
// date: requestDetailProvider.activityMaintenanceHelperModel?.startTime,
// formatDateWithTime: true,
// onDatePicker: (selectedDate) {
// showTimePicker(
// context: context,
// initialTime: TimeOfDay.now(),
// ).then((selectedTime) {
// // Handle the selected date and time here.
// if (selectedTime != null) {
// DateTime selectedDateTime = DateTime(
// selectedDate.year,
// selectedDate.month,
// selectedDate.day,
// selectedTime.hour,
// selectedTime.minute,
// );
// requestDetailProvider.activityMaintenanceHelperModel?.startTime = selectedDateTime;
// requestDetailProvider.activityMaintenanceHelperModel?.endTime = null;
// requestDetailProvider.updateActivityMaintenanceHelperModel(requestDetailProvider.activityMaintenanceHelperModel);
// _workingHoursController.clear();
// ServiceRequestUtils.calculateAndAssignWorkingHours(
// startTime: requestDetailProvider.activityMaintenanceHelperModel!.startTime,
// endTime: requestDetailProvider.activityMaintenanceHelperModel!.endTime,
// workingHoursController: _workingHoursController,
// updateModel: (hours) {
// requestDetailProvider.activityMaintenanceHelperModel?.workingHour = hours;
// },
// );
// }
// });
// },
// ).expanded,
// 8.width,
// ADatePicker(
// label: context.translation.endTime,
// hideShadow: true,
// backgroundColor: AppColor.neutral100,
// date: requestDetailProvider.activityMaintenanceHelperModel?.endTime,
// formatDateWithTime: true,
// onDatePicker: (selectedDate) {
// showTimePicker(
// context: context,
// initialTime: TimeOfDay.now(),
// ).then((selectedTime) {
// // Handle the selected date and time here.
// if (selectedTime != null) {
// DateTime selectedDateTime = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute);
// if (requestDetailProvider.activityMaintenanceHelperModel!.startTime != null &&
// selectedDateTime.isBefore(requestDetailProvider.activityMaintenanceHelperModel!.startTime!)) {
// "End Date time must be greater then start date".showToast;
// return;
// }
// requestDetailProvider.activityMaintenanceHelperModel?.endTime = selectedDateTime;
// requestDetailProvider.updateActivityMaintenanceHelperModel(requestDetailProvider.activityMaintenanceHelperModel);
// ServiceRequestUtils.calculateAndAssignWorkingHours(
// startTime: requestDetailProvider.activityMaintenanceHelperModel!.startTime,
// endTime: requestDetailProvider.activityMaintenanceHelperModel!.endTime,
// workingHoursController: _workingHoursController,
// updateModel: (hours) {
// requestDetailProvider.activityMaintenanceHelperModel?.workingHour = hours;
// },
// );
// }
// });
// },
// ).expanded,
// ],
// ),
8.height,
if (totalWorkingHours > 0.0) ...[
Container(
height: 56.toScreenHeight,
padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth),
alignment: Alignment.centerLeft,
decoration: BoxDecoration(
color: context.isDark ? AppColor.neutral40 : AppColor.background(context),
borderRadius: BorderRadius.circular(10),
boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Total Working Time",
style: Theme.of(context).textTheme.bodySmall?.copyWith(color: context.isDark ? null : AppColor.neutral20, fontWeight: FontWeight.w500),
),
Text(
" ${ServiceRequestUtils.formatTimerDuration(totalWorkingHours.round())}",
style: Theme.of(context).textTheme.bodyMedium,
),
],
),
),
8.height,
],
// if (totalWorkingHours > 0.0) ...[
// AppTextFormField(
// labelText: context.translation.workingHours,
// backgroundColor: AppColor.neutral80,
// controller: _workingHoursController,
// suffixIcon: "clock".toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null).paddingOnly(end: 16),
// initialValue: requestDetailProvider.activityMaintenanceHelperModel?.workingHour != null ? requestDetailProvider.activityMaintenanceHelperModel?.workingHour.toString() : '',
// textAlign: TextAlign.center,
// labelStyle: AppTextStyles.textFieldLabelStyle,
// enable: false,
// showShadow: false,
// style: Theme.of(context).textTheme.titleMedium,
// ),
// 8.height,
// ],
AppTextFormField(
labelText: context.translation.travelingHours,
controller: _travellingHoursController,
backgroundColor: AppColor.neutral100,
showShadow: false,
labelStyle: AppTextStyles.textFieldLabelStyle,
suffixIcon: "clock".toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null).paddingOnly(end: 16),
initialValue: requestDetailProvider.activityMaintenanceHelperModel?.travelHours?.toString(),
textInputType: TextInputType.number,
onChange: (value) {
requestDetailProvider.activityMaintenanceHelperModel?.travelHours = num.parse(value); // int.tryParse(value);
},
// contentPadding: EdgeInsets.symmetric(vertical: 18.toScreenHeight, horizontal: 16.toScreenWidth),
onSaved: (value) {
requestDetailProvider.activityMaintenanceHelperModel?.travelHours = value as num?;
},
),
16.height,
repairLocationWidget(context, requestDetailProvider),
16.height,
AppTextFormField(
labelText: context.translation.assignedEmployee,
backgroundColor: AppColor.neutral80,
initialValue: requestDetailProvider.activityMaintenanceHelperModel?.assignedEmployee?.userName,
textAlign: TextAlign.center,
labelStyle: AppTextStyles.textFieldLabelStyle,
showShadow: false,
enable: false,
style: Theme.of(context).textTheme.titleMedium,
),
8.height,
AppTextFormField(
initialValue: requestDetailProvider.activityMaintenanceHelperModel?.technicalComment,
labelText: context.translation.technicalComment,
backgroundColor: AppColor.neutral100,
showShadow: false,
labelStyle: AppTextStyles.textFieldLabelStyle,
alignLabelWithHint: true,
textInputType: TextInputType.multiline,
onChange: (value) {
requestDetailProvider.activityMaintenanceHelperModel?.technicalComment = value;
},
onSaved: (value) {
requestDetailProvider.activityMaintenanceHelperModel?.technicalComment = value;
},
),
],
// if (totalWorkingHours > 0.0) ...[
// AppTextFormField(
// labelText: context.translation.workingHours,
// backgroundColor: AppColor.neutral80,
// controller: _workingHoursController,
// suffixIcon: "clock".toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null).paddingOnly(end: 16),
// initialValue: requestDetailProvider.activityMaintenanceHelperModel?.workingHour != null ? requestDetailProvider.activityMaintenanceHelperModel?.workingHour.toString() : '',
// textAlign: TextAlign.center,
// labelStyle: AppTextStyles.textFieldLabelStyle,
// enable: false,
// showShadow: false,
// style: Theme.of(context).textTheme.titleMedium,
// ),
// 8.height,
// ],
AppTextFormField(
labelText: context.translation.travelingHours,
controller: _travellingHoursController,
backgroundColor: AppColor.neutral100,
showShadow: false,
labelStyle: AppTextStyles.textFieldLabelStyle,
suffixIcon: "clock".toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null).paddingOnly(end: 16),
initialValue: requestDetailProvider.activityMaintenanceHelperModel?.travelHours?.toString(),
textInputType: TextInputType.number,
onChange: (value) {
requestDetailProvider.activityMaintenanceHelperModel?.travelHours = num.parse(value) ;// int.tryParse(value);
},
// contentPadding: EdgeInsets.symmetric(vertical: 18.toScreenHeight, horizontal: 16.toScreenWidth),
onSaved: (value) {
requestDetailProvider.activityMaintenanceHelperModel?.travelHours = value as num?;
},
),
16.height,
repairLocationWidget(context, requestDetailProvider),
16.height,
AppTextFormField(
labelText: context.translation.assignedEmployee,
backgroundColor: AppColor.neutral80,
initialValue: requestDetailProvider.activityMaintenanceHelperModel?.assignedEmployee?.userName,
textAlign: TextAlign.center,
labelStyle: AppTextStyles.textFieldLabelStyle,
showShadow: false,
enable: false,
style: Theme.of(context).textTheme.titleMedium,
),
8.height,
AppTextFormField(
initialValue: requestDetailProvider.activityMaintenanceHelperModel?.technicalComment,
labelText: context.translation.technicalComment,
backgroundColor: AppColor.neutral100,
showShadow: false,
labelStyle: AppTextStyles.textFieldLabelStyle,
alignLabelWithHint: true,
textInputType: TextInputType.multiline,
onChange: (value) {
requestDetailProvider.activityMaintenanceHelperModel?.technicalComment = value;
},
onSaved: (value) {
requestDetailProvider.activityMaintenanceHelperModel?.technicalComment = value;
},
),
],
),
).toShadowContainer(context).paddingOnly(start: 13, end: 14, top: 12),
const AssistantEmployeeCard().toShadowContainer(context, paddingObject: const EdgeInsets.symmetric(horizontal: 16)).paddingOnly(start: 13, end: 14, top: 12),
100.height,
],
),
).toShadowContainer(context).paddingOnly(start: 13, end: 14, top: 12),
const AssistantEmployeeCard().toShadowContainer(context, paddingObject: const EdgeInsets.symmetric(horizontal: 16)).paddingOnly(start: 13, end: 14, top: 12),
100.height,
],
),
),
);
});

@ -18,7 +18,7 @@ import 'package:test_sa/service_request_latest/views/forms/maintenance_request/c
import 'package:test_sa/service_request_latest/views/forms/maintenance_request/components/internal_request.dart';
class MaintenanceRequestForm extends StatefulWidget {
const MaintenanceRequestForm({Key? key}) : super(key: key);
MaintenanceRequestForm({Key? key}) : super(key: key);
@override
_MaintenanceRequestFormState createState() => _MaintenanceRequestFormState();
@ -47,9 +47,16 @@ class _MaintenanceRequestFormState extends State<MaintenanceRequestForm> with Si
Widget build(BuildContext context) {
return Consumer<ServiceRequestDetailProvider>(builder: (context, ServiceRequestDetailProvider requestDetailProvider, child) {
bool isUpdate = requestDetailProvider.activityMaintenanceHelperModel?.id != 0;
return Scaffold(
return Scaffold(
backgroundColor: AppColor.neutral110,
appBar: const DefaultAppBar(title: "CM Activity"),
appBar: DefaultAppBar(
title: "CM Activity",
onWillPopScope: requestDetailProvider.isReadOnlyRequest
? null
: () {
save(requestDetailProvider);
},
),
body: Stack(
children: [
DefaultTabController(
@ -92,53 +99,55 @@ class _MaintenanceRequestFormState extends State<MaintenanceRequestForm> with Si
],
),
),
FooterActionButton.footerContainer(
child: AppFilledButton(
label: requestDetailProvider.activityMaintenanceHelperModel?.id != 0 ? context.translation.update : context.translation.addActivity, // Use the dynamic label
buttonColor: AppColor.primary10,
onPressed: () async {
//TODO add this as dropdown not added in design yet Bhaa need to confirm with hussain then.
// requestDetailProvider.activityMaintenanceHelperModel?.lastSituationId = 282;
if (validate(model: requestDetailProvider.activityMaintenanceHelperModel!)) {
requestDetailProvider.activityMaintenanceHelperModel?.activityMaintenanceTimers = requestDetailProvider.activityMaintenanceHelperModel?.activityMaintenanceTimers ?? [];
requestDetailProvider.activityMaintenanceHelperModel?.timerModelList?.forEach((timer) {
int durationInSecond = timer.endAt!.difference(timer.startAt!).inSeconds;
requestDetailProvider.activityMaintenanceHelperModel?.activityMaintenanceTimers?.add(
ActivityMaintenanceTimers(
id: 0,
startTime: timer.startAt!.toIso8601String(), // Handle potential null
endTime: timer.endAt?.toIso8601String(), // Handle potential null
workingHours: ((durationInSecond) / 60 / 60),
),
);
});
showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
int status = -1;
if (requestDetailProvider.activityMaintenanceHelperModel?.id == 0) {
status = await requestDetailProvider.createActivityMaintenanceRequest();
} else {
status = await requestDetailProvider.updateActivityMaintenance();
}
if (status == 200) {
requestDetailProvider.getWorkOrderById(id: requestDetailProvider.currentWorkOrder!.data!.requestId!);
Navigator.pop(context);
Navigator.pop(context);
} else {
Navigator.pop(context);
}
}
// Handle button press
},
if (!requestDetailProvider.isReadOnlyRequest)
FooterActionButton.footerContainer(
child: AppFilledButton(
label: requestDetailProvider.activityMaintenanceHelperModel?.id != 0 ? context.translation.update : context.translation.addActivity, // Use the dynamic label
buttonColor: AppColor.primary10,
onPressed: () async {
save(requestDetailProvider);
},
),
),
),
],
),
);
).handlePopScope(cxt: context, showPopUp: !requestDetailProvider.isReadOnlyRequest, onSave: () {
save(requestDetailProvider);
});
});
}
void save(ServiceRequestDetailProvider requestDetailProvider) async {
if (validate(model: requestDetailProvider.activityMaintenanceHelperModel!)) {
requestDetailProvider.activityMaintenanceHelperModel?.activityMaintenanceTimers = requestDetailProvider.activityMaintenanceHelperModel?.activityMaintenanceTimers ?? [];
requestDetailProvider.activityMaintenanceHelperModel?.timerModelList?.forEach((timer) {
int durationInSecond = timer.endAt!.difference(timer.startAt!).inSeconds;
requestDetailProvider.activityMaintenanceHelperModel?.activityMaintenanceTimers?.add(
ActivityMaintenanceTimers(
id: 0,
startTime: timer.startAt!.toIso8601String(), // Handle potential null
endTime: timer.endAt?.toIso8601String(), // Handle potential null
workingHours: ((durationInSecond) / 60 / 60),
),
);
});
showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
int status = -1;
if (requestDetailProvider.activityMaintenanceHelperModel?.id == 0) {
status = await requestDetailProvider.createActivityMaintenanceRequest();
} else {
status = await requestDetailProvider.updateActivityMaintenance();
}
if (status == 200) {
requestDetailProvider.getWorkOrderById(id: requestDetailProvider.currentWorkOrder!.data!.requestId!);
Navigator.pop(context);
Navigator.pop(context);
} else {
Navigator.pop(context);
}
}
}
bool validate({required ActivityMaintenanceHelperModel model}) {
if (model.activityStatus == null) {
Fluttertoast.showToast(msg: "${context.translation.youHaveToSelect} ${context.translation.activityStatus}");

@ -4,6 +4,7 @@ import 'dart:io';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/all_requests_provider.dart';
import 'package:test_sa/controllers/providers/api/parts_provider.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
@ -11,6 +12,7 @@ import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/helper_data_models/spare_part/activity_spare_part_model.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/models/size_config.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/single_item_drop_down_menu.dart';
@ -19,6 +21,7 @@ import 'package:test_sa/service_request_latest/service_request_detail_provider.d
import 'package:test_sa/service_request_latest/views/components/action_button/footer_action_button.dart';
import 'package:test_sa/service_request_latest/views/components/bottom_sheets/service_request_bottomsheet.dart';
import 'package:test_sa/views/widgets/images/new_multi_image_picker.dart';
import 'package:test_sa/views/widgets/loaders/no_data_found.dart';
import '../../../../../../models/service_request/spare_parts.dart';
import '../../../../../../new_views/common_widgets/app_text_form_field.dart';
@ -80,7 +83,7 @@ class _SparePartRequestState extends State<SparePartRequest> with TickerProvider
_isLoading = true;
_files = _requestDetailProvider?.sparePartHelperModel?.sparePartAttachments?.map((e) => MultiFilesPickerModel(e.id!, File(e.name!))).toList() ?? [];
setState(() {});
_spareParts = await _partsProvider!.getPartsList(assetId: _requestDetailProvider?.currentWorkOrder?.data?.asset?.id);
_spareParts = await _partsProvider!.getPartsListByDisplayName(assetId: _requestDetailProvider?.currentWorkOrder?.data?.asset?.id);
_isLoading = false;
setState(() {});
@ -119,6 +122,7 @@ class _SparePartRequestState extends State<SparePartRequest> with TickerProvider
key: _scaffoldKey,
appBar: DefaultAppBar(title: context.translation.sparePartRequest),
body: Consumer<ServiceRequestDetailProvider>(builder: (context, ServiceRequestDetailProvider requestDetailProvider, child) {
print('data i got is ${requestDetailProvider.sparePartHelperModel?.sparePart?.toJson()}');
return SafeArea(
child: Form(
key: _formKey,
@ -148,14 +152,14 @@ class _SparePartRequestState extends State<SparePartRequest> with TickerProvider
12.height,
SingleItemDropDownMenu<SparePart, NullableLoadingProvider>(
context: context,
title: context.translation.partNo,
title: context.translation.part,
staticData: _spareParts,
showShadow: false,
showAsBottomSheet: true,
loading: _isLoading,
initialValue: requestDetailProvider.sparePartHelperModel?.sparePart,
backgroundColor: context.isDark ? AppColor.neutral20 : AppColor.neutral90,
onSelect: (part) {
onSelect: (part) async {
if (part != null) {
requestDetailProvider.sparePartHelperModel?.sparePart = part;
_oracleNoController.text = part.oracleCode ?? '';
@ -163,6 +167,36 @@ class _SparePartRequestState extends State<SparePartRequest> with TickerProvider
}
},
),
if(requestDetailProvider.sparePartHelperModel?.sparePart?.id!=null)...[
12.height,
SizedBox(
height: 30.toScreenHeight,
child: Text('View Parts Availability',style:TextStyle(
fontSize: 12.toScreenWidth,
fontWeight: FontWeight.w500,
fontStyle: FontStyle.normal,
color:AppColor.primary10 ,
decorationColor: AppColor.primary10,
decoration: TextDecoration.underline,
)).onPress(
() async {
requestDetailProvider.getStoreAvailabilityById(partId: requestDetailProvider.sparePartHelperModel?.sparePart?.id);
showModalBottomSheet(
context: context,
isScrollControlled: true,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(20),
),
),
clipBehavior: Clip.antiAliasWithSaveLayer,
builder: (BuildContext context) => PartDetailBottomSheetSheet(),
);
},
),
),
],
12.height,
AppTextFormField(
controller: _partQtyController,
@ -245,7 +279,7 @@ class _SparePartRequestState extends State<SparePartRequest> with TickerProvider
controller: _descriptionController,
showSpeechToText: true,
backgroundColor: context.isDark ? AppColor.neutral20 : AppColor.neutral90,
labelText: context.translation.description,
labelText: "Engineer Comment",
alignLabelWithHint: true,
showWithoutDecoration: true,
textInputType: TextInputType.multiline,
@ -309,4 +343,58 @@ class _SparePartRequestState extends State<SparePartRequest> with TickerProvider
}),
);
}
}
class PartDetailBottomSheetSheet extends StatelessWidget {
PartDetailBottomSheetSheet( {Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return SizedBox(
height: SizeConfig.screenHeight!/2.2,
width: SizeConfig.screenWidth,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
8.height,
'Parts Availability'.heading6(context).paddingOnly(top: 12,start: 12),
Consumer<ServiceRequestDetailProvider>(
builder: (context, requestDetailProvider,child) {
return requestDetailProvider.isLoading
? const CircularProgressIndicator(color: AppColor.primary10).center
: requestDetailProvider.storeAvailability.isEmpty
? const NoDataFound().center
: ListView.separated(
padding: const EdgeInsets.all(16),
itemCount: requestDetailProvider.storeAvailability.length,
separatorBuilder: (czt, index) => 12.height,
itemBuilder: (context, index) {
StoreAvailability model = requestDetailProvider.storeAvailability[index];
return partAvailableQuantityCard(context: context,model:model);
},
);
}
).expanded,
],
),
);
}
Widget partAvailableQuantityCard({required StoreAvailability model,required BuildContext context }){
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
'Site Name: ${model.siteName??''}'.bodyText2(context).custom(color: AppColor.neutral120),
8.height,
'Store Name: ${model.storeName??''}'.bodyText2(context).custom(color: AppColor.neutral120),
8.height,
'Available Quantity: ${model.availablityQty??''}'.bodyText2(context).custom(color: AppColor.neutral120),
8.height,
]
).toShadowContainer(context, padding: 12, showShadow: false,backgroundColor: AppColor.neutral110);
}
}

@ -128,10 +128,10 @@ class _ServiceRequestDetailMainState extends State<ServiceRequestDetailMain> {
),
),
12.height,
const TabBarView(
TabBarView(
children: [
ServiceRequestDetailView(),
HistoryLogView(),
const HistoryLogView(),
],
).expanded,
],

@ -0,0 +1,345 @@
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/asset_transfer_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/device/asset_transfer.dart';
import 'package:test_sa/models/device/asset_transfer_attachment.dart';
import 'package:test_sa/models/new_models/department.dart';
import 'package:test_sa/models/new_models/floor.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_text_form_field.dart';
import 'package:test_sa/providers/ppm_service_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 '../../../models/new_models/building.dart';
import '../../../models/new_models/site.dart';
import '../../../new_views/common_widgets/app_filled_button.dart';
import '../../../new_views/common_widgets/default_app_bar.dart';
import '../../../new_views/common_widgets/single_item_drop_down_menu.dart';
import '../../../providers/gas_request_providers/site_provider.dart';
import '../../../providers/loading_list_notifier.dart';
class CreateAssetTransferRequest extends StatefulWidget {
static const String id = "/request-device-transfer";
const CreateAssetTransferRequest({Key? key}) : super(key: key);
@override
State<CreateAssetTransferRequest> createState() => _CreateAssetTransferRequestState();
}
class _CreateAssetTransferRequestState extends State<CreateAssetTransferRequest> {
late AssetTransferProvider _deviceTransferProvider;
final TextEditingController _requestedQuantityController = TextEditingController();
final AssetTransfer _transferModel = AssetTransfer(id: 0);
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
final TextEditingController _receiverNameController = TextEditingController(), _commentsController = TextEditingController();
final Asset _assetDestination = Asset();
Asset? _pickedAsset;
final List<File> _deviceImages = [];
PendingAssetServiceRequest? pendingAssetServiceRequest;
@override
void setState(VoidCallback fn) {
if (mounted) super.setState(() {});
}
bool checkPendingRequest = false;
void showPendingRequests() {
Navigator.of(context).push(MaterialPageRoute(builder: (_) => PendingServiceRequestScreen(pendingAssetServiceRequest!)));
}
void _onSubmit() async {
_transferModel.assetId = _pickedAsset?.id;
_transferModel.destSiteId = _assetDestination.site?.id;
_transferModel.destBuildingId = _assetDestination.building?.id;
_transferModel.destFloorId = _assetDestination.floor?.id;
_transferModel.destDepartmentId = _assetDestination.department?.id;
_transferModel.destRoomId = _assetDestination.room?.id;
if (!_formKey.currentState!.validate() || !(await _transferModel.validate(context))) {
return;
}
_formKey.currentState!.save();
List<AssetTransferAttachment> attachement = [];
for (var item in _deviceImages) {
attachement.add(AssetTransferAttachment(id: 0, attachmentName: "${item.path.split("/").last}|${base64Encode(item.readAsBytesSync())}"));
}
_transferModel.attachments = attachement;
await _deviceTransferProvider.createRequest(
context: context,
model: _transferModel,
);
}
@override
void initState() {
WidgetsBinding.instance.addPostFrameCallback((_) async {
Provider.of<PpmServiceProvider>(context, listen: false).getDate();
});
super.initState();
}
@override
void dispose() {
_requestedQuantityController.dispose();
_deviceTransferProvider.reset();
_receiverNameController.dispose();
_commentsController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
_deviceTransferProvider = Provider.of<AssetTransferProvider>(context, listen: false);
return Scaffold(
key: _scaffoldKey,
appBar: DefaultAppBar(
title: context.translation.createAssetTransferRequest,
titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
),
body: Form(
key: _formKey,
child: SafeArea(
child: Column(
children: [
SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
AssetPicker(
device: _pickedAsset,
showLoading: false,
borderColor: AppColor.black20,
backgroundColor: AppColor.white936,
onPick: (asset) async {
_pickedAsset = asset;
// await checkAssetForPendingServiceRequest(asset.id!.toInt());
// if (_pickedAsset != null && pendingAssetServiceRequest != null && pendingAssetServiceRequest!.details!.isNotEmpty) {
// showPendingRequestBottomSheet();
// }
setState(() {});
}),
// 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();
// }),
// ],
21.height,
requestTypeWidget(context),
12.height,
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SingleItemDropDownMenu<Site, SiteProvider>(
context: context,
title: context.translation.site,
initialValue: _assetDestination.site,
showShadow: false,
backgroundColor: AppColor.neutral100,
showAsBottomSheet: true,
onSelect: (value) {
_assetDestination.site = value;
_assetDestination.building = null;
_assetDestination.floor = null;
_assetDestination.department = null;
setState(() {});
},
).expanded,
8.width,
SingleItemDropDownMenu<Building, NullableLoadingProvider>(
context: context,
title: context.translation.building,
initialValue: _assetDestination.building,
showShadow: false,
showAsBottomSheet: true,
backgroundColor: AppColor.neutral100,
enabled: _assetDestination.site?.buildings?.isNotEmpty ?? false,
staticData: _assetDestination.site?.buildings ?? [],
onSelect: (value) {
_assetDestination.building = value;
_assetDestination.floor = null;
_assetDestination.department = null;
setState(() {});
},
).expanded,
],
),
8.height,
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SingleItemDropDownMenu<Floor, NullableLoadingProvider>(
context: context,
title: context.translation.floor,
showShadow: false,
showAsBottomSheet: true,
initialValue: _assetDestination.floor,
backgroundColor: AppColor.neutral100,
enabled: _assetDestination.building?.floors?.isNotEmpty ?? false,
staticData: _assetDestination.building?.floors ?? [],
onSelect: (value) {
_assetDestination.floor = value;
_assetDestination.department = null;
setState(() {});
},
).expanded,
8.width,
SingleItemDropDownMenu<Department, NullableLoadingProvider>(
context: context,
title: context.translation.department,
showShadow: false,
showAsBottomSheet: true,
initialValue: _assetDestination.department,
backgroundColor: AppColor.neutral100,
enabled: _assetDestination.floor?.departments?.isNotEmpty ?? false,
staticData: _assetDestination.floor?.departments ?? [],
onSelect: (value) {
_assetDestination.department = value;
_assetDestination.room = null;
setState(() {});
},
).expanded,
],
),
8.height,
AppTextFormField(
controller: _commentsController,
backgroundColor: AppColor.neutral100,
labelText: context.translation.callComments,
labelStyle: AppTextStyles.textFieldLabelStyle,
alignLabelWithHint: true,
textInputType: TextInputType.multiline,
showShadow: false,
onSaved: (text) {
_transferModel.comment = text;
},
),
8.height,
23.height,
MultiFilesPicker(
label: context.translation.attachImage,
files: _deviceImages,
buttonColor: AppColor.black10,
onlyImages: true,
buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.neutral120),
),
// 100.height,
],
).toShadowContainer(context).paddingOnly(top: 20, start: 16, end: 16),
).expanded,
FooterActionButton.footerContainer(
child: AppFilledButton(buttonColor: AppColor.primary10, label: context.translation.submitRequest, maxWidth: true, onPressed: _onSubmit),
),
],
),
),
),
);
}
Future<void> checkAssetForPendingServiceRequest(int assetId) async {
checkPendingRequest = true;
setState(() {});
pendingAssetServiceRequest = await _deviceTransferProvider.checkAssetPendingRequest(assetId);
await Future.delayed(const Duration(milliseconds: 250));
checkPendingRequest = false;
setState(() {});
}
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!, _pickedAsset!),
)) as bool;
if (view) {
showPendingRequests();
}
}
Widget requestTypeWidget(BuildContext context) {
return Consumer<PpmServiceProvider>(builder: (cxt, snapshot, _) {
try {
_transferModel.transferType ??= snapshot.items.first;
} catch (ex) {
print("snapshot.items:${snapshot.items.length}");
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
context.translation.requestType.bodyText(context).custom(color: AppColor.white936),
8.height,
Wrap(
runSpacing: 8,
spacing: 8,
children: [
for (var element in snapshot.items)
Row(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
width: 24,
height: 24,
child: Radio(
value: element,
activeColor: AppColor.primary10,
fillColor: WidgetStateColor.resolveWith((states) {
if (states.contains(WidgetState.selected)) {
return AppColor.primary10; // Thumb color when selected
}
return Colors.grey; // Thumb color when unselected (grey)
}),
groupValue: _transferModel.transferType,
onChanged: (state) {
_transferModel.transferType = element;
setState(() {});
// });
}),
),
8.width,
Text(element.name ?? '', style: AppTextStyles.tinyFont.copyWith(color: AppColor.neutral120)),
],
)
],
).toShimmer(isShow: snapshot.loading),
],
);
});
}
}

@ -1,3 +1,5 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/asset_transfer_provider.dart';
@ -8,6 +10,7 @@ import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/device/asset_transfer.dart';
import 'package:test_sa/views/pages/device_transfer/update_device_transfer.dart';
import 'package:test_sa/views/widgets/images/multi_image_picker.dart';
import 'package:test_sa/views/widgets/loaders/app_loading.dart';
import 'package:test_sa/views/widgets/loaders/loading_manager.dart';
@ -31,6 +34,7 @@ class _DeviceTransferDetailsState extends State<DeviceTransferDetails> {
AssetTransfer? _model;
final bool _isLoading = false;
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
List<File> _attachments = [];
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
@override
@ -41,6 +45,7 @@ class _DeviceTransferDetailsState extends State<DeviceTransferDetails> {
@override
Widget build(BuildContext context) {
_userProvider ??= Provider.of<UserProvider>(context);
return Scaffold(
appBar: DefaultAppBar(title: context.translation.deviceTransferDetails),
key: _scaffoldKey,
@ -52,6 +57,7 @@ class _DeviceTransferDetailsState extends State<DeviceTransferDetails> {
return const ALoading();
} else {
_model = snapshot.data as AssetTransfer?;
_attachments = _model?.attachments?.map((e) => File(e.attachmentName ?? '')).toList() ?? [];
return Form(
key: _formKey,
@ -89,6 +95,8 @@ class _DeviceTransferDetailsState extends State<DeviceTransferDetails> {
const Divider().defaultStyle(context),
8.height,
_buildTextWidget(_model!.comment!),
]
],
),
@ -177,6 +185,27 @@ class _DeviceTransferDetailsState extends State<DeviceTransferDetails> {
return widget.toShadowContainer(context).paddingOnly(top: 14, start: 14, end: 14);
}
Widget attachmentWidget(){
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
8.height,
if (_attachments.isNotEmpty) ...[
const Divider().defaultStyle(context),
context.translation.attachments.bodyText(context),
8.height,
MultiFilesPicker(
label: context.translation.attachments,
files: _attachments,
enabled: false,
onlyImages: false,
),
12.height,
],
],
);
}
_buildTextWidget(String text) {
return text.bodyText(context);
}
@ -224,6 +253,8 @@ class _DeviceTransferDetailsState extends State<DeviceTransferDetails> {
const Divider().defaultStyle(context),
8.height,
_buildTextWidget(comment),
attachmentWidget(),
]
],
).toShadowContainer(context);
@ -237,4 +268,6 @@ class _DeviceTransferDetailsState extends State<DeviceTransferDetails> {
}
}
}

@ -1,211 +0,0 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/asset_transfer_provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/employee/nurse_provider.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart';
import 'package:test_sa/controllers/providers/settings/setting_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/device/asset_transfer.dart';
import 'package:test_sa/models/employee.dart';
import 'package:test_sa/models/new_models/department.dart';
import 'package:test_sa/models/new_models/floor.dart';
import 'package:test_sa/models/new_models/room_model.dart';
import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart';
import 'package:test_sa/views/widgets/status/employee/nurse_menu.dart';
import '../../../models/new_models/building.dart';
import '../../../models/new_models/site.dart';
import '../../../new_views/common_widgets/app_filled_button.dart';
import '../../../new_views/common_widgets/default_app_bar.dart';
import '../../../new_views/common_widgets/single_item_drop_down_menu.dart';
import '../../../providers/gas_request_providers/site_provider.dart';
import '../../../providers/loading_list_notifier.dart';
import '../../widgets/equipment/pick_asset.dart';
class RequestDeviceTransfer extends StatefulWidget {
static const String id = "/request-device-transfer";
const RequestDeviceTransfer({Key? key}) : super(key: key);
@override
State<RequestDeviceTransfer> createState() => _RequestDeviceTransferState();
}
class _RequestDeviceTransferState extends State<RequestDeviceTransfer> {
UserProvider? _userProvider;
SettingProvider? _settingProvider;
late AssetTransferProvider _deviceTransferProvider;
final TextEditingController _requestedQuantityController = TextEditingController();
final AssetTransfer _transferModel = AssetTransfer();
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
final TextEditingController _receiverNameController = TextEditingController(), _commentsController = TextEditingController();
final Asset _assetDestination = Asset();
Asset? _pickedAsset;
Employee? receiverEndUser;
Employee? _selectedNurse;
@override
void setState(VoidCallback fn) {
if (mounted) super.setState(() {});
}
void _onSubmit() async {
_transferModel.assetId = _pickedAsset?.id;
_transferModel.destSiteId = _assetDestination.site?.id;
_transferModel.destBuildingId = _assetDestination.building?.id;
_transferModel.destFloorId = _assetDestination.floor?.id;
_transferModel.destDepartmentId = _assetDestination.department?.id;
_transferModel.destRoomId = _assetDestination.room?.id;
_transferModel.receiverEndUserId = _selectedNurse?.id;
if (!_formKey.currentState!.validate() || !(await _transferModel.validate(context))) {
return;
}
_formKey.currentState!.save();
await _deviceTransferProvider.createRequest(context: context, assetDestination: _transferModel, asset: _pickedAsset!);
}
@override
void dispose() {
_requestedQuantityController.dispose();
_deviceTransferProvider.reset();
_receiverNameController.dispose();
_commentsController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
_userProvider = Provider.of<UserProvider>(context, listen: false);
_settingProvider = Provider.of<SettingProvider>(context, listen: false);
_deviceTransferProvider = Provider.of<AssetTransferProvider>(context, listen: false);
// _selectedNurse ??= Employee(id: _userProvider.user.userID, name: _userProvider.user.username);
return Scaffold(
key: _scaffoldKey,
appBar: DefaultAppBar(title: context.translation.newTransferRequest),
body: Form(
key: _formKey,
child: SafeArea(
child: Column(
children: [
SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
16.height,
PickAsset(
device: _pickedAsset,
onPickAsset: (asset) {
_pickedAsset = asset;
setState(() {});
},
),
16.height,
context.translation.receiverDetails.heading5(context),
8.height,
SingleItemDropDownMenu<Site, SiteProvider>(
context: context,
title: context.translation.destinationSite,
initialValue: _assetDestination.site,
onSelect: (value) {
_assetDestination.site = value;
_assetDestination.building = null;
_assetDestination.floor = null;
_assetDestination.department = null;
_selectedNurse = null;
Provider.of<NurseProvider>(context, listen: false).siteId = value!.id!.toInt();
Provider.of<NurseProvider>(context, listen: false).getData();
setState(() {});
},
),
8.height,
SingleItemDropDownMenu<Building, NullableLoadingProvider>(
context: context,
title: context.translation.building,
initialValue: _assetDestination.building,
enabled: _assetDestination.site?.buildings?.isNotEmpty ?? false,
staticData: _assetDestination.site?.buildings ?? [],
onSelect: (value) {
_assetDestination.building = value;
_assetDestination.floor = null;
_assetDestination.department = null;
setState(() {});
},
),
8.height,
SingleItemDropDownMenu<Floor, NullableLoadingProvider>(
context: context,
title: context.translation.floor,
initialValue: _assetDestination.floor,
enabled: _assetDestination.building?.floors?.isNotEmpty ?? false,
staticData: _assetDestination.building?.floors ?? [],
onSelect: (value) {
_assetDestination.floor = value;
_assetDestination.department = null;
setState(() {});
},
),
8.height,
SingleItemDropDownMenu<Department, NullableLoadingProvider>(
context: context,
title: context.translation.department,
initialValue: _assetDestination.department,
enabled: _assetDestination.floor?.departments?.isNotEmpty ?? false,
staticData: _assetDestination.floor?.departments ?? [],
onSelect: (value) {
_assetDestination.department = value;
_assetDestination.room = null;
setState(() {});
},
),
8.height,
SingleItemDropDownMenu<Rooms, NullableLoadingProvider>(
context: context,
title: context.translation.room,
initialValue: _assetDestination.room,
enabled: _assetDestination.department?.rooms?.isNotEmpty ?? false,
staticData: _assetDestination.department?.rooms ?? [],
onSelect: (value) {
_assetDestination.room = value;
setState(() {});
},
),
8.height,
NurseMenu(
title: context.translation.receiverName,
initialValue: _selectedNurse,
enable: _assetDestination.site != null,
onSelect: (employee) {
if (employee != null) {
_selectedNurse = employee;
setState(() {});
}
},
),
16.height,
context.translation.comments.heading5(context),
8.height,
AppTextFormField(
controller: _commentsController,
labelText: context.translation.comments,
onSaved: (text) {
_transferModel.comment = text;
},
),
100.height,
],
),
).expanded,
AppFilledButton(label: context.translation.submitRequest, maxWidth: true, onPressed: _onSubmit)
],
).paddingOnly(start: 16, end: 16, bottom: 24),
),
),
);
}
}

@ -1,33 +1,366 @@
//older code.
// import 'dart:convert';
// import 'dart:io';
//
// import 'package:flutter/foundation.dart';
// import 'package:flutter/material.dart';
// import 'package:fluttertoast/fluttertoast.dart';
// import 'package:provider/provider.dart';
// import 'package:test_sa/controllers/providers/api/asset_transfer_provider.dart';
// import 'package:test_sa/controllers/providers/api/user_provider.dart';
// import 'package:test_sa/controllers/providers/settings/setting_provider.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/widget_extensions.dart';
// import 'package:test_sa/models/device/asset_transfer.dart';
// import 'package:test_sa/models/device/asset_transfer_attachment.dart';
// import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
// import 'package:test_sa/providers/asset_transfer/asset_transfer_status_provider.dart';
// import 'package:test_sa/views/app_style/sizing.dart';
// import 'package:test_sa/views/widgets/images/multi_image_picker.dart';
// import 'package:test_sa/views/widgets/loaders/loading_manager.dart';
//
// import '../../../extensions/text_extensions.dart';
// import '../../../models/lookup.dart';
// import '../../../models/ppm/ppm.dart';
// import '../../../new_views/app_style/app_color.dart';
// import '../../../new_views/common_widgets/app_text_form_field.dart';
// import '../../../new_views/common_widgets/default_app_bar.dart';
// import '../../../new_views/common_widgets/single_item_drop_down_menu.dart';
// import '../../widgets/e_signature/e_signature.dart';
// import '../../widgets/timer/app_timer.dart';
//
// class UpdateDeviceTransfer extends StatefulWidget {
// final AssetTransfer model;
// final bool isSender;
//
// const UpdateDeviceTransfer({Key? key, required this.model, required this.isSender}) : super(key: key);
//
// @override
// State<UpdateDeviceTransfer> createState() => _UpdateDeviceTransferState();
// }
//
// class _UpdateDeviceTransferState extends State<UpdateDeviceTransfer> {
// final bool _isLoading = false;
// bool _validate = false;
// late UserProvider _userProvider;
// late SettingProvider _settingProvider;
// Uint8List? _signature;
// late AssetTransferProvider _deviceTransferProvider;
// final TextEditingController _requestedQuantityController = TextEditingController();
// final AssetTransfer _formModel = AssetTransfer();
// final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
// final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
//
// List<File> _files = [];
//
// _update() async {
// if (widget.isSender) {
// _formModel.senderVisitTimers?.add(
// VisitTimers(
// id: 0,
// startDateTime: _formModel.tbsTimer?.startAt?.toIso8601String(),
// endDateTime: _formModel.tbsTimer?.endAt?.toIso8601String(),
// workingHours: ((_formModel.tbsTimer?.durationInSecond ?? 0) / 60 / 60),
// ),
// );
// } else {
// _formModel.receiverVisitTimers?.add(
// VisitTimers(
// id: 0,
// startDateTime: _formModel.tbsTimer?.startAt?.toIso8601String(),
// endDateTime: _formModel.tbsTimer?.endAt?.toIso8601String(),
// workingHours: ((_formModel.tbsTimer?.durationInSecond ?? 0) / 60 / 60),
// ),
// );
// }
//
// if (_formModel.tbsTimer?.startAt == null) {
// await Fluttertoast.showToast(msg: "Working Hours Required");
// return false;
// }
// if (_formModel.tbsTimer?.endAt == null || isTimerRunning) {
// await Fluttertoast.showToast(msg: "Please Stop The Timer");
// return false;
// }
// _validate = true;
// if (!(_formKey.currentState!.validate())) {
// setState(() {});
// return false;
// }
// _formKey.currentState!.save();
//
// if (widget.isSender) {
// _formModel.senderAttachments = [];
// } else {
// _formModel.receiverAttachments = [];
// }
//
// try {
// for (var file in _files) {
// String attachmentName = file.path;
// if (attachmentName.contains("/")) {
// attachmentName = file.path.split("/").last;
// attachmentName = "$attachmentName|${base64Encode(file.readAsBytesSync())}";
// }
//
// if (widget.isSender) {
// _formModel.senderAttachments!.add(AssetTransferAttachment(id: 0, attachmentName: attachmentName));
// } else {
// _formModel.receiverAttachments!.add(AssetTransferAttachment(id: 0, attachmentName: attachmentName));
// }
// }
// } catch (error) {
// print(error);
// }
// await _deviceTransferProvider.updateRequest(context, assetTransfer: _formModel, isSender: widget.isSender);
// }
//
// @override
// void initState() {
// _formModel.fromDetails(widget.model);
//
// if (widget.isSender) {
// _files = widget.model.senderAttachments?.map((e) => File(e.attachmentName!)).toList() ?? [];
// } else {
// _files = widget.model.receiverAttachments?.map((e) => File(e.attachmentName!)).toList() ?? [];
// }
//
// super.initState();
// }
//
// @override
// void dispose() {
// _requestedQuantityController.dispose();
// super.dispose();
// }
//
// bool isTimerRunning = false;
//
// @override
// Widget build(BuildContext context) {
// _userProvider = Provider.of<UserProvider>(context);
// _settingProvider = Provider.of<SettingProvider>(context);
// _deviceTransferProvider = Provider.of<AssetTransferProvider>(context, listen: false);
//
// double totalWorkingHours = widget.isSender
// ? (widget.model.senderVisitTimers?.fold(0.0, (sum, item) => (sum ?? 0) + DateTime.parse(item.endDateTime!).difference(DateTime.parse(item.startDateTime!)).inSeconds) ?? 0)
// : (widget.model.receiverVisitTimers?.fold(0.0, (sum, item) => (sum ?? 0) + DateTime.parse(item.endDateTime!).difference(DateTime.parse(item.startDateTime!)).inSeconds) ?? 0);
//
// bool isTimerEnable = widget.isSender
// ? (!(_formModel.senderMachineStatusName?.toLowerCase().contains("close") ?? false) || !(_formModel.senderMachineStatusName?.toLowerCase().contains("complete") ?? false))
// : (!(_formModel.receiverMachineStatusName?.toLowerCase().contains("close") ?? false) || !(_formModel.receiverMachineStatusName?.toLowerCase().contains("complete") ?? false));
//
// return Scaffold(
// appBar: DefaultAppBar(title: context.translation.updateRequest),
// key: _scaffoldKey,
// body: SafeArea(
// child: LoadingManager(
// isLoading: _isLoading,
// isFailedLoading: false,
// stateCode: 200,
// onRefresh: () async {},
// child: Form(
// key: _formKey,
// child: Column(
// children: [
// SingleChildScrollView(
// padding: EdgeInsets.all(12 * AppStyle.getScaleFactor(context)),
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.stretch,
// children: [
// _buildCard(),
// 8.height,
// AppTextFormField(
// initialValue: widget.isSender ? _formModel.senderTravelingHours ?? "" : _formModel.receiverTravelingHours ?? "",
// labelText: context.translation.travelingHours,
// onChange: (text) {
// widget.isSender ? _formModel.senderTravelingHours = text : _formModel.receiverTravelingHours = text;
// },
// onSaved: (value) {
// widget.isSender ? _formModel.senderTravelingHours = value : _formModel.receiverTravelingHours = value;
// //_formModel?.workingHours = double.tryParse(value);
// // _formModel.travelingHours = value;
// },
// textInputType: TextInputType.number,
// //validator: (value) => Validator.isNumeric(value) ? null : "allow numbers only",
// ),
// 8.height,
// if (totalWorkingHours > 0.0) ...[
// Container(
// height: 50.toScreenHeight,
// padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth),
// alignment: Alignment.centerLeft,
// decoration: BoxDecoration(
// color: context.isDark ? AppColor.neutral40 : AppColor.background(context),
// borderRadius: BorderRadius.circular(10),
// boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)],
// ),
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// mainAxisAlignment: MainAxisAlignment.center,
// children: [
// Text(
// "Total Working Time",
// style: Theme.of(context).textTheme.bodySmall?.copyWith(color: context.isDark ? null : AppColor.neutral20, fontWeight: FontWeight.w500),
// ),
// Text(
// " ${formatDuration(totalWorkingHours.round())}",
// style: Theme.of(context).textTheme.bodyLarge,
// ),
// ],
// ),
// ),
// 8.height,
// ],
// AppTimer(
// label: context.translation.workingHours,
// timer: _formModel.tbsTimer,
// enabled: isTimerEnable,
// // enabled: widget.isSender ? _formModel.senderEndDate == null : (_formModel?.receiverMachineStatusName?.toLowerCase()?.contains("close") ?? false),
// timerProgress: (isRunning) {
// isTimerRunning = isRunning;
// },
// onChange: (timer) async {
// _formModel.tbsTimer = timer;
// return true;
// },
// ),
// 8.height,
// Consumer<AssetTransferStatusProvider>(builder: (context, snapshot, _) {
// return SingleItemDropDownMenu<Lookup, AssetTransferStatusProvider>(
// context: context,
// title: widget.isSender ? "Status Sender" : "Status Receiver", //,context.translation.reportStatus,
// initialValue:
// snapshot.items.firstWhere((element) => element.name == (widget.isSender ? _formModel.senderMachineStatusName : _formModel.receiverMachineStatusName), orElse: null),
// onSelect: (value) {
// if (value?.value == 4) {
// "Status cannot be change to ${value?.name}.".addTranslation.showToast;
// setState(() {});
// return;
// }
// if (widget.isSender) {
// _formModel.senderMachineStatusName = value?.name;
// _formModel.senderMachineStatusId = value?.id;
// } else {
// _formModel.receiverMachineStatusName = value?.name;
// _formModel.receiverMachineStatusId = value?.id;
// }
// setState(() {});
// },
// );
// }),
// 8.height,
// MultiFilesPicker(label: context.translation.attachImage, files: _files),
// 8.height,
// AppTextFormField(
// initialValue: widget.isSender ? _formModel.senderComment ?? "" : _formModel.receiverComment ?? "",
// labelText: context.translation.comments,
// textInputType: TextInputType.multiline,
// alignLabelWithHint: true,
// onSaved: (value) {
// widget.isSender ? _formModel.senderComment = value : _formModel.receiverComment = value;
// },
// ),
// 8.height,
// ESignature(
// title: "Signature",
// oldSignature: widget.isSender ? widget.model.senderEngSignature : widget.model.receiverEngSignature,
// newSignature: _signature,
// onSaved: (signature) {
// _signature = signature;
// if (signature == null || signature.isEmpty) return;
// widget.isSender
// ? _formModel.senderEngSignature = "${DateTime.now().toIso8601String()}.png|${base64Encode(signature)}"
// : _formModel.receiverEngSignature = "${DateTime.now().toIso8601String()}.png|${base64Encode(signature)}";
// },
// ),
// ],
// ),
// ).expanded,
// Padding(
// padding: const EdgeInsets.all(16.0),
// child: AppFilledButton(
// label: context.translation.update,
// onPressed: _update,
// ),
// ),
// ],
// ),
// ),
// ),
// ),
// );
// }
//
// _buildCard() {
// return Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// context.translation.transferDetails.heading5(context),
// 8.height,
// '${context.translation.assetName}: ${_formModel.assetName?.cleanupWhitespace.capitalizeFirstOfEach}'.bodyText(context),
// '${context.translation.requesterName}: ${_formModel.receiverEndUserName?.cleanupWhitespace.capitalizeFirstOfEach ?? ""}'.bodyText(context),
// ],
// ).toShadowContainer(context);
// }
//
// String formatDuration(int seconds) {
// int hours = seconds ~/ 3600;
// int minutes = (seconds % 3600) ~/ 60;
// int remainingSeconds = seconds % 60;
//
// String formattedDuration = '';
// if (hours > 0) {
// formattedDuration += '$hours hour${hours > 1 ? 's' : ''} ';
// }
// if (minutes > 0) {
// formattedDuration += '$minutes minute${minutes > 1 ? 's' : ''} ';
// }
// if (remainingSeconds > 0) {
// formattedDuration += '$remainingSeconds second${remainingSeconds > 1 ? 's' : ''} ';
// }
// if (formattedDuration.isEmpty) {
// formattedDuration = 'Less than a second';
// }
//
// return formattedDuration.trim();
// }
// }
//.....new design..
import 'dart:convert';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/asset_transfer_provider.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart';
import 'package:test_sa/controllers/providers/settings/setting_provider.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/widget_extensions.dart';
import 'package:test_sa/models/device/asset_transfer.dart';
import 'package:test_sa/models/device/asset_transfer_attachment.dart';
import 'package:test_sa/models/new_models/assigned_employee.dart';
import 'package:test_sa/models/new_models/assistant_employee.dart';
import 'package:test_sa/models/timer_model.dart';
import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
import 'package:test_sa/providers/asset_transfer/asset_transfer_status_provider.dart';
import 'package:test_sa/service_request_latest/utilities/service_request_utils.dart';
import 'package:test_sa/service_request_latest/views/components/action_button/footer_action_button.dart';
import 'package:test_sa/views/app_style/sizing.dart';
import 'package:test_sa/views/widgets/date_and_time/date_picker.dart';
import 'package:test_sa/views/widgets/images/multi_image_picker.dart';
import 'package:test_sa/views/widgets/loaders/loading_manager.dart';
import 'package:test_sa/views/widgets/status/report/service_report_assistant_employee_menu.dart';
import '../../../extensions/text_extensions.dart';
import '../../../models/lookup.dart';
import '../../../models/ppm/ppm.dart';
import '../../../new_views/app_style/app_color.dart';
import '../../../new_views/common_widgets/app_text_form_field.dart';
import '../../../new_views/common_widgets/default_app_bar.dart';
import '../../../new_views/common_widgets/single_item_drop_down_menu.dart';
import '../../widgets/e_signature/e_signature.dart';
import '../../widgets/timer/app_timer.dart';
class UpdateDeviceTransfer extends StatefulWidget {
@ -42,10 +375,7 @@ class UpdateDeviceTransfer extends StatefulWidget {
class _UpdateDeviceTransferState extends State<UpdateDeviceTransfer> {
final bool _isLoading = false;
bool _validate = false;
late UserProvider _userProvider;
late SettingProvider _settingProvider;
Uint8List? _signature;
late AssetTransferProvider _deviceTransferProvider;
final TextEditingController _requestedQuantityController = TextEditingController();
final AssetTransfer _formModel = AssetTransfer();
@ -54,27 +384,7 @@ class _UpdateDeviceTransferState extends State<UpdateDeviceTransfer> {
List<File> _files = [];
_update() async {
if (widget.isSender) {
_formModel.senderVisitTimers?.add(
VisitTimers(
id: 0,
startDateTime: _formModel.tbsTimer?.startAt?.toIso8601String(),
endDateTime: _formModel.tbsTimer?.endAt?.toIso8601String(),
workingHours: ((_formModel.tbsTimer?.durationInSecond ?? 0) / 60 / 60),
),
);
} else {
_formModel.receiverVisitTimers?.add(
VisitTimers(
id: 0,
startDateTime: _formModel.tbsTimer?.startAt?.toIso8601String(),
endDateTime: _formModel.tbsTimer?.endAt?.toIso8601String(),
workingHours: ((_formModel.tbsTimer?.durationInSecond ?? 0) / 60 / 60),
),
);
}
_update({required int status}) async {
if (_formModel.tbsTimer?.startAt == null) {
await Fluttertoast.showToast(msg: "Working Hours Required");
return false;
@ -83,19 +393,38 @@ class _UpdateDeviceTransferState extends State<UpdateDeviceTransfer> {
await Fluttertoast.showToast(msg: "Please Stop The Timer");
return false;
}
_validate = true;
if (!(_formKey.currentState!.validate())) {
setState(() {});
return false;
}
_formKey.currentState!.save();
_formModel.statusValue = status;
_formModel.isSender = widget.isSender;
if (widget.isSender) {
_formModel.senderAttachments = [];
_formModel.senderVisitTimers?.add(
VisitTimers(
id: 0,
startDateTime: _formModel.tbsTimer?.startAt?.toIso8601String(),
endDateTime: _formModel.tbsTimer?.endAt?.toIso8601String(),
workingHours: ((_formModel.tbsTimer?.durationInSecond ?? 0) / 60 / 60),
),
);
_formModel.assetTransferEngineerTimers = _formModel.senderVisitTimers;
} else {
_formModel.receiverAttachments = [];
_formModel.receiverVisitTimers?.add(
VisitTimers(
id: 0,
startDateTime: _formModel.tbsTimer?.startAt?.toIso8601String(),
endDateTime: _formModel.tbsTimer?.endAt?.toIso8601String(),
workingHours: ((_formModel.tbsTimer?.durationInSecond ?? 0) / 60 / 60),
),
);
_formModel.assetTransferEngineerTimers = _formModel.receiverVisitTimers;
}
try {
for (var file in _files) {
String attachmentName = file.path;
@ -103,17 +432,19 @@ class _UpdateDeviceTransferState extends State<UpdateDeviceTransfer> {
attachmentName = file.path.split("/").last;
attachmentName = "$attachmentName|${base64Encode(file.readAsBytesSync())}";
}
if (widget.isSender) {
_formModel.senderAttachments!.add(AssetTransferAttachment(id: 0, attachmentName: attachmentName));
_formModel.attachments = _formModel.senderAttachments;
} else {
_formModel.receiverAttachments!.add(AssetTransferAttachment(id: 0, attachmentName: attachmentName));
_formModel.attachments = _formModel.receiverAttachments;
}
}
} catch (error) {
print(error);
}
await _deviceTransferProvider.updateRequest(context, assetTransfer: _formModel, isSender: widget.isSender);
await _deviceTransferProvider.updateRequest(context, model: _formModel);
}
@override
@ -139,20 +470,16 @@ class _UpdateDeviceTransferState extends State<UpdateDeviceTransfer> {
@override
Widget build(BuildContext context) {
_userProvider = Provider.of<UserProvider>(context);
_settingProvider = Provider.of<SettingProvider>(context);
_deviceTransferProvider = Provider.of<AssetTransferProvider>(context, listen: false);
double totalWorkingHours = widget.isSender
? (widget.model.senderVisitTimers?.fold(0.0, (sum, item) => (sum ?? 0) + DateTime.parse(item.endDateTime!).difference(DateTime.parse(item.startDateTime!)).inSeconds) ?? 0)
: (widget.model.receiverVisitTimers?.fold(0.0, (sum, item) => (sum ?? 0) + DateTime.parse(item.endDateTime!).difference(DateTime.parse(item.startDateTime!)).inSeconds) ?? 0);
bool isTimerEnable = widget.isSender
? (!(_formModel.senderMachineStatusName?.toLowerCase().contains("close") ?? false) || !(_formModel.senderMachineStatusName?.toLowerCase().contains("complete") ?? false))
: (!(_formModel.receiverMachineStatusName?.toLowerCase().contains("close") ?? false) || !(_formModel.receiverMachineStatusName?.toLowerCase().contains("complete") ?? false));
return Scaffold(
appBar: DefaultAppBar(title: context.translation.updateRequest),
appBar: DefaultAppBar(title: context.translation.transferAsset),
key: _scaffoldKey,
body: SafeArea(
child: LoadingManager(
@ -167,122 +494,60 @@ class _UpdateDeviceTransferState extends State<UpdateDeviceTransfer> {
SingleChildScrollView(
padding: EdgeInsets.all(12 * AppStyle.getScaleFactor(context)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
_buildCard(),
8.height,
AppTextFormField(
initialValue: widget.isSender ? _formModel.senderTravelingHours ?? "" : _formModel.receiverTravelingHours ?? "",
labelText: context.translation.travelingHours,
onChange: (text) {
widget.isSender ? _formModel.senderTravelingHours = text : _formModel.receiverTravelingHours = text;
},
onSaved: (value) {
widget.isSender ? _formModel.senderTravelingHours = value : _formModel.receiverTravelingHours = value;
//_formModel?.workingHours = double.tryParse(value);
// _formModel.travelingHours = value;
},
textInputType: TextInputType.number,
//validator: (value) => Validator.isNumeric(value) ? null : "allow numbers only",
),
8.height,
if (totalWorkingHours > 0.0) ...[
Container(
height: 50.toScreenHeight,
padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth),
alignment: Alignment.centerLeft,
decoration: BoxDecoration(
color: context.isDark ? AppColor.neutral40 : AppColor.background(context),
borderRadius: BorderRadius.circular(10),
boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)],
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
_timerWidget(context, totalWorkingHours, isTimerEnable),
8.height,
AppTextFormField(
initialValue: widget.isSender ? _formModel.senderComment ?? "" : _formModel.receiverComment ?? "",
labelText: context.translation.technicalComment,
labelStyle: AppTextStyles.tinyFont.copyWith(color: AppColor.neutral20),
textInputType: TextInputType.multiline,
backgroundColor: AppColor.neutral100,
showShadow: false,
alignLabelWithHint: true,
onSaved: (value) {
widget.isSender ? _formModel.senderComment = value : _formModel.receiverComment = value;
},
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Total Working Time",
style: Theme.of(context).textTheme.bodySmall?.copyWith(color: context.isDark ? null : AppColor.neutral20, fontWeight: FontWeight.w500),
),
Text(
" ${formatDuration(totalWorkingHours.round())}",
style: Theme.of(context).textTheme.bodyLarge,
),
],
8.height,
MultiFilesPicker(
label: context.translation.attachFiles,
files: _files,
buttonColor: AppColor.black10,
onlyImages: false,
buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.neutral120),
),
),
8.height,
],
AppTimer(
label: context.translation.workingHours,
timer: _formModel.tbsTimer,
enabled: isTimerEnable,
// enabled: widget.isSender ? _formModel.senderEndDate == null : (_formModel?.receiverMachineStatusName?.toLowerCase()?.contains("close") ?? false),
timerProgress: (isRunning) {
isTimerRunning = isRunning;
},
onChange: (timer) async {
_formModel.tbsTimer = timer;
return true;
},
),
8.height,
Consumer<AssetTransferStatusProvider>(builder: (context, snapshot, _) {
return SingleItemDropDownMenu<Lookup, AssetTransferStatusProvider>(
context: context,
title: widget.isSender ? "Status Sender" : "Status Receiver", //,context.translation.reportStatus,
initialValue:
snapshot.items.firstWhere((element) => element.name == (widget.isSender ? _formModel.senderMachineStatusName : _formModel.receiverMachineStatusName), orElse: null),
onSelect: (value) {
if (value?.value == 4) {
"Status cannot be change to ${value?.name}.".addTranslation.showToast;
setState(() {});
return;
}
if (widget.isSender) {
_formModel.senderMachineStatusName = value?.name;
_formModel.senderMachineStatusId = value?.id;
} else {
_formModel.receiverMachineStatusName = value?.name;
_formModel.receiverMachineStatusId = value?.id;
}
setState(() {});
},
);
}),
8.height,
MultiFilesPicker(label: context.translation.attachImage, files: _files),
8.height,
AppTextFormField(
initialValue: widget.isSender ? _formModel.senderComment ?? "" : _formModel.receiverComment ?? "",
labelText: context.translation.comments,
textInputType: TextInputType.multiline,
alignLabelWithHint: true,
onSaved: (value) {
widget.isSender ? _formModel.senderComment = value : _formModel.receiverComment = value;
},
),
8.height,
ESignature(
title: "Signature",
oldSignature: widget.isSender ? widget.model.senderEngSignature : widget.model.receiverEngSignature,
newSignature: _signature,
onSaved: (signature) {
_signature = signature;
if (signature == null || signature.isEmpty) return;
widget.isSender
? _formModel.senderEngSignature = "${DateTime.now().toIso8601String()}.png|${base64Encode(signature)}"
: _formModel.receiverEngSignature = "${DateTime.now().toIso8601String()}.png|${base64Encode(signature)}";
},
),
8.height,
],
).toShadowContainer(context),
16.height,
AssistantEmployeeCard(
isSender: widget.isSender,
formModel: _formModel,
).toShadowContainer(context, paddingObject: const EdgeInsets.symmetric(horizontal: 16)),
],
),
).expanded,
Padding(
padding: const EdgeInsets.all(16.0),
child: AppFilledButton(
label: context.translation.update,
onPressed: _update,
FooterActionButton.footerContainer(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
AppFilledButton(
label: context.translation.save,
buttonColor: AppColor.white60,
textColor: AppColor.black10,
onPressed: () => _update(status: 0),
).expanded,
12.width,
AppFilledButton(
label: context.translation.complete,
buttonColor: AppColor.primary10,
onPressed: () => _update(status: 1),
).expanded,
],
),
),
],
@ -293,37 +558,251 @@ class _UpdateDeviceTransferState extends State<UpdateDeviceTransfer> {
);
}
_buildCard() {
void updateTimer({TimerModel? timer}) {
_formModel.tbsTimer = timer;
if (timer?.startAt != null && timer?.endAt != null) {
_formModel.timerModelList = _formModel.timerModelList ?? [];
_formModel.timerModelList!.add(timer!);
}
// notifyListeners();
}
Widget _timerWidget(BuildContext context, double totalWorkingHours, bool isTimerEnable) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
context.translation.transferDetails.heading5(context),
8.height,
'${context.translation.assetName}: ${_formModel.assetName?.cleanupWhitespace.capitalizeFirstOfEach}'.bodyText(context),
'${context.translation.requesterName}: ${_formModel.receiverEndUserName?.cleanupWhitespace.capitalizeFirstOfEach ?? ""}'.bodyText(context),
AppTimer(
label: context.translation.workingHours,
timer: _formModel.tbsTimer,
width: double.infinity,
enabled: isTimerEnable,
decoration: BoxDecoration(
color: AppColor.neutral100,
borderRadius: BorderRadius.circular(10),
),
timerProgress: (isRunning) {},
onChange: (timer) async {
updateTimer(timer: timer);
return true;
},
),
if (totalWorkingHours > 0.0) ...[
12.height,
Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: [
'Total Working Time:'.bodyText2(context).custom(color: AppColor.neutral120),
8.width,
Text(
ServiceRequestUtils.formatTimerDuration(totalWorkingHours.round()),
style: AppTextStyles.bodyText.copyWith(color: AppColor.neutral50, fontWeight: FontWeight.w600),
),
],
),
],
],
).toShadowContainer(context);
);
}
}
String formatDuration(int seconds) {
int hours = seconds ~/ 3600;
int minutes = (seconds % 3600) ~/ 60;
int remainingSeconds = seconds % 60;
class AssistantEmployeeCard extends StatefulWidget {
bool? isSender = false;
AssetTransfer? formModel;
String formattedDuration = '';
if (hours > 0) {
formattedDuration += '$hours hour${hours > 1 ? 's' : ''} ';
}
if (minutes > 0) {
formattedDuration += '$minutes minute${minutes > 1 ? 's' : ''} ';
}
if (remainingSeconds > 0) {
formattedDuration += '$remainingSeconds second${remainingSeconds > 1 ? 's' : ''} ';
AssistantEmployeeCard({super.key, this.isSender, this.formModel});
@override
State<AssistantEmployeeCard> createState() => _AssistantEmployeeCardState();
}
class _AssistantEmployeeCardState extends State<AssistantEmployeeCard> {
final TextEditingController _workingHoursController = TextEditingController(text: '');
bool isCurrentUserIsAssistantEmp = false;
bool isExpanded = false;
List<AssetTransferAssistantEmployees> employeeList = [];
AssistantEmployees selectedEmployee = AssistantEmployees();
@override
void initState() {
WidgetsBinding.instance.addPostFrameCallback((_) {
getInitialData();
});
super.initState();
}
Future<void> getInitialData() async {
if (widget.isSender!) {
employeeList = widget.formModel!.assetTransferAssistantEmployeesSender ?? [];
} else {
employeeList = widget.formModel!.assetTransferAssistantEmployeesReceiver ?? [];
}
if (formattedDuration.isEmpty) {
formattedDuration = 'Less than a second';
widget.formModel?.modelAssistantEmployees = employeeList.isEmpty ? AssetTransferAssistantEmployees() : employeeList[0];
AssignedEmployee? assignedUser = AssignedEmployee();
if (employeeList.isNotEmpty) {
assignedUser = AssignedEmployee(
id: employeeList[0].employeeId,
name: employeeList[0].employeeName,
);
}
selectedEmployee = AssistantEmployees(userId: assignedUser.id, user: assignedUser);
}
@override
void dispose() {
_workingHoursController.dispose();
super.dispose();
}
return formattedDuration.trim();
@override
Widget build(BuildContext context) {
return Column(
children: [
SizedBox(
height: 56.toScreenHeight,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
context.translation.assistantEmployee.heading6(context).custom(color: AppColor.black10),
Icon(isExpanded ? Icons.keyboard_arrow_up_rounded : Icons.keyboard_arrow_down_rounded),
],
),
).onPress(() {
setState(() {
isExpanded = !isExpanded;
});
}),
isExpanded
? Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
ServiceReportAssistantEmployeeMenu(
title: context.translation.select,
backgroundColor: AppColor.neutral100,
assetId: widget.formModel?.assetId ?? 0,
initialValue: selectedEmployee,
onSelect: (employee) {
if (employee == null) {
widget.formModel?.assistantEmployees = [];
} else {
selectedEmployee = employee;
widget.formModel?.assistantEmployees = [employee.copyWith(id: 0)];
widget.formModel?.modelAssistantEmployees?.employeeId = employee.user?.id;
}
},
),
8.height,
Row(
mainAxisSize: MainAxisSize.min,
children: [
ADatePicker(
label: context.translation.startTime,
hideShadow: true,
backgroundColor: AppColor.neutral100,
date: widget.formModel?.modelAssistantEmployees?.startDate,
formatDateWithTime: true,
onDatePicker: (selectedDate) {
showTimePicker(
context: context,
initialTime: TimeOfDay.now(),
).then((selectedTime) {
// Handle the selected date and time here.
if (selectedTime != null) {
DateTime selectedDateTime = DateTime(
selectedDate.year,
selectedDate.month,
selectedDate.day,
selectedTime.hour,
selectedTime.minute,
);
widget.formModel?.modelAssistantEmployees?.startDate = selectedDateTime;
ServiceRequestUtils.calculateAndAssignWorkingHours(
startTime: widget.formModel?.modelAssistantEmployees?.startDate,
endTime: widget.formModel?.modelAssistantEmployees?.endDate,
workingHoursController: _workingHoursController,
updateModel: (hours) {
widget.formModel?.modelAssistantEmployees?.workingHours = hours;
});
setState(() {});
}
});
},
).expanded,
8.width,
ADatePicker(
label: context.translation.endTime,
hideShadow: true,
backgroundColor: AppColor.neutral100,
date: widget.formModel?.modelAssistantEmployees?.endDate,
formatDateWithTime: true,
onDatePicker: (selectedDate) {
showTimePicker(
context: context,
initialTime: TimeOfDay.now(),
).then((selectedTime) {
if (selectedTime != null) {
DateTime selectedDateTime = DateTime(
selectedDate.year,
selectedDate.month,
selectedDate.day,
selectedTime.hour,
selectedTime.minute,
);
if (widget.formModel?.modelAssistantEmployees?.startDate != null && selectedDateTime.isBefore(widget.formModel!.modelAssistantEmployees!.startDate!)) {
"End Date time must be greater then start date".showToast;
return;
}
widget.formModel?.modelAssistantEmployees?.endDate = selectedDateTime;
ServiceRequestUtils.calculateAndAssignWorkingHours(
startTime: widget.formModel?.modelAssistantEmployees?.startDate,
endTime: widget.formModel?.modelAssistantEmployees?.endDate,
workingHoursController: _workingHoursController,
updateModel: (hours) {
widget.formModel?.modelAssistantEmployees?.workingHours = hours;
});
setState(() {});
}
});
},
).expanded,
],
),
8.height,
AppTextFormField(
labelText: context.translation.workingHours,
backgroundColor: AppColor.neutral80,
controller: _workingHoursController,
suffixIcon: "clock".toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null).paddingOnly(end: 16),
initialValue: widget.formModel?.modelAssistantEmployees?.workingHours != null ? widget.formModel?.modelAssistantEmployees?.workingHours.toString() : '',
textAlign: TextAlign.center,
labelStyle: AppTextStyles.textFieldLabelStyle,
enable: false,
showShadow: false,
style: Theme.of(context).textTheme.titleMedium,
),
8.height,
AppTextFormField(
initialValue: widget.formModel?.modelAssistantEmployees?.techComment,
labelText: context.translation.technicalComment,
backgroundColor: AppColor.neutral100,
showShadow: false,
labelStyle: AppTextStyles.textFieldLabelStyle,
alignLabelWithHint: true,
textInputType: TextInputType.multiline,
onChange: (value) {
widget.formModel?.modelAssistantEmployees?.techComment = value;
},
onSaved: (value) {
widget.formModel?.modelAssistantEmployees?.techComment = value;
},
),
16.height,
],
)
: const SizedBox(),
],
);
}
}

@ -1,3 +1,5 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/gas_refill_comments.dart';
@ -7,7 +9,10 @@ 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/widget_extensions.dart';
import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
import 'package:test_sa/views/pages/user/gas_refill/gas_refill_form.dart';
import 'package:test_sa/views/pages/user/gas_refill/request_gas_refill.dart';
import 'package:test_sa/views/widgets/images/multi_image_picker.dart';
import 'package:test_sa/views/widgets/loaders/app_loading.dart';
import 'package:test_sa/views/widgets/loaders/no_data_found.dart';
@ -30,13 +35,14 @@ class GasRefillDetailsPage extends StatefulWidget {
}
class _GasRefillDetailsPageState extends State<GasRefillDetailsPage> {
GasRefillModel _model = GasRefillModel(gazRefillDetails: []);
GasRefillModel _model = GasRefillModel(gasRefillDetails: []);
late UserProvider _userProvider;
late GasRefillProvider gasRefillProvider;
final bool _isLoading = false;
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
List<File> _attachments = [];
@override
void initState() {
@ -61,6 +67,8 @@ class _GasRefillDetailsPageState extends State<GasRefillDetailsPage> {
return const ALoading();
} else if (snap.hasData) {
_model = snap.data as GasRefillModel;
_attachments = _model.gasRefillAttachments?.map((e) => File(e.attachmentName ?? '')).toList() ?? [];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -68,6 +76,14 @@ class _GasRefillDetailsPageState extends State<GasRefillDetailsPage> {
padding: const EdgeInsets.all(16),
child: informationCard(_model),
).expanded,
if (_userProvider.user!.type == UsersTypes.engineer && (_model.status!.id! != 5833))//TODO need to check this value for complete status.
AppFilledButton(
onPressed: () async {
await Navigator.of(context).push(MaterialPageRoute(builder: (_) => GasRefillForm(gasRefillModel: _model)));
// getVisitData();
},
label: context.translation.updateRequest,
).paddingAll(16)
],
);
}
@ -109,133 +125,124 @@ class _GasRefillDetailsPageState extends State<GasRefillDetailsPage> {
context.translation.gasRefillRequest.heading5(context),
8.height,
'${context.translation.gasRequest}: ${gasRefillModel.gazRefillDetails![0].gasType?.name}'.bodyText(context),
'${context.translation.cylinderType}: ${gasRefillModel.gazRefillDetails![0].cylinderType?.name}'.bodyText(context),
'${context.translation.cylinderSize}: ${gasRefillModel.gazRefillDetails![0].cylinderSize?.name}'.bodyText(context),
'${context.translation.gasRequest}: ${gasRefillModel.gasRefillDetails![0].gasType?.name}'.bodyText(context),
'${context.translation.cylinderType}: ${gasRefillModel.gasRefillDetails![0].cylinderType?.name}'.bodyText(context),
'${context.translation.cylinderSize}: ${gasRefillModel.gasRefillDetails![0].cylinderSize?.name}'.bodyText(context),
'${context.translation.site}: ${gasRefillModel.site?.name?.cleanupWhitespace.capitalizeFirstOfEach}'.bodyText(context),
'${context.translation.department}: ${gasRefillModel.department?.name?.cleanupWhitespace.capitalizeFirstOfEach}'.bodyText(context),
'${context.translation.requestNo}: ${gasRefillModel.gazRefillNo}'.bodyText(context),
'${context.translation.requestNo}: ${gasRefillModel.gasRefillNo}'.bodyText(context),
//TODO need to confirm where to display this new data...
infoText(label:context.translation.gasRequest ,value:gasRefillModel.extensionNo ),
infoText(label:context.translation.employeeId ,value:gasRefillModel.employeeId ),
infoText(label:context.translation.name ,value:gasRefillModel.name ),
infoText(label:context.translation.createdDate ,value:gasRefillModel.createdDate?.toInitialVisitCardFormat),
infoText(label: context.translation.gasRequest, value: gasRefillModel.extensionNo),
infoText(label: context.translation.employeeId, value: gasRefillModel.employeeId),
infoText(label: context.translation.name, value: gasRefillModel.name),
infoText(label: context.translation.createdDate, value: gasRefillModel.createdDate?.toInitialVisitCardFormat),
const Divider().defaultStyle(context),
'${context.translation.requestedQuantity}: ${gasRefillModel.gazRefillDetails![0].requestedQty ?? 0}'.bodyText(context),
'${context.translation.deliveredQuantity}: ${gasRefillModel.gazRefillDetails![0].deliverdQty ?? 0}'.bodyText(context),
'${context.translation.requestedQuantity}: ${gasRefillModel.gasRefillDetails![0].requestedQty ?? 0}'.bodyText(context),
'${context.translation.deliveredQuantity}: ${gasRefillModel.gasRefillDetails![0].deliverdQty ?? 0}'.bodyText(context),
8.height,
if (gasRefillModel.comment?.isNotEmpty ?? false) ...[
const Divider().defaultStyle(context),
gasRefillModel.comment!.bodyText(context),
8.height,
]
],
).expanded,
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
if (_userProvider.user!.type == UsersTypes.engineer && (gasRefillModel.status?.value ?? 0) != 2)
"edit".toSvgAsset(height: 48, width: 48).onPress(
() async {
_model.fromGasRefillModel(gasRefillModel);
// setState(() {});
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => RequestGasRefill(gasRefillModel: gasRefillModel),
),
).then((value) {
if (value != null) {
_model = value;
setState(() {});
}
});
},
],
if (_attachments.isNotEmpty) ...[
const Divider().defaultStyle(context),
context.translation.attachments.bodyText(context),
8.height,
MultiFilesPicker(
label: context.translation.attachments,
files: _attachments,
enabled: false,
onlyImages: false,
),
if (_userProvider.user!.type == UsersTypes.engineer && (gasRefillModel.status?.value ?? 0) != 2) 8.height,
Text(
(widget.date ?? gasRefillModel.expectedDate)?.toServiceRequestCardFormat ?? "",
textAlign: TextAlign.end,
style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50),
),
12.height,
],
],
).expanded,
if (_userProvider.user!.type == UsersTypes.engineer && (gasRefillModel.status?.value ?? 0) != 2) 8.height,
Text(
(widget.date ?? gasRefillModel.expectedDate)?.toServiceRequestCardFormat ?? "",
textAlign: TextAlign.end,
style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50),
),
],
).paddingOnly(top: 16, start: 16, end: 16),
/// TBD
(_userProvider.user!.type == UsersTypes.normal_user
? Container(
height: 50,
padding: const EdgeInsets.only(left: 16, right: 16),
alignment: Alignment.center,
width: double.infinity,
decoration: ShapeDecoration(
color: context.isDark ? AppColor.neutral50 : AppColor.neutral30,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(14),
bottomRight: Radius.circular(14),
),
),
),
child: Row(
children: [
Text(
'${context.translation.commentHere}...',
style: AppTextStyles.heading6.copyWith(
color: (context.isDark ? AppColor.neutral30 : AppColor.neutral50).withOpacity(.6),
),
).expanded,
"comment_send".toSvgAsset(width: 24, color: context.isDark ? AppColor.primary50 : AppColor.primary70),
],
),
)
: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Divider().defaultStyle(context),
8.height,
Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
context.translation.viewComments,
style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context)),
),
4.width,
Icon(
Icons.arrow_forward,
color: AppColor.blueStatus(context),
size: 14,
)
],
),
],
).paddingOnly(bottom: 16, start: 16, end: 16))
.onPress(() {
showModalBottomSheet(
context: context,
useSafeArea: true,
isScrollControlled: true,
useRootNavigator: true,
backgroundColor: Colors.transparent,
builder: (context) => GasRefillCommentsBottomSheet(requestId: gasRefillModel.id.toString()),
);
}),
// (_userProvider.user!.type == UsersTypes.normal_user
// ? Container(
// height: 50,
// padding: const EdgeInsets.only(left: 16, right: 16),
// alignment: Alignment.center,
// width: double.infinity,
// decoration: ShapeDecoration(
// color: context.isDark ? AppColor.neutral50 : AppColor.neutral30,
// shape: const RoundedRectangleBorder(
// borderRadius: BorderRadius.only(
// bottomLeft: Radius.circular(14),
// bottomRight: Radius.circular(14),
// ),
// ),
// ),
// child: Row(
// children: [
// Text(
// '${context.translation.commentHere}...',
// style: AppTextStyles.heading6.copyWith(
// color: (context.isDark ? AppColor.neutral30 : AppColor.neutral50).withOpacity(.6),
// ),
// ).expanded,
// "comment_send".toSvgAsset(width: 24, color: context.isDark ? AppColor.primary50 : AppColor.primary70),
// ],
// ),
// )
// : Column(
// mainAxisSize: MainAxisSize.min,
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// const Divider().defaultStyle(context),
// 8.height,
// Row(
// mainAxisSize: MainAxisSize.min,
// children: [
// Text(
// context.translation.viewComments,
// style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context)),
// ),
// 4.width,
// Icon(
// Icons.arrow_forward,
// color: AppColor.blueStatus(context),
// size: 14,
// )
// ],
// ),
// ],
// ).paddingOnly(bottom: 16, start: 16, end: 16))
// .onPress(() {
// showModalBottomSheet(
// context: context,
// useSafeArea: true,
// isScrollControlled: true,
// useRootNavigator: true,
// backgroundColor: Colors.transparent,
// builder: (context) => GasRefillCommentsBottomSheet(requestId: gasRefillModel.id.toString()),
// );
// }),
],
).toShadowContainer(context, padding: 0);
}
Widget infoText({String ?label,String ?value,}){
if(value==null||value.isEmpty){
return const SizedBox();
}
else {
Widget infoText({
String? label,
String? value,
}) {
if (value == null || value.isEmpty) {
return const SizedBox();
} else {
return '$label: $value'.bodyText(context);
}
}
}

@ -0,0 +1,385 @@
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/all_requests_provider.dart';
import 'package:test_sa/controllers/providers/api/gas_refill_provider.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart';
import 'package:test_sa/controllers/providers/settings/setting_provider.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/models/timer_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_lazy_loading.dart';
import 'package:test_sa/providers/loading_list_notifier.dart';
import 'package:test_sa/service_request_latest/utilities/service_request_utils.dart';
import 'package:test_sa/service_request_latest/views/components/action_button/footer_action_button.dart';
import 'package:test_sa/views/widgets/images/multi_image_picker.dart';
import 'package:test_sa/views/widgets/loaders/loading_manager.dart';
import '../../../../extensions/text_extensions.dart';
import '../../../../models/new_models/gas_refill_model.dart';
import '../../../../new_views/common_widgets/app_text_form_field.dart';
import '../../../../new_views/common_widgets/default_app_bar.dart';
import '../../../../new_views/common_widgets/single_item_drop_down_menu.dart';
import '../../../widgets/timer/app_timer.dart';
class GasRefillForm extends StatefulWidget {
static const String id = "/gas-refill-form";
final GasRefillModel? gasRefillModel;
const GasRefillForm({this.gasRefillModel, Key? key}) : super(key: key);
@override
State<GasRefillForm> createState() => _GasRefillFormState();
}
class _GasRefillFormState extends State<GasRefillForm> {
final bool _isLoading = false;
bool _validate = false;
Uint8List? _engineerSignature;
Uint8List? _nurseSignature;
double totalWorkingHours = 0.0;
late UserProvider _userProvider;
late SettingProvider _settingProvider;
GasRefillProvider? _gasRefillProvider;
GasRefillDetails _currentDetails = GasRefillDetails();
final TextEditingController _deliveredQuantityController = TextEditingController();
final TextEditingController _commentController = TextEditingController();
final TextEditingController _workingHoursController = TextEditingController();
final GasRefillModel _formModel = GasRefillModel(gasRefillDetails: []);
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final GlobalKey _DetailsKey = GlobalKey<FormState>();
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
bool _firstTime = true;
Lookup? _deliveredQuantity;
List<File> _attachments = [];
static List<Lookup> deliveredQuantity = [
Lookup(name: "1", id: 1, value: 1),
Lookup(name: "2", id: 2, value: 2),
Lookup(name: "3", id: 3, value: 3),
Lookup(name: "4", id: 4, value: 4),
Lookup(name: "5", id: 5, value: 5)
];
@override
void initState() {
super.initState();
_gasRefillProvider ??= Provider.of<GasRefillProvider>(context, listen: false);
if (widget.gasRefillModel != null) {
_formModel.fromGasRefillModel(widget.gasRefillModel!);
totalWorkingHours =
_formModel.gasRefillTimers?.fold(0.0, (sum, item) => (sum ?? 0) + DateTime.parse(item.endDate!).difference(DateTime.parse(item.startDate!)).inSeconds) ?? 0;
_commentController.text = _formModel.techComment ?? "";
try {
_deliveredQuantity = deliveredQuantity.singleWhere((element) => element.value == _formModel.gasRefillDetails![0].deliverdQty);
_currentDetails.deliverdQty = _deliveredQuantity!.value;
} catch (ex) {}
}
if (_formModel.gasRefillAttachments != null && _formModel.gasRefillAttachments!.isNotEmpty) {
_attachments.addAll(_formModel.gasRefillAttachments!.map((e) => File(e.attachmentName!)).toList());
}
}
@override
void setState(VoidCallback fn) {
if (mounted) super.setState(() {});
}
_onSubmit(BuildContext context, int status) async {
if (_formModel.timer?.startAt == null) {
await Fluttertoast.showToast(msg: "Working Hours Required");
return false;
}
if (_formModel.timer?.endAt == null) {
await Fluttertoast.showToast(msg: "Please Stop The Timer");
return false;
}
if (_currentDetails.deliverdQty == null) {
await Fluttertoast.showToast(msg: "Delivered Quantity is Required");
return false;
}
_formModel.gasRefillDetails = [];
_formModel.gasRefillDetails?.add(_currentDetails);
showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
_formModel.gasRefillTimers = _formModel.gasRefillTimers ?? [];
_formModel.timerModelList?.forEach((timer) {
int durationInSecond = timer.endAt!.difference(timer.startAt!).inSeconds;
_formModel.gasRefillTimers?.add(
GasRefillTimer(
id: 0,
startDate: timer.startAt!.toIso8601String(), // Handle potential null
endDate: timer.endAt?.toIso8601String(), // Handle potential null
workingHours: ((durationInSecond) / 60 / 60),
),
);
});
_formModel.gasRefillAttachments = [];
for (var item in _attachments) {
_formModel.gasRefillAttachments
?.add(GasRefillAttachments(id: 0,gasRefillId: _formModel.id??0, attachmentName: ServiceRequestUtils.isLocalUrl(item.path) ? "${item.path.split("/").last}|${base64Encode(item.readAsBytesSync())}" : item.path));
}
await _gasRefillProvider?.updateGasRefill(status: status, model: _formModel).whenComplete(() {
if (status == 1) {
AllRequestsProvider allRequestsProvider = Provider.of<AllRequestsProvider>(context, listen: false);
// when click complete then this request remove from the list and status changes to closed..
_gasRefillProvider?.reset();
allRequestsProvider.getAllRequests(context, typeTransaction: 2);
}
Navigator.pop(context);
Navigator.pop(context);
});
}
@override
void dispose() {
_deliveredQuantityController.dispose();
_commentController.dispose();
_workingHoursController.dispose();
super.dispose();
}
void updateTimer({TimerModel? timer}) {
_formModel.timer = timer;
if (timer?.startAt != null && timer?.endAt != null) {
_formModel.timerModelList = _formModel.timerModelList ?? [];
_formModel.timerModelList!.add(timer!);
}
// notifyListeners();
}
@override
Widget build(BuildContext context) {
_userProvider = Provider.of<UserProvider>(context);
_settingProvider = Provider.of<SettingProvider>(context);
if (_firstTime) {
String? clientName;
if (widget.gasRefillModel != null) {
//_formModel.status = widget.gasRefillModel?.status ?? Lookup(value: 0);
_gasRefillProvider!.expectedDateTime = DateTime.tryParse(_formModel.expectedDate ?? "");
_formModel.timer = TimerModel(startAt: DateTime.tryParse(widget.gasRefillModel?.startDate ?? ""), endAt: DateTime.tryParse(widget.gasRefillModel?.endDate ?? ""));
clientName = _formModel.site?.custName;
} else {
_formModel.timer = null;
clientName = _userProvider.user?.clientName;
}
// HospitalsProvider().getHospitalsListByVal(searchVal: clientName ?? '').then((value) {
// _gasRefillProvider!.hospital = value.firstWhere((element) => element.name == clientName, orElse: null);
// _gasRefillProvider!.building = _gasRefillProvider!.hospital?.buildings?.firstWhere((element) => element.name == widget.gasRefillModel?.building?.name, orElse: null);
// _gasRefillProvider!.floor = _gasRefillProvider!.building?.floors?.firstWhere((element) => element.name == widget.gasRefillModel?.floor?.name, orElse: null);
// _gasRefillProvider!.department = _gasRefillProvider!.floor?.departments?.firstWhere((element) => element.name == widget.gasRefillModel?.department?.departmentName, orElse: null);
// _firstTime = false;
// setState(() {});
// });
}
double totalWorkingHours = _formModel.gasRefillTimers?.fold(0.0, (sum, item) => (sum ?? 0) + DateTime.parse(item.endDate!).difference(DateTime.parse(item.startDate!)).inSeconds) ?? 0;
return Scaffold(
appBar: DefaultAppBar(title: context.translation.gasRefill),
key: _scaffoldKey,
body: Form(
key: _formKey,
child: SafeArea(
child: LoadingManager(
isLoading: _isLoading,
isFailedLoading: false,
stateCode: 200,
onRefresh: () async {},
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// context.translation.gasRefill.heading5(context),
// 8.height,
// '${context.translation.gasRequest}: ${widget.gasRefillModel!.gasRefillDetails![0].gasType!.name}'.bodyText(context),
// '${context.translation.cylinderType}: ${widget.gasRefillModel!.gasRefillDetails![0].cylinderType!.name}'.bodyText(context),
// '${context.translation.cylinderSize}: ${widget.gasRefillModel!.gasRefillDetails![0].cylinderSize!.name}'.bodyText(context),
// '${context.translation.quantity}: ${widget.gasRefillModel!.gasRefillDetails![0].requestedQty ?? 0}'.bodyText(context),
// '${context.translation.site}: ${widget.gasRefillModel!.site?.name}'.bodyText(context),
// ],
// ).toShadowContainer(context),
8.height,
SingleItemDropDownMenu<Lookup, NullableLoadingProvider>(
context: context,
title: context.translation.quantity,
backgroundColor: AppColor.neutral100,
showShadow: false,
initialValue: _deliveredQuantity,
staticData: deliveredQuantity,
onSelect: (value) {
_deliveredQuantity = value;
_currentDetails.deliverdQty = value!.value;
},
),
8.height,
// AppTextFormField(
// initialValue: _formModel.gasRefillDetails?[0].deliverdQty?.toString() ?? "",
// labelText: context.translation.deliveredQuantity,
// onSaved: (value) {
// _currentDetails.deliverdQty = double.tryParse(value);
// },
// textInputType: TextInputType.number,
// controller: _deliveredQuantityController,
// validator: (value) => value == null || value.isEmpty
// ? context.translation.requiredField
// : Validator.isNumeric(value)
// ? null
// : context.translation.onlyNumbers,
// ),
// 8.height,
_timerWidget(context, totalWorkingHours),
8.height,
// SingleItemDropDownMenu<Lookup, GasStatusProvider>(
// context: context,
// title: context.translation.requestStatus,
// initialValue: _formModel.status,
// onSelect: (value) {
// if (value?.value == 0) {
// "Status cannot be change to ${value?.name}.".addTranslation.showToast;
// setState(() {});
// return;
// }
// if (value != null) {
// _formModel.status = value;
// }
// },
// ),
// 8.height,
// 8.height,
/// TBD
AppTextFormField(
labelText: context.translation.technicalComment,
textInputType: TextInputType.multiline,
alignLabelWithHint: true,
backgroundColor: AppColor.neutral100,
showShadow: false,
controller: _commentController,
onChange: (value) {
_formModel.techComment = value;
},
onSaved: (value) {},
),
16.height,
MultiFilesPicker(
label: context.translation.attachFiles,
files: _attachments,
buttonColor: AppColor.black10,
onlyImages: false,
buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.neutral120),
),
8.height,
// ESignature(
// title: "Engineer Signature",
// oldSignature: widget.gasRefillModel?.engSignature,
// newSignature: _engineerSignature,
// onSaved: (signature) {
// _engineerSignature = signature;
// if (signature == null || signature.isEmpty) return;
// _formModel.engSignature = "${DateTime.now().toIso8601String()}.png|${base64Encode(signature)}";
// //base64Encode(signature);
// },
// ),
// 8.height,
// ESignature(
// title: "Nurse Signature",
// oldSignature: widget.gasRefillModel?.nurseSignature,
// newSignature: _nurseSignature,
// onSaved: (signature) {
// _nurseSignature = signature;
// if (signature == null || signature.isEmpty) return;
// _formModel.nurseSignature = "${DateTime.now().toIso8601String()}.png|${base64Encode(signature)}";
// //base64Encode(signature);
// },
// ),
],
).toShadowContainer(context),
).expanded,
FooterActionButton.footerContainer(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
AppFilledButton(
label: context.translation.save,
buttonColor: AppColor.white60,
textColor: AppColor.black10,
onPressed: () => _onSubmit(context, 0),
).expanded,
12.width,
AppFilledButton(
label: context.translation.complete,
buttonColor: AppColor.primary10,
onPressed: () => _onSubmit(context, 1),
).expanded,
],
),
),
],
)),
),
),
);
}
Widget _timerWidget(BuildContext context, double totalWorkingHours) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
AppTimer(
label: context.translation.workingHours,
timer: _formModel.timer,
//TODO need to fix this..
// enabled: _formModel.endDate == null,
width: double.infinity,
decoration: BoxDecoration(
color: AppColor.neutral100,
borderRadius: BorderRadius.circular(10),
),
timerProgress: (isRunning) {},
onChange: (timer) async {
updateTimer(timer: timer);
return true;
},
),
if (totalWorkingHours > 0.0) ...[
12.height,
Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: [
'Total Working Time:'.bodyText2(context).custom(color: AppColor.neutral120),
8.width,
Text(
ServiceRequestUtils.formatTimerDuration(totalWorkingHours.round()),
style: AppTextStyles.bodyText.copyWith(color: AppColor.neutral50, fontWeight: FontWeight.w600),
),
],
),
],
],
);
}
}

@ -8,7 +8,6 @@ import 'package:test_sa/controllers/api_routes/http_status_manger.dart';
import 'package:test_sa/controllers/providers/api/gas_refill_provider.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart';
import 'package:test_sa/controllers/providers/settings/setting_provider.dart';
import 'package:test_sa/controllers/validator/validator.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';
@ -53,13 +52,12 @@ class _RequestGasRefillState extends State<RequestGasRefill> {
final TextEditingController _commentController = TextEditingController();
final TextEditingController _workingHoursController = TextEditingController();
final GasRefillModel _formModel = GasRefillModel(gazRefillDetails: []);
final GasRefillModel _formModel = GasRefillModel(gasRefillDetails: []);
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final GlobalKey _DetailsKey = GlobalKey<FormState>();
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
bool _firstTime = true;
Lookup? _deliveredQuantity;
static List<Lookup> deliveredQuantity = [
@ -77,7 +75,7 @@ class _RequestGasRefillState extends State<RequestGasRefill> {
_formModel.fromGasRefillModel(widget.gasRefillModel!);
_commentController.text = _formModel.comment ?? "";
try {
_deliveredQuantity = deliveredQuantity.singleWhere((element) => element.value == _formModel.gazRefillDetails![0].deliverdQty);
_deliveredQuantity = deliveredQuantity.singleWhere((element) => element.value == _formModel.gasRefillDetails![0].deliverdQty);
_currentDetails.deliverdQty = _deliveredQuantity!.value;
} catch (ex) {}
}
@ -101,7 +99,7 @@ class _RequestGasRefillState extends State<RequestGasRefill> {
await Fluttertoast.showToast(msg: "Please Stop The Timer");
return false;
}
if (_formModel.gazRefillDetails?.isNotEmpty ?? false) {
if (_formModel.gasRefillDetails?.isNotEmpty ?? false) {
if (!(await _addNewModel(context))) return;
}
@ -135,7 +133,7 @@ class _RequestGasRefillState extends State<RequestGasRefill> {
}
}
bool _addNewModel(BuildContext context) {
bool _addNewModel(BuildContext context) {
_validate = true;
if (_currentDetails.deliverdQty == null) {
Fluttertoast.showToast(msg: "${context.translation.youHaveToSelect} ${context.translation.quantity}");
@ -147,15 +145,15 @@ class _RequestGasRefillState extends State<RequestGasRefill> {
// return false;
// }
_formKey.currentState!.save();
_currentDetails.gasType = _formModel.gazRefillDetails![0].gasType;
_currentDetails.cylinderSize = _formModel.gazRefillDetails![0].cylinderSize;
_currentDetails.cylinderType = _formModel.gazRefillDetails![0].cylinderType;
_currentDetails.requestedQty = _formModel.gazRefillDetails![0].requestedQty;
if (!( _currentDetails.validate(context))) {
_currentDetails.gasType = _formModel.gasRefillDetails![0].gasType;
_currentDetails.cylinderSize = _formModel.gasRefillDetails![0].cylinderSize;
_currentDetails.cylinderType = _formModel.gasRefillDetails![0].cylinderType;
_currentDetails.requestedQty = _formModel.gasRefillDetails![0].requestedQty;
if (!(_currentDetails.validate(context))) {
setState(() {});
return false;
}
_formModel.gazRefillDetails![0].deliverdQty = _currentDetails.deliverdQty;
_formModel.gasRefillDetails![0].deliverdQty = _currentDetails.deliverdQty;
_validate = false;
// Scrollable.ensureVisible(_DetailsKey.currentContext);
_deliveredQuantityController.clear();
@ -176,7 +174,6 @@ class _RequestGasRefillState extends State<RequestGasRefill> {
@override
Widget build(BuildContext context) {
_userProvider = Provider.of<UserProvider>(context);
_settingProvider = Provider.of<SettingProvider>(context);
_gasRefillProvider ??= Provider.of<GasRefillProvider>(context, listen: false);
@ -192,12 +189,11 @@ class _RequestGasRefillState extends State<RequestGasRefill> {
clientName = _userProvider.user?.clientName;
}
HospitalsProvider().getHospitalsListByVal(searchVal: clientName??'').then((value) {
_gasRefillProvider!.hospital = value.firstWhere((element) => element.name == clientName, orElse: null);
_gasRefillProvider!.building = _gasRefillProvider!.hospital?.buildings?.firstWhere((element) => element.name == widget.gasRefillModel?.building?.name, orElse: null);
_gasRefillProvider!.floor = _gasRefillProvider!.building?.floors?.firstWhere((element) => element.name == widget.gasRefillModel?.floor?.name, orElse: null);
_gasRefillProvider!.department = _gasRefillProvider!.floor?.departments?.firstWhere((element) => element.name == widget.gasRefillModel?.department?.departmentName, orElse: null);
HospitalsProvider().getHospitalsListByVal(searchVal: clientName ?? '').then((value) {
_gasRefillProvider!.hospital = value.firstWhere((element) => element.name == clientName, orElse: null);
_gasRefillProvider!.building = _gasRefillProvider!.hospital?.buildings?.firstWhere((element) => element.name == widget.gasRefillModel?.building?.name, orElse: null);
_gasRefillProvider!.floor = _gasRefillProvider!.building?.floors?.firstWhere((element) => element.name == widget.gasRefillModel?.floor?.name, orElse: null);
_gasRefillProvider!.department = _gasRefillProvider!.floor?.departments?.firstWhere((element) => element.name == widget.gasRefillModel?.department?.departmentName, orElse: null);
_firstTime = false;
setState(() {});
});
@ -226,10 +222,10 @@ class _RequestGasRefillState extends State<RequestGasRefill> {
children: [
context.translation.gasRefill.heading5(context),
8.height,
'${context.translation.gasRequest}: ${widget.gasRefillModel!.gazRefillDetails![0].gasType!.name}'.bodyText(context),
'${context.translation.cylinderType}: ${widget.gasRefillModel!.gazRefillDetails![0].cylinderType!.name}'.bodyText(context),
'${context.translation.cylinderSize}: ${widget.gasRefillModel!.gazRefillDetails![0].cylinderSize!.name}'.bodyText(context),
'${context.translation.quantity}: ${widget.gasRefillModel!.gazRefillDetails![0].requestedQty ?? 0}'.bodyText(context),
'${context.translation.gasRequest}: ${widget.gasRefillModel!.gasRefillDetails![0].gasType!.name}'.bodyText(context),
'${context.translation.cylinderType}: ${widget.gasRefillModel!.gasRefillDetails![0].cylinderType!.name}'.bodyText(context),
'${context.translation.cylinderSize}: ${widget.gasRefillModel!.gasRefillDetails![0].cylinderSize!.name}'.bodyText(context),
'${context.translation.quantity}: ${widget.gasRefillModel!.gasRefillDetails![0].requestedQty ?? 0}'.bodyText(context),
'${context.translation.site}: ${widget.gasRefillModel!.site?.name}'.bodyText(context),
],
).toShadowContainer(context),

@ -19,7 +19,7 @@
//
// import '../../../models/enums/user_types.dart';
// import '../../widgets/land_page/land_page_item.dart';
// import '../device_transfer/request_device_transfer.dart';
// import '../device_transfer/create__asset_transfer_request.dart';
// import 'requests/requests_page.dart';
//
// @Deprecated("Use the page which is inside the [new_views/pages/land_page] folder")

@ -97,7 +97,7 @@ class _PpmDetailsPageState extends State<PpmDetailsPage> {
// '${context.translation.expectDate}: ${planPreventiveVisit.expectedDate?.toAssetDetailsFormat ?? ""}'.bodyText(context), //todo @baha,
'${context.translation.actualDate}: ${planPreventiveVisit.acutalDateOfVisit?.toIso8601String().toAssetDetailsFormat ?? ""}'.bodyText(context), //todo @baha,
const Divider().defaultStyle(context),
'${context.translation.engineerName}: ${planPreventiveVisit.assignedEmployee?.userName ?? ""}'.bodyText(context), //todo @baha,
'${context.translation.assignedEmployee}: ${planPreventiveVisit.assignedEmployee?.userName ?? ""}'.bodyText(context), //todo @baha,
'${context.translation.site}: ${planPreventiveVisit.siteName?.cleanupWhitespace.capitalizeFirstOfEach}'.bodyText(context), //todo @baha,
'${context.translation.building}: ${planPreventiveVisit.buildingName?.cleanupWhitespace.capitalizeFirstOfEach}'.bodyText(context), //todo @baha,
'${context.translation.floor}: ${planPreventiveVisit.floorName?.cleanupWhitespace.capitalizeFirstOfEach}'.bodyText(context), //todo @baha,
@ -106,14 +106,24 @@ class _PpmDetailsPageState extends State<PpmDetailsPage> {
],
).toShadowContainer(context).paddingAll(16),
).expanded,
if (userProvider!.user!.type == UsersTypes.engineer && (planPreventiveVisit.visitStatus!.id! != 270 && planPreventiveVisit.visitStatus!.id! != 269))
if (userProvider!.user!.type == UsersTypes.engineer && (!ppmProvider.isReadOnly))...[
AppFilledButton(
onPressed: () async {
await Navigator.of(context).push(MaterialPageRoute(builder: (_) => UpdatePpm(ppm: null, planPreventiveVisit: planPreventiveVisit)));
getVisitData();
},
label: context.translation.updateRequest,
label: context.translation.updateWorkOrder,
).paddingAll(16)
]
else ...[
AppFilledButton(
onPressed: () async {
await Navigator.of(context).push(MaterialPageRoute(builder: (_) => UpdatePpm(ppm: null, planPreventiveVisit: planPreventiveVisit)));
getVisitData();
},
label: context.translation.viewDetails,
).paddingAll(16)
]
]);
}),
),

@ -52,16 +52,8 @@ class _RoomInspectionCardState extends State<RoomInspectionCard> {
).toShadowContainer(context).paddingOnly(top: 12);
}
Widget inspectionStatusRadioWidget({
required int index,
required PlanRecurrentMedicalTaskRoomTabAttributes model,
required BuildContext context,
}) {
bool status = model.attribute != null
? model.attributeValue == 'true'
? true
: false
: false;
Widget inspectionStatusRadioWidget({required int index, required PlanRecurrentMedicalTaskRoomTabAttributes model, required BuildContext context}) {
bool status = (model.attribute == null || model.attributeValue == null) ? true : (model.attribute != null ? (model.attributeValue == 'true' ? true : false) : false);
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
@ -71,7 +63,7 @@ class _RoomInspectionCardState extends State<RoomInspectionCard> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
model.attribute!.name!,
model.attribute?.name ?? '',
overflow: TextOverflow.ellipsis,
maxLines: 1,
style: AppTextStyles.bodyText2.copyWith(color: AppColor.white936),

@ -76,7 +76,8 @@ class _RoomTabsWidgetState extends State<RoomTabsWidget> {
? const ALoading().paddingOnly(top: 150)
: ListView(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(), padding: EdgeInsets.zero,
physics: const NeverScrollableScrollPhysics(),
padding: EdgeInsets.zero,
children: widget.model!.planRecurrentMedicalTaskRooms![selectedIndex].planRecurrentMedicalTaskRoomTabs!.map<Widget>((card) {
return RoomInspectionCard(inspectionModel: card);
}).toList(),

@ -6,11 +6,9 @@ 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/ppm/ppm.dart';
import 'package:test_sa/models/ppm/recurrent_wo.dart';
import 'package:test_sa/models/timer_model.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart';
import 'package:test_sa/service_request_latest/utilities/service_request_utils.dart';
import 'package:test_sa/views/widgets/requests/request_status.dart';
import 'package:test_sa/views/widgets/timer/app_timer.dart';
@ -40,7 +38,7 @@ class RecurrentTaskInfoWidget extends StatelessWidget {
2.height,
'${context.translation.taskNo}: ${model!.taskNo!}'.bodyText2(context).custom(color: AppColor.neutral120),
'${context.translation.site}: ${model!.site!.siteName!}'.bodyText2(context).custom(color: AppColor.neutral120),
'${context.translation.assignEngineer}: ${model!.engineer!.userName ?? ""}'.bodyText2(context).custom(color: AppColor.neutral120),
'${context.translation.assignedEmployee}: ${model!.engineer!.userName ?? ""}'.bodyText2(context).custom(color: AppColor.neutral120),
'${context.translation.scheduledDate}: ${model!.scheduleDate!.toMonthYearFormat}'.bodyText2(context).custom(color: AppColor.neutral120),
],
).toShadowContainer(context),
@ -50,17 +48,21 @@ class RecurrentTaskInfoWidget extends StatelessWidget {
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
buildingInfoWidget(label: context.translation.department, value: model?.department?.name?.cleanupWhitespace.capitalizeFirstOfEach, context: context),
buildingInfoWidget(label: context.translation.department, value: model!.department?.name?.cleanupWhitespace.capitalizeFirstOfEach, context: context),
8.height,
buildingInfoWidget(label: context.translation.floor, value: model?.floor?.name?.cleanupWhitespace.capitalizeFirstOfEach, context: context),
buildingInfoWidget(label: context.translation.floor, value: model!.floor?.name?.cleanupWhitespace.capitalizeFirstOfEach, context: context),
8.height,
buildingInfoWidget(label: context.translation.room, value: model?.room?.name?.cleanupWhitespace.capitalizeFirstOfEach, context: context),
buildingInfoWidget(label: context.translation.room, value: model!.room?.name?.cleanupWhitespace.capitalizeFirstOfEach, context: context),
8.height,
_timerWidget(context, model!.totalWorkingHours!)
_timerWidget(context, model!.totalWorkingHours!),
8.height,
_commentWidget(context: context, model: model)
],
// ],
).toShadowContainer(context, padding: 12)
: _timerWidget(context, model!.totalWorkingHours!).toShadowContainer(context, padding: 12),
: Column(
children: [_timerWidget(context, model!.totalWorkingHours!), 8.height, _commentWidget(context: context, model: model)],
).toShadowContainer(context, padding: 12),
],
);
}
@ -74,7 +76,7 @@ class RecurrentTaskInfoWidget extends StatelessWidget {
label: context.translation.timer,
timer: snapshot.recurrentWoData?.recurrentWoTimerModel,
width: double.infinity,
// enabled: snapshot.recurrentWoData?.recurrentWoTimerModel?.endAt == null,
enabled: snapshot.recurrentWoData?.status?.value != 1,
decoration: BoxDecoration(
color: AppColor.neutral100,
borderRadius: BorderRadius.circular(10),
@ -104,6 +106,24 @@ class RecurrentTaskInfoWidget extends StatelessWidget {
);
});
}
Widget _commentWidget({RecurrentWoData? model, required BuildContext context}) {
return AppTextFormField(
initialValue: model?.comment,
labelText: context.translation.comment,
backgroundColor: AppColor.neutral100,
showShadow: false,
labelStyle: AppTextStyles.textFieldLabelStyle,
alignLabelWithHint: true,
textInputType: TextInputType.multiline,
onChange: (value) {
model?.comment = value;
},
onSaved: (value) {
model?.comment = value;
},
);
}
}
Widget buildingInfoWidget({required String label, required String? value, required BuildContext context}) {
@ -118,10 +138,9 @@ Widget buildingInfoWidget({required String label, required String? value, requir
),
3.height,
Text(
value??'',
value ?? '',
style: AppTextStyles.bodyText2.copyWith(color: AppColor.black10),
)
],
).toShadowContainer(context, backgroundColor: AppColor.neutral100, borderRadius: 10, paddingObject: EdgeInsets.all(12.toScreenHeight), showShadow: false);
}

@ -48,7 +48,12 @@ class _RecurrentWorkOrderViewState extends State<RecurrentWorkOrderView> {
Widget build(BuildContext context) {
return Consumer<AllRequestsProvider>(builder: (context, requestProvider, child) {
return Scaffold(
appBar: DefaultAppBar(title: context.translation.recurrentWo),
appBar: DefaultAppBar(
title: context.translation.recurrentWo,
onWillPopScope: () {
_updateTask(context: context, status: 0);
},
),
body: allRequestsProvider!.isLoading
? const ALoading()
: requestProvider.recurrentWoData != null
@ -60,7 +65,6 @@ class _RecurrentWorkOrderViewState extends State<RecurrentWorkOrderView> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
RecurrentTaskInfoWidget(model: requestProvider.recurrentWoData),
// 8.height,
requestProvider.recurrentWoData!.planRecurrentMedicalTaskRooms!.isNotEmpty
? Column(
children: [
@ -72,29 +76,35 @@ class _RecurrentWorkOrderViewState extends State<RecurrentWorkOrderView> {
],
).paddingAll(12),
).paddingOnly(bottom: 85),
FooterActionButton.footerContainer(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
AppFilledButton(
label: context.translation.save,
buttonColor: AppColor.white60,
textColor: AppColor.black10,
onPressed: () => _updateTask(context: context, status: 0),
).expanded,
12.width,
AppFilledButton(
label: context.translation.complete,
buttonColor: AppColor.primary10,
onPressed: () => _updateTask(context: context, status: 1),
).expanded,
],
if (requestProvider.recurrentWoData?.status?.value != 1) ...[
FooterActionButton.footerContainer(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
AppFilledButton(
label: context.translation.save,
buttonColor: AppColor.white60,
textColor: AppColor.black10,
onPressed: () => _updateTask(context: context, status: 0),
).expanded,
12.width,
AppFilledButton(
label: context.translation.complete,
buttonColor: AppColor.primary10,
onPressed: () => _updateTask(context: context, status: 1),
).expanded,
],
),
),
),
]
],
)
: NoDataFound(message: context.translation.noDataFound).center,
);
).handlePopScope(
cxt: context,
onSave: () {
_updateTask(context: context, status: 0);
});
});
}
}
@ -104,11 +114,7 @@ void _updateTask({required BuildContext context, required int status}) async {
if (validate(model: allRequestsProvider.recurrentWoData!)) {
allRequestsProvider.recurrentWoData?.planRecurrentTaskTimers = allRequestsProvider.recurrentWoData?.planRecurrentTaskTimers ?? [];
DateTime? startTime = allRequestsProvider.recurrentWoData?.recurrentWoTimerModel?.startAt;
DateTime? endTime = allRequestsProvider.recurrentWoData?.recurrentWoTimerModel?.endAt;
// final duration = (endTime?.difference(startTime!));
showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
allRequestsProvider.recurrentWoData?.timerModelList?.forEach((timer) {
int durationInSecond = timer.endAt!.difference(timer.startAt!).inSeconds;
allRequestsProvider.recurrentWoData?.planRecurrentTaskTimers?.add(

@ -8,6 +8,7 @@ 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/device/asset.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/models/plan_preventive_visit/plan_preventive_visit_model.dart';
import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
@ -29,7 +30,8 @@ class _PpmCalibrationToolsFormState extends State<PpmCalibrationToolsForm> {
@override
Widget build(BuildContext context) {
final userProvider = Provider.of<UserProvider>(context);
int totalTabs = Provider.of<PpmProvider>(context, listen: false).totalTabs;
final ppmProvider = Provider.of<PpmProvider>(context, listen: false);
int totalTabs = ppmProvider.totalTabs;
int currentIndex = totalTabs == 4 ? 2 : 1;
return ListView.separated(
itemCount: widget.models!.length + 1,
@ -37,27 +39,30 @@ class _PpmCalibrationToolsFormState extends State<PpmCalibrationToolsForm> {
separatorBuilder: (cxt, index) => 16.height,
itemBuilder: (context, index) {
if (index == widget.models!.length) {
return AppFilledButton(
label: "Add More Calibration Tools".addTranslation,
maxWidth: true,
textColor: AppColor.black10,
buttonColor: context.isDark ? AppColor.neutral60 : AppColor.white10,
icon: Icon(Icons.add_circle, color: AppColor.blueStatus(context)),
showIcon: true,
onPressed: () async {
if (widget.models?.isNotEmpty ?? false) {
if (widget.models!.last.asset?.id == null) {
await Fluttertoast.showToast(msg: "${context.translation.youHaveToSelect} ${context.translation.assetNumber}");
return;
return Visibility(
visible: !ppmProvider.isReadOnly,
child: AppFilledButton(
label: "Add More Calibration Tools".addTranslation,
maxWidth: true,
textColor: AppColor.black10,
buttonColor: context.isDark ? AppColor.neutral60 : AppColor.white10,
icon: Icon(Icons.add_circle, color: AppColor.blueStatus(context)),
showIcon: true,
onPressed: () async {
if (widget.models?.isNotEmpty ?? false) {
if (widget.models!.last.asset?.id == null) {
await Fluttertoast.showToast(msg: "${context.translation.youHaveToSelect} ${context.translation.assetNumber}");
return;
}
if (widget.models!.last.calibrationDateOfTesters == null) {
await Fluttertoast.showToast(msg: "${context.translation.youHaveToSelect} ${context.translation.date}");
return;
}
}
if (widget.models!.last.calibrationDateOfTesters == null) {
await Fluttertoast.showToast(msg: "${context.translation.youHaveToSelect} ${context.translation.date}");
return;
}
}
widget.models!.add(PreventiveVisitCalibrations(id: 0));
setState(() {});
},
widget.models!.add(PreventiveVisitCalibrations(id: 0));
setState(() {});
},
),
);
}
PreventiveVisitCalibrations model = widget.models![index];
@ -68,48 +73,51 @@ class _PpmCalibrationToolsFormState extends State<PpmCalibrationToolsForm> {
borderRadius: BorderRadius.circular(20),
boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.03), blurRadius: 14)],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
(index == 0 ? "$currentIndex /$totalTabs . Calibration Tools" : "").heading5(context),
"trash".toSvgAsset(height: 20, width: 15).onPress(() {
widget.models!.remove(model);
child: IgnorePointer(
ignoring:ppmProvider.isReadOnly,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
(index == 0 ? "$currentIndex /$totalTabs . Calibration Tools" : "").heading5(context),
"trash".toSvgAsset(height: 20, width: 15).onPress(() {
widget.models!.remove(model);
setState(() {});
}),
],
),
16.height,
CalibrationToolAssetPicker(
initialValue: model.asset?.id == null ? null : Lookup(id: model.asset?.id?.toInt(), name: model.asset?.assetNumber ?? ""),
hospitalId: userProvider.user!.clientId,
onPick: (asset) {
model.asset = Asset(id: asset.id, assetNumber: asset.assetNumber, assetSerialNo: asset.assetSerialNo);
setState(() {});
},
),
12.height,
if (model.asset?.assetNumber != null)
Text("Asset Number: ${model.asset?.assetNumber?.cleanupWhitespace.capitalizeFirstOfEach}", style: AppTextStyles.bodyText2.copyWith(color: AppColor.neutral120)),
// if (model.assetName != null) Text("Asset Name: ${model.assetName?.cleanupWhitespace.capitalizeFirstOfEach}", style: AppTextStyles.bodyText2.copyWith(color: AppColor.neutral120)),
if (model.asset?.assetSerialNo != null)
Text("Asset Serial No: ${model.asset?.assetSerialNo?.cleanupWhitespace.capitalizeFirstOfEach}", style: AppTextStyles.bodyText2.copyWith(color: AppColor.neutral120)),
12.height,
ADatePicker(
label: context.translation.calibrationDate,
date: DateTime.tryParse(model.calibrationDateOfTesters ?? ""),
from: DateTime.now().subtract(const Duration(days: 90)),
backgroundColor: context.isDark ? AppColor.neutral50 : AppColor.neutral100,
withBorder: false,
hideShadow: true,
onDatePicker: (date) {
model.calibrationDateOfTesters = date.toIso8601String();
setState(() {});
}),
],
),
16.height,
CalibrationToolAssetPicker(
initialValue: model.asset?.id == null ? null : Lookup(id: model.asset?.id?.toInt(), name: model.asset?.assetNumber ?? ""),
hospitalId: userProvider.user!.clientId,
onPick: (asset) {
model.asset = Asset(id: asset.id, assetNumber: asset.assetNumber, assetSerialNo: asset.assetSerialNo);
setState(() {});
},
),
12.height,
if (model.asset?.assetNumber != null)
Text("Asset Number: ${model.asset?.assetNumber?.cleanupWhitespace.capitalizeFirstOfEach}", style: AppTextStyles.bodyText2.copyWith(color: AppColor.neutral120)),
// if (model.assetName != null) Text("Asset Name: ${model.assetName?.cleanupWhitespace.capitalizeFirstOfEach}", style: AppTextStyles.bodyText2.copyWith(color: AppColor.neutral120)),
if (model.asset?.assetSerialNo != null)
Text("Asset Serial No: ${model.asset?.assetSerialNo?.cleanupWhitespace.capitalizeFirstOfEach}", style: AppTextStyles.bodyText2.copyWith(color: AppColor.neutral120)),
12.height,
ADatePicker(
label: context.translation.calibrationDate,
date: DateTime.tryParse(model.calibrationDateOfTesters ?? ""),
from: DateTime.now().subtract(const Duration(days: 90)),
backgroundColor: context.isDark ? AppColor.neutral50 : AppColor.neutral100,
withBorder: false,
hideShadow: true,
onDatePicker: (date) {
model.calibrationDateOfTesters = date.toIso8601String();
setState(() {});
},
),
],
},
),
],
),
),
);
},

@ -237,6 +237,8 @@
// }
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/ppm_provider.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';
@ -289,20 +291,23 @@ class _PpmExternalDetailsFormState extends State<PpmExternalDetailsForm> {
@override
Widget build(BuildContext context) {
print("widget.models!.length:${widget.models!.length}");
final ppmProvider = Provider.of<PpmProvider>(context, listen: false);
return ListView.builder(
itemCount: widget.models!.length + 1,
padding: const EdgeInsets.all(16),
itemBuilder: (context, index) {
if (index == widget.models!.length) {
return AppFilledButton(
label: "Add More External Details".addTranslation,
maxWidth: true,
textColor: AppColor.black10,
buttonColor: context.isDark ? AppColor.neutral60 : AppColor.white10,
icon: Icon(Icons.add_circle, color: AppColor.blueStatus(context)),
showIcon: true,
onPressed: _addNewEntry,
return Visibility(
visible: !ppmProvider.isReadOnly,
child: AppFilledButton(
label: "Add More External Details".addTranslation,
maxWidth: true,
textColor: AppColor.black10,
buttonColor: context.isDark ? AppColor.neutral60 : AppColor.white10,
icon: Icon(Icons.add_circle, color: AppColor.blueStatus(context)),
showIcon: true,
onPressed: _addNewEntry,
),
);
}
// return !isLoading
@ -336,10 +341,12 @@ class ExternalDetailItem extends StatefulWidget {
class _ExternalDetailItemState extends State<ExternalDetailItem> {
TextEditingController? controller;
PpmProvider? _ppmProvider;
@override
void initState() {
controller = TextEditingController(text: widget.model.workingHours != null ? widget.model.workingHours.toString() : '');
_ppmProvider= Provider.of<PpmProvider>(context,listen:false);
super.initState();
}
@ -353,148 +360,151 @@ class _ExternalDetailItemState extends State<ExternalDetailItem> {
borderRadius: BorderRadius.circular(20),
boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.03), blurRadius: 14)],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
(widget.index == 0 ? "1 /4 . External Details" : "").heading5(context),
Container(
height: 32,
width: 32,
padding: const EdgeInsets.all(6),
child: "trash".toSvgAsset(height: 20, width: 20),
).onPress(() {
widget.onRemove();
}),
],
),
16.height,
SingleItemDropDownMenu<SupplierDetails, VendorProvider>(
context: context,
title: context.translation.supplier,
initialValue: widget.model.supplier,
backgroundColor: AppColor.neutral100,
showAsBottomSheet: true,
showShadow: false,
onSelect: (supplier) {
if (supplier != null) {
setState(() {
widget.model.supplier = supplier;
});
}
},
),
8.height,
SingleItemDropDownMenu<SuppPersons, NullableLoadingProvider>(
context: context,
title: context.translation.supplierEngineer,
enabled: widget.model.supplier != null,
backgroundColor: AppColor.neutral100,
initialValue: widget.model.suppPerson,
staticData: widget.model.supplier?.suppPersons,
showAsBottomSheet: true,
showShadow: false,
onSelect: (suppPerson) {
if (suppPerson != null) {
widget.model.suppPerson = suppPerson;
}
},
),
8.height,
Row(
mainAxisSize: MainAxisSize.min,
children: [
ADatePicker(
label: context.translation.startTime,
hideShadow: true,
backgroundColor: AppColor.neutral100,
date: widget.model.startDateTime,
formatDateWithTime: true,
onDatePicker: (selectedDate) {
showTimePicker(
context: context,
initialTime: TimeOfDay.now(),
).then((selectedTime) {
if (selectedTime != null) {
DateTime selectedDateTime = DateTime(
selectedDate.year,
selectedDate.month,
selectedDate.day,
selectedTime.hour,
selectedTime.minute,
);
setState(() {
widget.model.startDateTime = selectedDateTime;
});
widget.model.endDateTime = null;
controller?.clear();
ServiceRequestUtils.calculateAndAssignWorkingHours(
startTime: widget.model.startDateTime,
endTime: widget.model.endDateTime,
workingHoursController: controller!,
updateModel: (hours) {
widget.model.workingHours = hours;
},
);
}
child: IgnorePointer(
ignoring: _ppmProvider!.isReadOnly,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
(widget.index == 0 ? "1 /4 . External Details" : "").heading5(context),
Container(
height: 32,
width: 32,
padding: const EdgeInsets.all(6),
child: "trash".toSvgAsset(height: 20, width: 20),
).onPress(() {
widget.onRemove();
}),
],
),
16.height,
SingleItemDropDownMenu<SupplierDetails, VendorProvider>(
context: context,
title: context.translation.supplier,
initialValue: widget.model.supplier,
backgroundColor: AppColor.neutral100,
showAsBottomSheet: true,
showShadow: false,
onSelect: (supplier) {
if (supplier != null) {
setState(() {
widget.model.supplier = supplier;
});
},
).expanded,
8.width,
ADatePicker(
label: context.translation.endTime,
hideShadow: true,
backgroundColor: AppColor.neutral100,
date: widget.model.endDateTime,
formatDateWithTime: true,
onDatePicker: (selectedDate) {
showTimePicker(
context: context,
initialTime: TimeOfDay.now(),
).then((selectedTime) {
if (selectedTime != null) {
DateTime selectedDateTime = DateTime(
selectedDate.year,
selectedDate.month,
selectedDate.day,
selectedTime.hour,
selectedTime.minute,
);
if (widget.model.startDateTime != null && selectedDateTime.isBefore(widget.model.startDateTime!)) {
"End Date time must be greater than start date".showToast;
return;
}
},
),
8.height,
SingleItemDropDownMenu<SuppPersons, NullableLoadingProvider>(
context: context,
title: context.translation.supplierEngineer,
enabled: widget.model.supplier != null,
backgroundColor: AppColor.neutral100,
initialValue: widget.model.suppPerson,
staticData: widget.model.supplier?.suppPersons,
showAsBottomSheet: true,
showShadow: false,
onSelect: (suppPerson) {
if (suppPerson != null) {
widget.model.suppPerson = suppPerson;
}
},
),
8.height,
Row(
mainAxisSize: MainAxisSize.min,
children: [
ADatePicker(
label: context.translation.startTime,
hideShadow: true,
backgroundColor: AppColor.neutral100,
date: widget.model.startDateTime,
formatDateWithTime: true,
onDatePicker: (selectedDate) {
showTimePicker(
context: context,
initialTime: TimeOfDay.now(),
).then((selectedTime) {
if (selectedTime != null) {
DateTime selectedDateTime = DateTime(
selectedDate.year,
selectedDate.month,
selectedDate.day,
selectedTime.hour,
selectedTime.minute,
);
setState(() {
widget.model.startDateTime = selectedDateTime;
});
widget.model.endDateTime = null;
controller?.clear();
ServiceRequestUtils.calculateAndAssignWorkingHours(
startTime: widget.model.startDateTime,
endTime: widget.model.endDateTime,
workingHoursController: controller!,
updateModel: (hours) {
widget.model.workingHours = hours;
},
);
}
setState(() {
widget.model.endDateTime = selectedDateTime;
});
ServiceRequestUtils.calculateAndAssignWorkingHours(
startTime: widget.model.startDateTime,
endTime: widget.model.endDateTime,
workingHoursController: controller!,
updateModel: (hours) {
widget.model.workingHours = hours;
},
);
}
});
},
).expanded,
],
),
8.height,
AppTextFormField(
labelText: context.translation.workingHours,
backgroundColor: AppColor.neutral80,
controller: controller,
textAlign: TextAlign.center,
enable: false,
showShadow: false,
style: Theme.of(context).textTheme.titleMedium,
),
8.height,
],
});
},
).expanded,
8.width,
ADatePicker(
label: context.translation.endTime,
hideShadow: true,
backgroundColor: AppColor.neutral100,
date: widget.model.endDateTime,
formatDateWithTime: true,
onDatePicker: (selectedDate) {
showTimePicker(
context: context,
initialTime: TimeOfDay.now(),
).then((selectedTime) {
if (selectedTime != null) {
DateTime selectedDateTime = DateTime(
selectedDate.year,
selectedDate.month,
selectedDate.day,
selectedTime.hour,
selectedTime.minute,
);
if (widget.model.startDateTime != null && selectedDateTime.isBefore(widget.model.startDateTime!)) {
"End Date time must be greater than start date".showToast;
return;
}
setState(() {
widget.model.endDateTime = selectedDateTime;
});
ServiceRequestUtils.calculateAndAssignWorkingHours(
startTime: widget.model.startDateTime,
endTime: widget.model.endDateTime,
workingHoursController: controller!,
updateModel: (hours) {
widget.model.workingHours = hours;
},
);
}
});
},
).expanded,
],
),
8.height,
AppTextFormField(
labelText: context.translation.workingHours,
backgroundColor: AppColor.neutral80,
controller: controller,
textAlign: TextAlign.center,
enable: false,
showShadow: false,
style: Theme.of(context).textTheme.titleMedium,
),
8.height,
],
),
),
);
}

@ -32,6 +32,7 @@ class _PpmPmChecklistFormState extends State<PpmPmChecklistForm> {
@override
Widget build(BuildContext context) {
int totalTabs = Provider.of<PpmProvider>(context, listen: false).totalTabs;
final ppmProvider = Provider.of<PpmProvider>(context, listen: false);
int currentIndex = totalTabs == 4 ? 4 : 3;
List<PreventiveVisitChecklists>? list = widget.checkList ?? [];
return (list.isEmpty)
@ -42,68 +43,71 @@ class _PpmPmChecklistFormState extends State<PpmPmChecklistForm> {
shrinkWrap: true,
separatorBuilder: (cxt, index) => 12.height,
itemBuilder: (context, index) {
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (index == 0) ...[
"$currentIndex /$totalTabs . PM Checklist".heading5(context),
16.height,
return IgnorePointer(
ignoring: ppmProvider.isReadOnly,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (index == 0) ...[
"$currentIndex /$totalTabs . PM Checklist".heading5(context),
16.height,
],
AppTextFormField(
labelText: "Task".addTranslation,
labelStyle: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120, fontWeight: FontWeight.w500),
initialValue: list[index].instructionText?.text ?? "",
enable: false,
showShadow: false,
makeMultiLinesNull: true,
enableColor: AppColor.neutral100,
backgroundColor: context.isDark ? AppColor.neutral20 : AppColor.neutral100,
// backgroundColor: context.isDark ? AppColor.neutral50 : null,
onChange: (text) {
list[index].taskComment = text;
},
),
8.height,
SingleItemDropDownMenu<Lookup, PpmChecklistStatusProvider>(
context: context,
showShadow: false,
backgroundColor: context.isDark ? AppColor.neutral20 : AppColor.neutral100,
initialValue: list[index].taskStatus?.id == null ? null : Lookup(id: list[index].taskStatus?.id?.toInt(), name: list[index].taskStatus?.name),
title: context.translation.taskStatus,
onSelect: (value) {
if (value != null) {
list[index].taskStatus = Lookup(id: value.id, name: value.name, value: value.value);
}
},
),
8.height,
AppTextFormField(
labelText: context.translation.measuredValue,
labelStyle: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120, fontWeight: FontWeight.w500),
initialValue: list[index].measuredValue ?? "",
// enable: false,
backgroundColor: context.isDark ? AppColor.neutral20 : AppColor.neutral100,
showShadow: false,
onChange: (text) {
list[index].measuredValue = text;
},
),
8.height,
AppTextFormField(
labelText: "Task Comment".addTranslation,
labelStyle: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120, fontWeight: FontWeight.w500),
initialValue: list[index].taskComment ?? "",
textInputType: TextInputType.multiline,
makeMultiLinesNull: true,
backgroundColor: context.isDark ? AppColor.neutral20 : AppColor.neutral100,
showShadow: false,
onChange: (text) {
list[index].taskComment = text;
},
),
],
AppTextFormField(
labelText: "Task".addTranslation,
labelStyle: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120, fontWeight: FontWeight.w500),
initialValue: list[index].instructionText?.text ?? "",
enable: false,
showShadow: false,
makeMultiLinesNull: true,
enableColor: AppColor.neutral100,
backgroundColor: context.isDark ? AppColor.neutral20 : AppColor.neutral100,
// backgroundColor: context.isDark ? AppColor.neutral50 : null,
onChange: (text) {
list[index].taskComment = text;
},
),
8.height,
SingleItemDropDownMenu<Lookup, PpmChecklistStatusProvider>(
context: context,
showShadow: false,
backgroundColor: context.isDark ? AppColor.neutral20 : AppColor.neutral100,
initialValue: list[index].taskStatus?.id == null ? null : Lookup(id: list[index].taskStatus?.id?.toInt(), name: list[index].taskStatus?.name),
title: context.translation.taskStatus,
onSelect: (value) {
if (value != null) {
list[index].taskStatus = Lookup(id: value.id, name: value.name, value: value.value);
}
},
),
8.height,
AppTextFormField(
labelText: context.translation.measuredValue,
labelStyle: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120, fontWeight: FontWeight.w500),
initialValue: list[index].measuredValue ?? "",
// enable: false,
backgroundColor: context.isDark ? AppColor.neutral20 : AppColor.neutral100,
showShadow: false,
onChange: (text) {
list[index].measuredValue = text;
},
),
8.height,
AppTextFormField(
labelText: "Task Comment".addTranslation,
labelStyle: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120, fontWeight: FontWeight.w500),
initialValue: list[index].taskComment ?? "",
textInputType: TextInputType.multiline,
makeMultiLinesNull: true,
backgroundColor: context.isDark ? AppColor.neutral20 : AppColor.neutral100,
showShadow: false,
onChange: (text) {
list[index].taskComment = text;
},
),
],
).toShadowContainer(context, showShadow: false, borderRadius: 20);
).toShadowContainer(context, showShadow: false, borderRadius: 20),
);
},
);
}

@ -26,7 +26,8 @@ class PpmPMKitsForm extends StatefulWidget {
class _PpmPMKitsFormState extends State<PpmPMKitsForm> {
@override
Widget build(BuildContext context) {
int totalTabs = Provider.of<PpmProvider>(context, listen: false).totalTabs;
final ppmProvider = Provider.of<PpmProvider>(context, listen: false);
int totalTabs = ppmProvider.totalTabs;
int currentIndex = totalTabs == 4 ? 3 : 2;
return ListView.builder(
itemCount: widget.models!.length + 1,
@ -34,27 +35,30 @@ class _PpmPMKitsFormState extends State<PpmPMKitsForm> {
padding: const EdgeInsets.only(left: 16, right: 16, top: 8, bottom: 16),
itemBuilder: (context, index) {
if (index == widget.models!.length) {
return AppFilledButton(
label: "Add More PM Kits".addTranslation,
maxWidth: true,
textColor: AppColor.black10,
buttonColor: context.isDark ? AppColor.neutral60 : AppColor.white10,
icon: Icon(Icons.add_circle, color: AppColor.blueStatus(context)),
showIcon: true,
onPressed: () async {
if (widget.models?.isNotEmpty ?? false) {
if (widget.models!.last.partCatalogItem?.partNumber == null) {
await Fluttertoast.showToast(msg: "${context.translation.youHaveToSelect} ${context.translation.partNumber}");
return;
return Visibility(
visible: !ppmProvider.isReadOnly,
child: AppFilledButton(
label: "Add More PM Kits".addTranslation,
maxWidth: true,
textColor: AppColor.black10,
buttonColor: context.isDark ? AppColor.neutral60 : AppColor.white10,
icon: Icon(Icons.add_circle, color: AppColor.blueStatus(context)),
showIcon: true,
onPressed: () async {
if (widget.models?.isNotEmpty ?? false) {
if (widget.models!.last.partCatalogItem?.partNumber == null) {
await Fluttertoast.showToast(msg: "${context.translation.youHaveToSelect} ${context.translation.partNumber}");
return;
}
if (widget.models!.last.partCatalogItem?.partName == null) {
await Fluttertoast.showToast(msg: "${context.translation.youHaveToSelect} ${context.translation.partName}");
return;
}
}
if (widget.models!.last.partCatalogItem?.partName == null) {
await Fluttertoast.showToast(msg: "${context.translation.youHaveToSelect} ${context.translation.partName}");
return;
}
}
widget.models!.add(PreventiveVisitKits(id: 0));
setState(() {});
},
widget.models!.add(PreventiveVisitKits(id: 0));
setState(() {});
},
),
);
}
final model = widget.models![index];
@ -66,47 +70,50 @@ class _PpmPMKitsFormState extends State<PpmPMKitsForm> {
borderRadius: BorderRadius.circular(20),
boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.03), blurRadius: 14)],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
(index == 0 ? "$currentIndex /$totalTabs . PM Kits" : "").heading5(context),
Container(
height: 32,
width: 32,
padding: const EdgeInsets.all(6),
child: "trash".toSvgAsset(height: 20, width: 20),
).onPress(() {
widget.models!.remove(model);
child: IgnorePointer(
ignoring: ppmProvider.isReadOnly,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
(index == 0 ? "$currentIndex /$totalTabs . PM Kits" : "").heading5(context),
Container(
height: 32,
width: 32,
padding: const EdgeInsets.all(6),
child: "trash".toSvgAsset(height: 20, width: 20),
).onPress(() {
widget.models!.remove(model);
setState(() {});
}),
],
),
16.height,
AutoCompletePartsField(
assetId: widget.assetId,
clearAfterPick: false,
byName: true,
initialValue: model.partCatalogItem?.partName ?? "",
onPick: (part) {
model.partCatalogItem = PartCatalogItem(id: part.sparePart?.id, partNumber: part.sparePart?.partNo, partName: part.sparePart?.partName, oracleCode: part.sparePart?.oracleCode);
setState(() {});
},
),
8.height,
AutoCompletePartsField(
assetId: widget.assetId,
clearAfterPick: false,
byName: false,
initialValue: model.partCatalogItem?.partNumber ?? "",
onPick: (part) {
model.partCatalogItem = PartCatalogItem(id: part.sparePart?.id, partNumber: part.sparePart?.partNo, partName: part.sparePart?.partName, oracleCode: part.sparePart?.oracleCode);
setState(() {});
}),
],
),
16.height,
AutoCompletePartsField(
assetId: widget.assetId,
clearAfterPick: false,
byName: true,
initialValue: model.partCatalogItem?.partName ?? "",
onPick: (part) {
model.partCatalogItem = PartCatalogItem(id: part.sparePart?.id, partNumber: part.sparePart?.partNo, partName: part.sparePart?.partName, oracleCode: part.sparePart?.oracleCode);
setState(() {});
},
),
8.height,
AutoCompletePartsField(
assetId: widget.assetId,
clearAfterPick: false,
byName: false,
initialValue: model.partCatalogItem?.partNumber ?? "",
onPick: (part) {
model.partCatalogItem = PartCatalogItem(id: part.sparePart?.id, partNumber: part.sparePart?.partNo, partName: part.sparePart?.partName, oracleCode: part.sparePart?.oracleCode);
setState(() {});
},
),
],
},
),
],
),
),
);
},

@ -1,5 +1,4 @@
import 'dart:convert';
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
@ -9,7 +8,6 @@ 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/widget_extensions.dart';
import 'package:test_sa/models/all_requests_and_count_model.dart';
import 'package:test_sa/models/plan_preventive_visit/plan_preventive_visit_model.dart';
import 'package:test_sa/models/ppm/ppm.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
@ -44,8 +42,7 @@ class _UpdatePpmState extends State<UpdatePpm> with TickerProviderStateMixin {
late PpmProvider ppmProvider;
_onSubmit({required int status}) async {
if(ppmProvider.validate()){
if (ppmProvider.validate()) {
showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
ppmProvider.planPreventiveVisit?.preventiveVisitAttachments = [];
for (var item in ppmProvider.ppmPlanAttachments) {
@ -67,7 +64,7 @@ class _UpdatePpmState extends State<UpdatePpm> with TickerProviderStateMixin {
});
await ppmProvider.updateVisitByEngineer(status: status).whenComplete(() {
if(status==1){
if (status == 1) {
AllRequestsProvider allRequestsProvider = Provider.of<AllRequestsProvider>(context, listen: false);
allRequestsProvider.reset();
allRequestsProvider.getAllRequests(context, typeTransaction: 4);
@ -78,15 +75,16 @@ class _UpdatePpmState extends State<UpdatePpm> with TickerProviderStateMixin {
Navigator.pop(context);
});
}
}
@override
void initState() {
ppmProvider = Provider.of<PpmProvider>(context, listen: false);
_planPreventiveVisit = widget.planPreventiveVisit;
initTabs(_planPreventiveVisit.typeOfService);
// WidgetsBinding.instance.addPostFrameCallback((_) {
initTabs(_planPreventiveVisit.typeOfService);
// });
super.initState();
}
@ -115,7 +113,12 @@ class _UpdatePpmState extends State<UpdatePpm> with TickerProviderStateMixin {
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColor.neutral110,
appBar: DefaultAppBar(title: context.translation.preventiveMaintenance),
appBar: DefaultAppBar(
title: context.translation.preventiveMaintenance,
onWillPopScope:ppmProvider.isReadOnly?null: () {
_onSubmit(status: 0);
},
),
key: _scaffoldKey,
body: SafeArea(
child: Column(
@ -158,6 +161,7 @@ class _UpdatePpmState extends State<UpdatePpm> with TickerProviderStateMixin {
),
),
TabBarView(
physics: const NeverScrollableScrollPhysics(),
children: [
WoInfoForm(
planPreventiveVisit: _planPreventiveVisit,
@ -183,35 +187,72 @@ class _UpdatePpmState extends State<UpdatePpm> with TickerProviderStateMixin {
).expanded,
Row(
children: [
AppFilledButton(
buttonColor: AppColor.white60,
textColor: AppColor.neutral50,
onPressed: () {
_onSubmit(status: 0);
},
label: context.translation.save,
).expanded,
16.width,
AppFilledButton(
onPressed: () {
if (tabIndex == 0) {
_onSubmit(status: 1);
return;
}
if (ppmProvider.totalTabs == _tabController!.index + 1) {
_onSubmit(status: 1);
} else {
_tabController?.animateTo(_tabController!.index + 1);
if (tabIndex == 1) ...[
AppFilledButton(
buttonColor: _tabController!.index == 0 ? null : AppColor.background(context),
textColor: _tabController!.index == 0 ? null : AppColor.blueStatus(context),
showBorder: true,
disableButton: _tabController!.index == 0,
onPressed: () {
if (_tabController!.index == 0) {
return;
}
_tabController?.animateTo(_tabController!.index - 1);
setState(() {});
}
},
label: tabIndex == 0 ? "Complete".addTranslation : ((ppmProvider.totalTabs == _tabController!.index + 1) ? "Complete".addTranslation : context.translation.next),
).expanded,
return;
},
label: context.translation.back,
).expanded,
8.width,
],
if (!ppmProvider.isReadOnly) ...[
AppFilledButton(
buttonColor: AppColor.white60,
textColor: AppColor.neutral50,
onPressed: () {
_onSubmit(status: 0);
},
label: context.translation.save,
).expanded,
8.width,
AppFilledButton(
onPressed: () {
if (tabIndex == 0) {
_onSubmit(status: 1);
return;
}
if (ppmProvider.totalTabs == _tabController!.index + 1) {
_onSubmit(status: 1);
} else {
_tabController?.animateTo(_tabController!.index + 1);
setState(() {});
}
},
label: tabIndex == 0 ? "Complete".addTranslation : ((ppmProvider.totalTabs == _tabController!.index + 1) ? "Complete".addTranslation : context.translation.next),
).expanded,
] else ...[
Visibility(
visible: tabIndex != 0,
child: AppFilledButton(
onPressed: () {
if(ppmProvider.totalTabs == _tabController!.index + 1){
Navigator.pop(context);
return;
}
_tabController?.animateTo(_tabController!.index + 1);
setState(() {});
},
label:ppmProvider.totalTabs == _tabController!.index + 1? context.translation.close: context.translation.next,
).expanded,
),
]
],
).toShadowContainer(context, showShadow: false, borderRadius: 0),
],
),
),
);
).handlePopScope(cxt: context, showPopUp:!ppmProvider.isReadOnly ,onSave: () {
_onSubmit(status: 0);
});
}
}

@ -6,8 +6,15 @@ import 'package:test_sa/controllers/providers/api/ppm_provider.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/models/device/model_definition.dart';
import 'package:test_sa/models/device/supplier.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/new_models/building.dart';
import 'package:test_sa/models/new_models/department.dart';
import 'package:test_sa/models/new_models/floor.dart';
import 'package:test_sa/models/new_models/room_model.dart';
import 'package:test_sa/models/new_models/site.dart';
import 'package:test_sa/models/plan_preventive_visit/plan_preventive_visit_model.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/providers/ppm_asset_availability_provider.dart';
@ -15,9 +22,11 @@ import 'package:test_sa/providers/ppm_electrical_safety_provider.dart';
import 'package:test_sa/providers/ppm_service_provider.dart';
import 'package:test_sa/providers/ppm_task_status_provider.dart';
import 'package:test_sa/service_request_latest/utilities/service_request_utils.dart';
import 'package:test_sa/views/widgets/bottom_sheets/asset_detail_bottom_sheet.dart';
import 'package:test_sa/views/widgets/date_and_time/date_picker.dart';
import 'package:test_sa/views/widgets/images/multi_image_picker.dart';
import 'package:test_sa/views/widgets/requests/request_status.dart';
import 'package:test_sa/models/device/asset.dart';
import '../../../../../models/lookup.dart';
import '../../../../../new_views/common_widgets/app_text_form_field.dart';
@ -36,8 +45,6 @@ class WoInfoForm extends StatefulWidget {
}
class _WoInfoFormState extends State<WoInfoForm> {
//TODO need to move this to provider ...
@override
void initState() {
WidgetsBinding.instance.addPostFrameCallback((_) async {
@ -56,218 +63,240 @@ class _WoInfoFormState extends State<WoInfoForm> {
double totalWorkingHours =
widget.planPreventiveVisit.preventiveVisitTimers?.fold(0.0, (sum, item) => (sum ?? 0) + DateTime.parse(item.endDateTime!).difference(DateTime.parse(item.startDateTime!)).inSeconds) ?? 0;
totalWorkingHours = totalWorkingHours;
return Consumer<PpmProvider>(builder: (context, ppmProvider, child) {
return ListView(
padding: const EdgeInsets.only(left: 16, right: 16, top: 8, bottom: 16),
children: [
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (widget.planPreventiveVisit.visitStatus != null)
StatusLabel(
label: widget.planPreventiveVisit.visitStatus?.name,
textColor: AppColor.getRequestStatusTextColorByName(context, widget.planPreventiveVisit.visitStatus?.name),
backgroundColor: AppColor.getRequestStatusColorByName(context, widget.planPreventiveVisit.visitStatus?.name),
),
8.height,
widget.planPreventiveVisit.planName!.bodyText(context).custom(color: AppColor.black10),
2.height,
'${context.translation.pmPlanNo}: ${widget.planPreventiveVisit.planNo}'.bodyText2(context).custom(color: AppColor.neutral120),
//need to add in translation it's suggestion from ahmed..
'Work Order Number: ${widget.planPreventiveVisit.visitNo}'.bodyText2(context).custom(color: AppColor.neutral120),
'${context.translation.from}: ${widget.planPreventiveVisit.fromDate?.toMonthYearFormat}'.bodyText2(context).custom(color: AppColor.neutral120),
'${context.translation.to}: ${widget.planPreventiveVisit.toDate?.toMonthYearFormat}'.bodyText2(context).custom(color: AppColor.neutral120),
IgnorePointer(
ignoring: ppmProvider.isReadOnly,
child: Column(
children: [
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (widget.planPreventiveVisit.visitStatus != null)
StatusLabel(
label: widget.planPreventiveVisit.visitStatus?.name,
textColor: AppColor.getRequestStatusTextColorByName(context, widget.planPreventiveVisit.visitStatus?.name),
backgroundColor: AppColor.getRequestStatusColorByName(context, widget.planPreventiveVisit.visitStatus?.name),
),
8.height,
widget.planPreventiveVisit.planName!.bodyText(context).custom(color: AppColor.black10),
2.height,
'${context.translation.pmPlanNo}: ${widget.planPreventiveVisit.planNo}'.bodyText2(context).custom(color: AppColor.neutral120),
//need to add in translation it's suggestion from ahmed..
'Work Order Number: ${widget.planPreventiveVisit.visitNo}'.bodyText2(context).custom(color: AppColor.neutral120),
'${context.translation.creationDate}: ${widget.planPreventiveVisit.creationDate?.toMonthYearFormat}'.bodyText2(context).custom(color: AppColor.neutral120),
'${context.translation.closedDate}: ${widget.planPreventiveVisit.closedDate != null ? widget.planPreventiveVisit.closedDate?.toMonthYearFormat : '-'}'
.bodyText2(context)
.custom(color: AppColor.neutral120),
'${context.translation.nextPmDate}: ${widget.planPreventiveVisit.nextPMDate != null ? widget.planPreventiveVisit.nextPMDate!.toMonthYearFormat : '-'}'
.bodyText2(context)
.custom(color: AppColor.neutral120),
'${context.translation.assignEngineer}: ${widget.planPreventiveVisit.assignedEmployee?.userName ?? ""}'.bodyText2(context).custom(color: AppColor.neutral120),
'${context.translation.executionTimeFrame}: ${widget.planPreventiveVisit.executionTimeFrame ?? ""} days'.bodyText2(context).custom(color: AppColor.neutral120),
],
).toShadowContainer(context),
12.height,
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
widget.planPreventiveVisit.assetName!.bodyText(context).custom(color: AppColor.black10),
"info_icon".toSvgAsset(height: 17, width: 17),
],
),
2.height,
'${context.translation.assetNo}: ${widget.planPreventiveVisit.asset?.assetNumber}'.bodyText2(context).custom(color: AppColor.neutral120),
'${context.translation.model}: ${widget.planPreventiveVisit.model}'.bodyText2(context).custom(color: AppColor.neutral120),
],
).toShadowContainer(context),
'${context.translation.nextPmDate}: ${widget.planPreventiveVisit.nextPMDate != null ? widget.planPreventiveVisit.nextPMDate!.toMonthYearFormat : '-'}'
.bodyText2(context)
.custom(color: AppColor.neutral120),
'${context.translation.assignEngineer}: ${widget.planPreventiveVisit.assignedEmployee?.userName ?? ""}'.bodyText2(context).custom(color: AppColor.neutral120),
'${context.translation.executionTimeFrame}: ${widget.planPreventiveVisit.executionTimeFrame ?? ""} days'.bodyText2(context).custom(color: AppColor.neutral120),
],
).toShadowContainer(context),
12.height,
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
widget.planPreventiveVisit.assetName!.bodyText(context).custom(color: AppColor.black10),
"info_icon".toSvgAsset(height: 17, width: 17).onPress(
() {
// There is only limited information for asset is returned from backend to show all info need to return the whole model from backend...
showModalBottomSheet(
context: context,
isScrollControlled: true,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(20),
),
),
clipBehavior: Clip.antiAliasWithSaveLayer,
builder: (BuildContext context) => _buildAssetDetailBottomSheet(context),
);
},
)
],
),
2.height,
'${context.translation.assetNo}: ${widget.planPreventiveVisit.asset?.assetNumber}'.bodyText2(context).custom(color: AppColor.neutral120),
'${context.translation.model}: ${widget.planPreventiveVisit.model}'.bodyText2(context).custom(color: AppColor.neutral120),
],
).toShadowContainer(context),
// SingleItemDropDownMenu<Lookup, PPMVisitStatusProvider>(
// context: context,
// initialValue:
// widget.planPreventiveVisit.visitStatus?.id == null ? null : Lookup(name: widget.planPreventiveVisit.visitStatus?.name ?? "", id: widget.planPreventiveVisit.visitStatus?.id?.toInt()),
// title: context.translation.ppmVisit,
// onSelect: (value) {
// if (value?.value == 4) {
// "Status cannot be change to ${value?.name}.".addTranslation.showToast;
// setState(() {});
// return;
// }
//
// if (value != null) {
// widget.planPreventiveVisit.visitStatus?.name = value.name;
// widget.planPreventiveVisit.visitStatus?.id = value.id;
// }
// },
// ),
// SingleItemDropDownMenu<Lookup, PPMVisitStatusProvider>(
// context: context,
// initialValue:
// widget.planPreventiveVisit.visitStatus?.id == null ? null : Lookup(name: widget.planPreventiveVisit.visitStatus?.name ?? "", id: widget.planPreventiveVisit.visitStatus?.id?.toInt()),
// title: context.translation.ppmVisit,
// onSelect: (value) {
// if (value?.value == 4) {
// "Status cannot be change to ${value?.name}.".addTranslation.showToast;
// setState(() {});
// return;
// }
//
// if (value != null) {
// widget.planPreventiveVisit.visitStatus?.name = value.name;
// widget.planPreventiveVisit.visitStatus?.id = value.id;
// }
// },
// ),
// SingleItemDropDownMenu<Lookup, PPMDeviceStatusProvider>(
// context: context,
// initialValue: widget.planPreventiveVisit.deviceStatusId == null ? null : Lookup(name: widget.model.deviceStatusName ?? "", id: widget.model.deviceStatusId?.toInt()),
// title: context.translation.deviceStatus,
// onSelect: (value) {
// if (value != null) {
// widget.planPreventiveVisit.deviceStatusId = value.id;
// widget.planPreventiveVisit.deviceStatusName = value.name;
// }
// },
// ),
8.height,
Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
//TODO Ahmed need to provide look up value....
SingleItemDropDownMenu<Lookup, PpmTaskStatusProvider>(
context: context,
showShadow: false,
initialValue: widget.planPreventiveVisit.taskStatus == null ? null : Lookup(name: widget.planPreventiveVisit.taskStatus?.name ?? "", id: widget.planPreventiveVisit.taskStatus?.id),
title: context.translation.pmTestResult,
backgroundColor: AppColor.neutral100,
onSelect: (value) {
if (value != null) {
widget.planPreventiveVisit.taskStatus = value;
}
},
),
8.height,
ADatePicker(
label: context.translation.actualVisit,
hideShadow: true,
backgroundColor: AppColor.neutral100,
date: widget.planPreventiveVisit.acutalDateOfVisit,
formatDateWithTime: true,
onDatePicker: (selectedDate) {
showTimePicker(
context: context,
initialTime: TimeOfDay.now(),
).then((selectedTime) {
if (selectedTime != null) {
DateTime selectedDateTime = DateTime(
selectedDate.year,
selectedDate.month,
selectedDate.day,
selectedTime.hour,
selectedTime.minute,
);
setState(() {
widget.planPreventiveVisit.acutalDateOfVisit = selectedDateTime;
});
}
});
},
),
// SingleItemDropDownMenu<Lookup, PpmElectricalSafetyProvider>(
// context: context,
// backgroundColor: AppColor.neutral100,
// initialValue: widget.planPreventiveVisit.safety?.id == null ? null : Lookup(name: widget.planPreventiveVisit.safety?.name ?? "", id: widget.planPreventiveVisit.safety?.id),
// title: context.translation.actualVisit,
// onSelect: (value) {
// if (value != null) {
// widget.planPreventiveVisit.safety = value;
// // widget.planPreventiveVisit.safety?.id = value.id;
// // widget.planPreventiveVisit.safety?.name = value.name;
// }
// },
// ),
// SingleItemDropDownMenu<Lookup, PPMDeviceStatusProvider>(
// context: context,
// initialValue: widget.planPreventiveVisit.deviceStatusId == null ? null : Lookup(name: widget.model.deviceStatusName ?? "", id: widget.model.deviceStatusId?.toInt()),
// title: context.translation.deviceStatus,
// onSelect: (value) {
// if (value != null) {
// widget.planPreventiveVisit.deviceStatusId = value.id;
// widget.planPreventiveVisit.deviceStatusName = value.name;
// }
// },
// ),
8.height,
Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
SingleItemDropDownMenu<Lookup, PpmTaskStatusProvider>(
context: context,
showShadow: false,
initialValue: widget.planPreventiveVisit.taskStatus == null ? null : Lookup(name: widget.planPreventiveVisit.taskStatus?.name ?? "", id: widget.planPreventiveVisit.taskStatus?.id),
title: context.translation.pmTestResult,
backgroundColor: AppColor.neutral100,
onSelect: (value) {
if (value != null) {
widget.planPreventiveVisit.taskStatus = value;
}
},
),
8.height,
ADatePicker(
label: context.translation.actualVisit,
hideShadow: true,
backgroundColor: AppColor.neutral100,
date: widget.planPreventiveVisit.acutalDateOfVisit,
formatDateWithTime: true,
onDatePicker: (selectedDate) {
showTimePicker(
context: context,
initialTime: TimeOfDay.now(),
).then((selectedTime) {
if (selectedTime != null) {
DateTime selectedDateTime = DateTime(
selectedDate.year,
selectedDate.month,
selectedDate.day,
selectedTime.hour,
selectedTime.minute,
);
setState(() {
widget.planPreventiveVisit.acutalDateOfVisit = selectedDateTime;
});
}
});
},
),
// SingleItemDropDownMenu<Lookup, PpmElectricalSafetyProvider>(
// context: context,
// backgroundColor: AppColor.neutral100,
// initialValue: widget.planPreventiveVisit.safety?.id == null ? null : Lookup(name: widget.planPreventiveVisit.safety?.name ?? "", id: widget.planPreventiveVisit.safety?.id),
// title: context.translation.actualVisit,
// onSelect: (value) {
// if (value != null) {
// widget.planPreventiveVisit.safety = value;
// // widget.planPreventiveVisit.safety?.id = value.id;
// // widget.planPreventiveVisit.safety?.name = value.name;
// }
// },
// ),
8.height,
SingleItemDropDownMenu<Lookup, PpmElectricalSafetyProvider>(
context: context,
backgroundColor: AppColor.neutral100,
showShadow: false,
initialValue: widget.planPreventiveVisit.safety?.id == null ? null : Lookup(name: widget.planPreventiveVisit.safety?.name ?? "", id: widget.planPreventiveVisit.safety?.id),
title: "Electrical Safety",
onSelect: (value) {
if (value != null) {
widget.planPreventiveVisit.safety = value;
}
},
),
8.height,
SingleItemDropDownMenu<Lookup, PpmAssetAvailabilityProvider>(
context: context,
backgroundColor: AppColor.neutral100,
showShadow: false,
initialValue: widget.planPreventiveVisit.assetAvailability == null
? null
: Lookup(name: widget.planPreventiveVisit.assetAvailability?.name ?? "", id: widget.planPreventiveVisit.assetAvailability?.id),
title: "Asset Availability",
onSelect: (value) {
if (value != null) {
widget.planPreventiveVisit.assetAvailability = value;
}
},
),
8.height,
SingleItemDropDownMenu<Lookup, PpmServiceProvider>(
context: context,
backgroundColor: AppColor.neutral100,
showShadow: false,
initialValue: widget.planPreventiveVisit.typeOfService == null
? null
: Lookup(name: widget.planPreventiveVisit.typeOfService?.name ?? "", id: widget.planPreventiveVisit.typeOfService?.id?.toInt()),
title: context.translation.typeOfPm,
onSelect: (value) {
if (value != null) {
widget.planPreventiveVisit.typeOfService = value;
if (widget.planPreventiveVisit.typeOfService?.id == 66) {
ppmProvider.totalTabs = 4;
} else {
ppmProvider.totalTabs = 3;
}
widget.onTypeOfServiceChange!(value);
}
},
),
8.height,
_timerWidget(context, totalWorkingHours),
8.height,
AppTextFormField(
labelText: context.translation.callComments,
backgroundColor: AppColor.neutral100,
showShadow: false,
initialValue: (widget.planPreventiveVisit.comments ?? "").toString(),
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.titleMedium,
onChange: (value) {
widget.planPreventiveVisit.comments = value;
},
),
16.height,
MultiFilesPicker(
label: context.translation.attachments,
files: ppmProvider.ppmPlanAttachments,
buttonColor: AppColor.black10,
onlyImages: false,
buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.neutral120),
),
],
).toShadowContainer(context),
8.height,
SingleItemDropDownMenu<Lookup, PpmElectricalSafetyProvider>(
context: context,
backgroundColor: AppColor.neutral100,
showShadow: false,
initialValue: widget.planPreventiveVisit.safety?.id == null ? null : Lookup(name: widget.planPreventiveVisit.safety?.name ?? "", id: widget.planPreventiveVisit.safety?.id),
title: "Electrical Safety",
onSelect: (value) {
if (value != null) {
widget.planPreventiveVisit.safety = value;
}
},
),
8.height,
SingleItemDropDownMenu<Lookup, PpmAssetAvailabilityProvider>(
context: context,
backgroundColor: AppColor.neutral100,
showShadow: false,
initialValue: widget.planPreventiveVisit.assetAvailability == null
? null
: Lookup(name: widget.planPreventiveVisit.assetAvailability?.name ?? "", id: widget.planPreventiveVisit.assetAvailability?.id),
title: "Asset Availability",
onSelect: (value) {
if (value != null) {
widget.planPreventiveVisit.assetAvailability = value;
}
},
),
8.height,
SingleItemDropDownMenu<Lookup, PpmServiceProvider>(
context: context,
backgroundColor: AppColor.neutral100,
showShadow: false,
initialValue: widget.planPreventiveVisit.typeOfService == null
? null
: Lookup(name: widget.planPreventiveVisit.typeOfService?.name ?? "", id: widget.planPreventiveVisit.typeOfService?.id?.toInt()),
title: context.translation.typeOfPm,
onSelect: (value) {
if (value != null) {
widget.planPreventiveVisit.typeOfService = value;
if (widget.planPreventiveVisit.typeOfService?.id == 66) {
ppmProvider.totalTabs = 4;
} else {
ppmProvider.totalTabs = 3;
}
widget.onTypeOfServiceChange!(value);
}
},
),
8.height,
_timerWidget(context, totalWorkingHours),
8.height,
AppTextFormField(
labelText: context.translation.comment,
backgroundColor: AppColor.neutral100,
showShadow: false,
initialValue: (widget.planPreventiveVisit.comments ?? "").toString(),
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.titleMedium,
onChange: (value) {
widget.planPreventiveVisit.comments = value;
},
),
16.height,
MultiFilesPicker(
label: context.translation.attachments,
files: ppmProvider.ppmPlanAttachments,
buttonColor: AppColor.black10,
onlyImages: false,
buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.neutral120),
),
],
).toShadowContainer(context),
],
),
),
//TODO need to check this also...
// ESignature(
// title: context.translation.nurseSignature,
@ -292,6 +321,33 @@ class _WoInfoFormState extends State<WoInfoForm> {
});
}
_buildAssetDetailBottomSheet(BuildContext context) {
PlanPreventiveVisit model = widget.planPreventiveVisit;
Asset asset = Asset(
id: model.asset?.id,
assetSerialNo: model.asset?.assetSerialNo,
assetNumber: model.asset?.assetNumber,
building: Building(name: model.buildingName),
floor: Floor(name: model.floorName),
site: Site(custName: model.siteName),
supplier: Supplier(suppliername: model.supplierName),
modelDefinition: ModelDefinition(modelName: model.model, manufacturerName: model.manufacturer),
room: Rooms(value: int.tryParse(model.roomName??'')),
department: Department(departmentName: model.departmentName),
);
return AssetDetailBottomSheet(asset);
}
// Future<Asset> getAssetById () async {
// Asset asset = Asset();
// AssetProvider _assetProvider = Provider.of<AssetProvider>(context, listen: false);
// if(widget.planPreventiveVisit.asset!=null){
// AssetByIdModel ?assetByIdModel = await _assetProvider.getAssetById(widget.planPreventiveVisit.asset!.id!.toInt(), context.translation);
// asss
// }
// return asset;
// }
Widget _timerWidget(BuildContext context, double totalWorkingHours) {
return Column(
children: [

@ -18,7 +18,7 @@ class PendingServiceRequestScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: DefaultAppBar(title: "Pending Requests (${pendingAssetServiceRequest.details!.length})"),
appBar: DefaultAppBar(title: "Pending WOs (${pendingAssetServiceRequest.details!.length})"),
body: ListView.separated(
itemCount: pendingAssetServiceRequest.details!.length,
padding: const EdgeInsets.all(16),

@ -48,9 +48,9 @@ class AssetDetailBottomSheet extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"${context.translation.assetNo}: ${asset!.assetNumber}".bodyText(context),
"${context.translation.modelName}: ${asset!.modelDefinition!.modelName}".bodyText(context),
"${context.translation.modelName}: ${asset!.modelDefinition?.modelName}".bodyText(context),
"${context.translation.supplier}: ${asset!.supplier?.suppliername?.cleanupWhitespace.capitalizeFirstOfEach ?? "-"}".bodyText(context),
"${context.translation.manufacture}: ${asset!.modelDefinition!.manufacturerName?.cleanupWhitespace.capitalizeFirstOfEach}".bodyText(context),
"${context.translation.manufacture}: ${asset!.modelDefinition?.manufacturerName?.cleanupWhitespace.capitalizeFirstOfEach}".bodyText(context),
//"${context.translation.location}: ${assetModel.site.custName?.cleanupWhitespace?.capitalizeFirstOfEach}".bodyText(context),
],
).expanded,

@ -25,7 +25,7 @@ class PendingRequestBottomSheet extends StatelessWidget {
"Alert!".heading4(context),
12.height,
Text(
"${pendingAssetServiceRequest.details!.length} pending service requests found",
"${pendingAssetServiceRequest.details!.length} pending corrective maintenance found",
style: TextStyle(
fontSize: 16.toScreenWidth,
fontWeight: FontWeight.w500,

@ -19,6 +19,7 @@ class AssetPicker extends StatelessWidget {
final bool showAssetInfo;
final Color? borderColor;
final Color? buttonColor;
Color? backgroundColor;
final bool forPPM;
final bool showLoading;
final bool multiSelection;
@ -33,6 +34,7 @@ class AssetPicker extends StatelessWidget {
this.onAssetRemove,
this.borderColor,
this.buttonColor,
this.backgroundColor,
this.showAssetInfo = true,
this.multiSelection = false,
this.forPPM = false,
@ -53,7 +55,7 @@ class AssetPicker extends StatelessWidget {
height: 50,
alignment: Alignment.center,
decoration: BoxDecoration(
color: buttonColor ?? AppColor.blueStatus(context),
color: buttonColor ?? backgroundColor?? AppColor.blueStatus(context),
borderRadius: BorderRadius.circular(10),
// boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.03), blurRadius: 14)],
),

@ -54,7 +54,7 @@ class _CommissioningStatusButtonsState extends State<CommissioningStatusButtons>
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
context.translation.equipmentStatus.heading5(context).paddingOnly(start: 16, end: 16),
context.translation.assetStatus.heading5(context).paddingOnly(start: 16, end: 16),
8.height,
Consumer<CommissioningStatusProvider>(
builder: (context, snapshot, _) {

@ -41,7 +41,7 @@ class GasRefillItem extends StatelessWidget {
),
8.height,
context.translation.gasRefillRequest.heading5(context),
'${context.translation.gasType}: ${item.gazRefillDetails![0].gasType!.name}'.bodyText(context),
'${context.translation.gasType}: ${item.gasRefillDetails![0].gasType!.name}'.bodyText(context),
'${context.translation.site}: ${item.site!.name}'.bodyText(context),
8.height,
Row(

@ -18,6 +18,7 @@ class MultiFilesPicker extends StatefulWidget {
final String label;
final bool error;
final List<File> files;
final List<AttachmentModel> attachment ;
final bool enabled, onlyImages;
double? buttonHeight;
Widget? buttonIcon;
@ -28,6 +29,7 @@ class MultiFilesPicker extends StatefulWidget {
MultiFilesPicker(
{Key? key,
this.files = const <File>[],
this.attachment = const <AttachmentModel>[],
required this.label,
this.error = false,
this.buttonHeight,
@ -49,17 +51,19 @@ class _MultiFilesPickerState extends State<MultiFilesPicker> {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
AppDashedButton(
title: widget.label,
height: widget.buttonHeight,
buttonColor: widget.buttonColor,
icon: widget.buttonIcon,
onPressed: (widget.enabled == false)
? () {}
: widget.showAsGrid
? showFileSourceSheet
: onFilePicker),
16.height,
if(widget.enabled)...[
AppDashedButton(
title: widget.label,
height: widget.buttonHeight,
buttonColor: widget.buttonColor,
icon: widget.buttonIcon,
onPressed: (widget.enabled == false)
? () {}
: widget.showAsGrid
? showFileSourceSheet
: onFilePicker),
16.height,
],
if (widget.files.isNotEmpty)
Wrap(
spacing: 8.toScreenWidth,
@ -123,10 +127,10 @@ class _MultiFilesPickerState extends State<MultiFilesPicker> {
"Attach File".heading4(context),
12.height,
GridView(
padding: EdgeInsets.all(0),
padding: const EdgeInsets.all(0),
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3, childAspectRatio: 1, crossAxisSpacing: 12, mainAxisSpacing: 12),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3, childAspectRatio: 1, crossAxisSpacing: 12, mainAxisSpacing: 12),
children: <Widget>[
gridItem(Icons.camera_enhance_rounded, context.translation.pickFromCamera).onPress(() => Navigator.of(context).pop(ImageSource.camera)),
gridItem(Icons.image_rounded, context.translation.pickFromGallery).onPress(() => Navigator.of(context).pop(ImageSource.gallery)),
@ -141,38 +145,34 @@ class _MultiFilesPickerState extends State<MultiFilesPicker> {
).paddingAll(21),
)) as ImageSource;
if (source == null) return;
final pickedFile = await ImagePicker().pickImage(source: source, imageQuality: 70, maxWidth: 800, maxHeight: 800);
if (pickedFile != null) {
File fileImage = File(pickedFile.path);
if (fileImage != null) {
widget.files.add(fileImage);
if (widget.onChange != null) {
widget.onChange!(widget.files);
}
setState(() {});
widget.files.add(fileImage);
if (widget.onChange != null) {
widget.onChange!(widget.files);
}
}
setState(() {});
}
}
Widget gridItem(IconData iconData, String title) {
return Container(
padding: EdgeInsets.all(12),
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Color(0xffF1F1F1), width: 1),
border: Border.all(color: const Color(0xffF1F1F1), width: 1),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Icon(iconData, color: Color(0xff7D859A), size: 36),
Icon(iconData, color: const Color(0xff7D859A), size: 36),
Text(
title,
style: TextStyle(fontSize: 12, fontWeight: FontWeight.w500),
style: const TextStyle(fontSize: 12, fontWeight: FontWeight.w500),
),
],
),
@ -285,3 +285,295 @@ class _MultiFilesPickerState extends State<MultiFilesPicker> {
setState(() {});
}
}
class AttachmentModel {
int id =0;
File ? file;
AttachmentModel(this.id,this.file);
factory AttachmentModel.fromJson(Map<String, dynamic> json) {
return AttachmentModel(
json['id'] ?? 0,
json['file'] != null ? File(json['file']) : null,
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'file': file?.path,
};
}
}
class AttachmentPicker extends StatefulWidget {
final String label;
final bool error;
final List<AttachmentModel> attachment ;
final bool enabled, onlyImages;
double? buttonHeight;
Widget? buttonIcon;
Color? buttonColor;
final Function(List<AttachmentModel>)? onChange;
final bool showAsGrid;
AttachmentPicker(
{Key? key,
this.attachment = const <AttachmentModel>[],
required this.label,
this.error = false,
this.buttonHeight,
this.buttonIcon,
this.enabled = true,
this.onlyImages = false,
this.onChange,
this.showAsGrid = false,
this.buttonColor})
: super(key: key);
@override
State<AttachmentPicker> createState() => _AttachmentPickerState();
}
class _AttachmentPickerState extends State<AttachmentPicker> {
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
AppDashedButton(
title: widget.label,
height: widget.buttonHeight,
buttonColor: widget.buttonColor,
icon: widget.buttonIcon,
onPressed: (widget.enabled == false)
? () {}
: widget.showAsGrid
? showFileSourceSheet
: onFilePicker),
16.height,
if (widget.attachment.isNotEmpty)
Wrap(
spacing: 8.toScreenWidth,
children: List.generate(
widget.attachment.length,
(index) {
File image = widget.attachment[index].file!;
return MultiFilesPickerItem(
file: image,
enabled: widget.enabled,
onRemoveTap: (image) {
if (!widget.enabled) {
return;
}
widget.attachment.remove(image);
if (widget.onChange != null) {
widget.onChange!(widget.attachment);
}
setState(() {});
},
);
},
),
),
],
);
}
fromFilePicker() async {
FilePickerResult? result = await FilePicker.platform.pickFiles(
type: FileType.custom,
allowMultiple: true,
allowedExtensions: widget.onlyImages ? ['jpg', 'jpeg', 'png'] : ['jpg', 'jpeg', 'png', 'pdf', 'doc', 'docx', 'xlsx', 'pptx'],
);
if (result != null) {
for (var path in result.paths) {
widget.attachment.add(AttachmentModel(0, File(path!)));
}
setState(() {});
}
}
void showFileSourceSheet() async {
if (widget.attachment.length >= 5) {
Fluttertoast.showToast(msg: context.translation.maxImagesNumberIs5);
return;
}
ImageSource source = (await showModalBottomSheet(
context: context,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(20),
),
),
clipBehavior: Clip.antiAliasWithSaveLayer,
builder: (BuildContext context) => Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Attach File".heading4(context),
12.height,
GridView(
padding: const EdgeInsets.all(0),
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3, childAspectRatio: 1, crossAxisSpacing: 12, mainAxisSpacing: 12),
children: <Widget>[
gridItem(Icons.camera_enhance_rounded, context.translation.pickFromCamera).onPress(() => Navigator.of(context).pop(ImageSource.camera)),
gridItem(Icons.image_rounded, context.translation.pickFromGallery).onPress(() => Navigator.of(context).pop(ImageSource.gallery)),
gridItem(Icons.file_present_rounded, context.translation.pickFromFiles).onPress(() async {
await fromFilePicker();
Navigator.pop(context);
}),
],
),
12.height,
],
).paddingAll(21),
)) as ImageSource;
final pickedFile = await ImagePicker().pickImage(source: source, imageQuality: 70, maxWidth: 800, maxHeight: 800);
if (pickedFile != null) {
File fileImage = File(pickedFile.path);
widget.attachment.add(AttachmentModel(0, fileImage));
if (widget.onChange != null) {
widget.onChange!(widget.attachment);
}
setState(() {});
}
}
Widget gridItem(IconData iconData, String title) {
return Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: const Color(0xffF1F1F1), width: 1),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Icon(iconData, color: const Color(0xff7D859A), size: 36),
Text(
title,
style: const TextStyle(fontSize: 12, fontWeight: FontWeight.w500),
),
],
),
);
}
onFilePicker() async {
if (widget.attachment.length >= 5) {
Fluttertoast.showToast(msg: context.translation.maxImagesNumberIs5);
return;
}
ImageSource? source = await showModalBottomSheet<ImageSource>(
context: context,
builder: (BuildContext context) {
Widget listCard({required String icon, required String label, required VoidCallback onTap}){
return GestureDetector(
onTap: onTap,
child: Container(
constraints: BoxConstraints(minWidth: 111.toScreenWidth,minHeight: 111.toScreenHeight),
padding: EdgeInsets.symmetric(horizontal: 12.toScreenWidth,vertical: 12.toScreenHeight),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
border: Border.all(width: 1,color:AppColor.white70)
),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
icon.toSvgAsset(),
24.height,
label.bodyText2(context).custom(color: AppColor.black20),
],
),
),
);
}
return Container(
padding: const EdgeInsets.all(16.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
listCard(
icon: 'camera_icon',
label: '${context.translation.open}\n${context.translation.camera}',
onTap: () {
Navigator.of(context).pop(ImageSource.camera);
},
),
listCard(
icon: 'gallery_icon',
label: '${context.translation.open}\n${context.translation.gallery}',
onTap: () {
Navigator.of(context).pop(ImageSource.gallery);
},
),
listCard(
icon: 'file_icon',
label: '${context.translation.open}\n${context.translation.files}',
onTap: () async {
await fromFilePicker();
Navigator.pop(context);
},
),
],
),
);
},
);
// ImageSource source = await showDialog(
// context: context,
// builder: (dialogContext) => CupertinoAlertDialog(
// actions: <Widget>[
// TextButton(
// child: Text(context.translation.pickFromCamera),
// onPressed: () {
// Navigator.of(dialogContext).pop(ImageSource.camera);
// },
// ),
// TextButton(
// child: Text(context.translation.pickFromGallery),
// onPressed: () {
// Navigator.of(dialogContext).pop(ImageSource.gallery);
// },
// ),
// TextButton(
// child: Text(context.translation.pickFromFiles),
// onPressed: () async {
// await fromFilePicker();
// Navigator.pop(context);
// },
// ),
// ],
// ),
// );
if (source == null) return;
final pickedFile = await ImagePicker().pickImage(source: source, imageQuality: 70, maxWidth: 800, maxHeight: 800);
if (pickedFile != null) {
File fileImage = File(pickedFile.path);
widget.attachment.add(AttachmentModel(0, fileImage));
if (widget.onChange != null) {
widget.onChange!(widget.attachment);
}
setState(() {});
}
setState(() {});
}
}

@ -32,6 +32,7 @@ class _AutoCompletePartsFieldState extends State<AutoCompletePartsField> {
@override
void initState() {
print('initial value i got is ${widget.initialValue}');
_controller = TextEditingController(text: widget.initialValue);
super.initState();
}

@ -18,8 +18,9 @@ class AssistantEmployeeMenu extends StatefulWidget {
final String? title; // Now nullable
final bool enable;
final bool showAsBottomSheet;
final bool hideShadow;
AssistantEmployeeMenu({Key? key, required this.statuses, this.title, this.showAsBottomSheet = false, required this.onSelect, this.initialStatus, this.backgroundColor, this.enable = true})
AssistantEmployeeMenu({Key? key, required this.statuses, this.title, this.showAsBottomSheet = false,this.hideShadow = false, required this.onSelect, this.initialStatus, this.backgroundColor, this.enable = true})
: super(key: key);
@override
@ -74,7 +75,7 @@ class _SingleAssistantEmployeeMenuState extends State<AssistantEmployeeMenu> {
decoration: BoxDecoration(
color: widget.backgroundColor ?? (context.isDark ? AppColor.neutral50 : AppColor.neutral120),
borderRadius: BorderRadius.circular(10),
boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)],
boxShadow: widget.hideShadow ? null : [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)],
),
child: Stack(
alignment: Alignment.center,

@ -31,6 +31,7 @@ class ServiceReportAssistantEmployeeMenu extends StatelessWidget {
initialStatus: initialValue,
title: title,
showAsBottomSheet: true,
hideShadow: true,
statuses: menuProvider.assistantEmployees ?? [],
backgroundColor: backgroundColor,
// Provide an empty list if null

@ -1213,6 +1213,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "6.0.2"
pie_chart:
dependency: "direct main"
description:
name: pie_chart
sha256: "58e6a46999ac938bfa1c3e5be414d6e149f037647197dca03ba3614324c12c82"
url: "https://pub.dev"
source: hosted
version: "5.4.0"
pinput:
dependency: "direct main"
description:
@ -1506,22 +1514,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.2.0"
syncfusion_flutter_charts:
dependency: "direct main"
description:
name: syncfusion_flutter_charts
sha256: a755274a8786b200b7a05f7414168cd5858871db74d0f1de2e57b20a8aaeb7a4
url: "https://pub.dev"
source: hosted
version: "26.2.14"
syncfusion_flutter_core:
dependency: transitive
description:
name: syncfusion_flutter_core
sha256: "6e67726b85812afc7105725a23620b876ab7f6b04b8410e211330ffb8c2cdbe8"
url: "https://pub.dev"
source: hosted
version: "26.2.14"
synchronized:
dependency: transitive
description:

@ -79,11 +79,11 @@ dependencies:
image_cropper: ^8.0.2
flutter_timezone: ^3.0.1
device_calendar: ^4.3.3
pie_chart: ^5.4.0
badges: ^3.1.1
# buttons_tabbar: ^1.1.2
flutter_custom_month_picker: ^0.1.3
syncfusion_flutter_charts: ^26.2.14
local_auth: ^2.3.0
google_api_availability: ^5.0.0
huawei_push: ^6.5.0+300

Loading…
Cancel
Save