Merge remote-tracking branch 'origin/main_latest_merged' into main_latest_merged

# Conflicts:
#	ios/Podfile.lock
#	ios/Runner.xcodeproj/project.pbxproj
main_design2.0
Sikander Saleem 2 years ago
commit c6c6aa5bce

@ -49,30 +49,30 @@ android {
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration.
minSdkVersion 21
targetSdkVersion 33
versionCode 1
versionName '1.0.0'
versionCode 3
versionName '1.0.3'
}
signingConfigs {
// release {
// keyAlias keystoreProperties['keyAlias']
// keyPassword keystoreProperties['keyPassword']
// storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
// storePassword keystoreProperties['storePassword']
// }
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
storePassword keystoreProperties['storePassword']
}
}
buildTypes {
debug {
signingConfig signingConfigs.debug
}
release {
signingConfig signingConfigs.debug
}
// release {
// minifyEnabled true
// shrinkResources true
// signingConfig signingConfigs.release
// signingConfig signingConfigs.debug
// }
release {
minifyEnabled true
shrinkResources true
signingConfig signingConfigs.release
}
}
}

@ -1,5 +1,5 @@
buildscript {
ext.kotlin_version = '1.6.10'
ext.kotlin_version = '1.8.20'
repositories {
google()
mavenCentral()

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

@ -167,7 +167,7 @@
"newServiceReport": "تقرير خدمة جديد",
"number": "رقم",
"operatingHours": "ساعات العمل",
"partNumber": "رقم القطعة",
"partNumberName": "رقم/اسم القطعة",
"quantity": "كمية",
"reasons": "الاسباب",
"reportStatus": "حالة التقرير",
@ -201,5 +201,9 @@
"floor": "طابق",
"department": "قسم",
"room": "غرفه",
"actions": "اجراءات"
"actions": "اجراءات",
"deviceFiles": "ملفات الجهاز",
"pickFromFiles" : "اختر من الملفات",
"requiredFile" : "الملف مطلوب",
"pickFile" : "اختر ملف"
}

@ -73,7 +73,7 @@
"deviceImages": "Asset Images",
"deviceModel": "Asset Model",
"deviceRequired": "Asset Required",
"deviceSN": "Asset SN",
"deviceSN": "Asset Serial Number",
"engineerName": "Engineer Name",
"engineerPhone": "Engineer Phone",
"facebook": "facebook",
@ -167,7 +167,7 @@
"newServiceReport": "New Work Order",
"number": "Number",
"operatingHours": "Operating Hours",
"partNumber": "Part Number",
"partNumberName": "Part Number/Name",
"quantity": "Quantity",
"reasons": "Reasons",
"reportStatus": "Report Status",
@ -201,5 +201,9 @@
"floor": "Floor",
"department": "Department",
"room": "Room",
"actions": "Actions"
"actions": "Actions",
"deviceFiles": "Asset Files",
"pickFromFiles" : "Pick From Files",
"requiredFile" : "File Required",
"pickFile" : "Pick File"
}

@ -41,4 +41,16 @@ post_install do |installer|
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '12.0'
end
end
installer.generated_projects.each do |project|
project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '12.0'
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
'$(inherited)',
## dart: PermissionGroup.microphone
'PERMISSION_MICROPHONE=1',
]
end
end
end
end

@ -0,0 +1,268 @@
PODS:
- audioplayers_darwin (0.0.1):
- Flutter
- DKImagePickerController/Core (4.3.4):
- DKImagePickerController/ImageDataManager
- DKImagePickerController/Resource
- DKImagePickerController/ImageDataManager (4.3.4)
- DKImagePickerController/PhotoGallery (4.3.4):
- DKImagePickerController/Core
- DKPhotoGallery
- DKImagePickerController/Resource (4.3.4)
- DKPhotoGallery (0.0.17):
- DKPhotoGallery/Core (= 0.0.17)
- DKPhotoGallery/Model (= 0.0.17)
- DKPhotoGallery/Preview (= 0.0.17)
- DKPhotoGallery/Resource (= 0.0.17)
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Core (0.0.17):
- DKPhotoGallery/Model
- DKPhotoGallery/Preview
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Model (0.0.17):
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Preview (0.0.17):
- DKPhotoGallery/Model
- DKPhotoGallery/Resource
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Resource (0.0.17):
- SDWebImage
- SwiftyGif
- file_picker (0.0.1):
- DKImagePickerController/PhotoGallery
- Flutter
- Firebase/CoreOnly (10.12.0):
- FirebaseCore (= 10.12.0)
- Firebase/Messaging (10.12.0):
- Firebase/CoreOnly
- FirebaseMessaging (~> 10.12.0)
- firebase_core (2.15.0):
- Firebase/CoreOnly (= 10.12.0)
- Flutter
- firebase_messaging (14.6.5):
- Firebase/Messaging (= 10.12.0)
- firebase_core
- Flutter
- FirebaseCore (10.12.0):
- FirebaseCoreInternal (~> 10.0)
- GoogleUtilities/Environment (~> 7.8)
- GoogleUtilities/Logger (~> 7.8)
- FirebaseCoreInternal (10.12.0):
- "GoogleUtilities/NSData+zlib (~> 7.8)"
- FirebaseInstallations (10.12.0):
- FirebaseCore (~> 10.0)
- GoogleUtilities/Environment (~> 7.8)
- GoogleUtilities/UserDefaults (~> 7.8)
- PromisesObjC (~> 2.1)
- FirebaseMessaging (10.12.0):
- FirebaseCore (~> 10.0)
- FirebaseInstallations (~> 10.0)
- GoogleDataTransport (~> 9.2)
- GoogleUtilities/AppDelegateSwizzler (~> 7.8)
- GoogleUtilities/Environment (~> 7.8)
- GoogleUtilities/Reachability (~> 7.8)
- GoogleUtilities/UserDefaults (~> 7.8)
- nanopb (< 2.30910.0, >= 2.30908.0)
- Flutter (1.0.0)
- flutter_keyboard_visibility (0.0.1):
- Flutter
- flutter_local_notifications (0.0.1):
- Flutter
- flutter_sound (9.2.13):
- Flutter
- flutter_sound_core (= 9.2.13)
- flutter_sound_core (9.2.13)
- fluttertoast (0.0.2):
- Flutter
- Toast
- FMDB (2.7.5):
- FMDB/standard (= 2.7.5)
- FMDB/standard (2.7.5)
- GoogleDataTransport (9.2.3):
- GoogleUtilities/Environment (~> 7.7)
- nanopb (< 2.30910.0, >= 2.30908.0)
- PromisesObjC (< 3.0, >= 1.2)
- GoogleUtilities/AppDelegateSwizzler (7.11.4):
- GoogleUtilities/Environment
- GoogleUtilities/Logger
- GoogleUtilities/Network
- GoogleUtilities/Environment (7.11.4):
- PromisesObjC (< 3.0, >= 1.2)
- GoogleUtilities/Logger (7.11.4):
- GoogleUtilities/Environment
- GoogleUtilities/Network (7.11.4):
- GoogleUtilities/Logger
- "GoogleUtilities/NSData+zlib"
- GoogleUtilities/Reachability
- "GoogleUtilities/NSData+zlib (7.11.4)"
- GoogleUtilities/Reachability (7.11.4):
- GoogleUtilities/Logger
- GoogleUtilities/UserDefaults (7.11.4):
- GoogleUtilities/Logger
- image_picker_ios (0.0.1):
- Flutter
- MTBBarcodeScanner (5.0.11)
- nanopb (2.30909.0):
- nanopb/decode (= 2.30909.0)
- nanopb/encode (= 2.30909.0)
- nanopb/decode (2.30909.0)
- nanopb/encode (2.30909.0)
- package_info (0.0.1):
- Flutter
- path_provider_foundation (0.0.1):
- Flutter
- FlutterMacOS
- permission_handler_apple (9.1.1):
- Flutter
- PromisesObjC (2.3.1)
- qr_code_scanner (0.2.0):
- Flutter
- MTBBarcodeScanner
- SDWebImage (5.17.0):
- SDWebImage/Core (= 5.17.0)
- SDWebImage/Core (5.17.0)
- share (0.0.1):
- Flutter
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
- speech_to_text (0.0.1):
- Flutter
- Try
- sqflite (0.0.3):
- Flutter
- FMDB (>= 2.7.5)
- SwiftyGif (5.4.4)
- Toast (4.0.0)
- Try (2.1.1)
- url_launcher_ios (0.0.1):
- Flutter
DEPENDENCIES:
- audioplayers_darwin (from `.symlinks/plugins/audioplayers_darwin/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`)
- fluttertoast (from `.symlinks/plugins/fluttertoast/ios`)
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
- package_info (from `.symlinks/plugins/package_info/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/ios`)
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
- qr_code_scanner (from `.symlinks/plugins/qr_code_scanner/ios`)
- share (from `.symlinks/plugins/share/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/ios`)
- speech_to_text (from `.symlinks/plugins/speech_to_text/ios`)
- sqflite (from `.symlinks/plugins/sqflite/ios`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
SPEC REPOS:
trunk:
- DKImagePickerController
- DKPhotoGallery
- Firebase
- FirebaseCore
- FirebaseCoreInternal
- FirebaseInstallations
- FirebaseMessaging
- flutter_sound_core
- FMDB
- GoogleDataTransport
- GoogleUtilities
- MTBBarcodeScanner
- nanopb
- PromisesObjC
- SDWebImage
- SwiftyGif
- Toast
- Try
EXTERNAL SOURCES:
audioplayers_darwin:
:path: ".symlinks/plugins/audioplayers_darwin/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"
fluttertoast:
:path: ".symlinks/plugins/fluttertoast/ios"
image_picker_ios:
:path: ".symlinks/plugins/image_picker_ios/ios"
package_info:
:path: ".symlinks/plugins/package_info/ios"
path_provider_foundation:
:path: ".symlinks/plugins/path_provider_foundation/ios"
permission_handler_apple:
:path: ".symlinks/plugins/permission_handler_apple/ios"
qr_code_scanner:
:path: ".symlinks/plugins/qr_code_scanner/ios"
share:
:path: ".symlinks/plugins/share/ios"
shared_preferences_foundation:
:path: ".symlinks/plugins/shared_preferences_foundation/ios"
speech_to_text:
:path: ".symlinks/plugins/speech_to_text/ios"
sqflite:
:path: ".symlinks/plugins/sqflite/ios"
url_launcher_ios:
:path: ".symlinks/plugins/url_launcher_ios/ios"
SPEC CHECKSUMS:
audioplayers_darwin: 877d9a4d06331c5c374595e46e16453ac7eafa40
DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
file_picker: ce3938a0df3cc1ef404671531facef740d03f920
Firebase: 07150e75d142fb9399f6777fa56a187b17f833a0
firebase_core: e477125798fc37cd4ab43ca6a8536bf7e0929c00
firebase_messaging: 334d68c3a36b6d4d5cd91e4f42509e0d4ae49828
FirebaseCore: f86a1394906b97ac445ae49c92552a9425831bed
FirebaseCoreInternal: 950500ad8a08963657f6d8c67b579740c06d6aa1
FirebaseInstallations: 7b99ef103f013624444c614397038219c45f8e63
FirebaseMessaging: bb2c4f6422a753038fe137d90ae7c1af57251316
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069
flutter_local_notifications: 0c0b1ae97e741e1521e4c1629a459d04b9aec743
flutter_sound: c60effa2a350fb977885f0db2fbc4c1ad5160900
flutter_sound_core: 26c10e5832e76aaacfae252d8925232281c486ae
fluttertoast: fafc4fa4d01a6a9e4f772ecd190ffa525e9e2d9c
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
GoogleDataTransport: f0308f5905a745f94fb91fea9c6cbaf3831cb1bd
GoogleUtilities: c63691989bf362ba0505507da00eeb326192e83e
image_picker_ios: 4a8aadfbb6dc30ad5141a2ce3832af9214a705b5
MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb
nanopb: b552cce312b6c8484180ef47159bc0f65a1f0431
package_info: 873975fc26034f0b863a300ad47e7f1ac6c7ec62
path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6
PromisesObjC: c50d2056b5253dadbd6c2bea79b0674bd5a52fa4
qr_code_scanner: bb67d64904c3b9658ada8c402e8b4d406d5d796e
SDWebImage: 750adf017a315a280c60fde706ab1e552a3ae4e9
share: 0b2c3e82132f5888bccca3351c504d0003b3b410
shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126
speech_to_text: b43a7d99aef037bd758ed8e45d79bbac035d2dfe
sqflite: 31f7eba61e3074736dff8807a9b41581e4f7f15a
SwiftyGif: 93a1cc87bf3a51916001cf8f3d63835fb64c819f
Toast: 91b396c56ee72a5790816f40d3a94dd357abc196
Try: 5ef669ae832617b3cee58cb2c6f99fb767a4ff96
url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4
PODFILE CHECKSUM: 9addd1ae6176ca7bfe24f8bac9acf6aeb76cd8f5
COCOAPODS: 1.12.1

@ -7,7 +7,7 @@
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Atoms SA</string>
<string>Atoms</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
@ -15,7 +15,7 @@
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>Atoms SA</string>
<string>Atoms</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
@ -28,6 +28,8 @@
<false/>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>LSSupportsOpeningDocumentsInPlace</key>
<true/>
<key>NSCameraUsageDescription</key>
<string>This app requires permission to access Camera to allow user to attach images</string>
<key>NSMicrophoneUsageDescription</key>
@ -36,6 +38,8 @@
<string>This app requires permission to access photo gallery to allow user to attach images</string>
<key>NSSpeechRecognitionUsageDescription</key>
<string>This app requires permission for Speech Recognition for speech to text functionality.</string>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
@ -58,9 +62,9 @@
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportsDocumentBrowser</key>
<true/>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
</dict>
</plist>

@ -4,5 +4,7 @@
<dict>
<key>aps-environment</key>
<string>development</string>
<key>inter-app-audio</key>
<true/>
</dict>
</plist>

@ -1,7 +1,5 @@
import 'dart:convert';
import 'dart:developer';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:http/http.dart' as http;
@ -23,6 +21,7 @@ class ApiManager {
Future<http.Response> get(
String url, {
Map<String, String> headers,
enableToastMessage = true,
}) async {
headers ??= {};
@ -34,7 +33,7 @@ class ApiManager {
http.Response response = await http.get(_url, headers: headers);
if (jsonDecode(response.body) is Map<String, dynamic>) {
final message = jsonDecode(response.body)["message"];
if (message != null && message.toString().isNotEmpty) {
if (message != null && message.toString().isNotEmpty && enableToastMessage) {
Fluttertoast.showToast(msg: message ?? "", toastLength: Toast.LENGTH_LONG);
}
}

@ -1,8 +1,12 @@
class URLs {
URLs._();
static const host2 = "http://194.163.164.213/atoms/api";
static const host1 = "https://atomsuat.hmg.com"; // uat url
static const host2 = "http://194.163.164.213/atoms/api"; // todo @sikander will remove after confirmation
//static const host1 = "https://atomsuat.hmg.com"; // old uat url
//static const host1 = "https://atomsm.hmg.com"; // production url
static const host1 = "https://atomsmdev.hmg.com"; // local UAT url
// static const host1 = "http://109.123.243.118:9000";
@ -12,7 +16,9 @@ class URLs {
set host(String value) => _host = value;
static String getFileUrl(String file) => (file == null || file.isEmpty) ? null : (file.contains("/") ? file : "$_host/attachment/$file");
static String getFileUrl(String file) => (file == null || file.isEmpty) ? null : (file.contains("/") ? file : "$_baseUrl/Files/DownloadFile?fileName=$file");
// static String getFileUrl(String file) => (file == null || file.isEmpty) ? null :1 (file.contains("/") ? file : "$_host/attachment/$file");
// API Routes
static get login => "$_baseUrl/MobileAuth/LoginIntegration"; // post
@ -50,6 +56,8 @@ class URLs {
static get updateRegularVisits => "$_baseUrl/Visit/UpdateVisits"; // get
static get getSingleServiceRequest => "$_baseUrl/return/call/information"; // get
static get getSuppliersAutoComplete => "$_baseUrl/Supplier/GetSuppliersAutoComplete";
static get getNotifications => "$_baseUrl/return/user/notification"; // get
static get getRecentNotifications => "$_baseUrl/return/user/recent/notification"; // get
static get createRequest => "$_baseUrl/CallRequest/AddCallRequest"; // get
@ -63,13 +71,15 @@ class URLs {
static get createDuplicatedReport => "$_baseUrl/handle/duplicate/request"; // get
static get searchWorkOrders => "$_baseUrl/WorkOrder/SearchWorkOrders";
static get getSubWorkerInfoAccordingToPreviousStep => "$_baseUrl/WorkOrder/GetDataPreviousStep";
static get getServiceReportReasons => "$_baseUrl/Lookups/GetLookup?lookupEnum=522"; // get
static get getServiceReportTypes => "$_baseUrl/Lookups/GetLookup?lookupEnum=501"; // get
static get getServiceReportStatus => "$_baseUrl/Lookups/GetLookup?lookupEnum=521"; // get
static get getServiceReportLastCalls => "$_baseUrl/WorkOrder/GetLookupCallLastSituationBasedOnCase"; // get
static get getAssetTypes => "$_baseUrl/Lookups/GetLookup?lookupEnum=500"; // get
static get getPartNumber => "$_baseUrl/PartCatalog/GetPartAutoComplete"; // get
static get getServiceReportPriority => "$_baseUrl/Lookups/GetLookup?lookupEnum=602"; // 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
@ -87,6 +97,8 @@ class URLs {
static get requestDeviceTransfer => "$_baseUrl/AssetTransfer/AddAssetTransfer"; // get
static get updateDeviceTransfer => "$_baseUrl/AssetTransfer/UpdateAssetTransfer"; // get
static get getDeviceTransfer => "$_baseUrl/AssetTransfer/GetAssetTransfers"; // get
static get getAssetTransferById => "$_baseUrl/AssetTransfer/GetAssetTransferById"; // get
static get getAssetTransferStatus => "$_baseUrl/Lookups/GetLookup?lookupEnum=406"; // get
// employee
static get getEmployees => "$_baseUrl/Lookups/GetLookup?lookupEnum=33"; // get

@ -1,4 +1,5 @@
import 'dart:convert';
import 'dart:developer';
import 'package:flutter/cupertino.dart';
import 'package:http/http.dart';
@ -6,6 +7,7 @@ import 'package:test_sa/controllers/api_routes/api_manager.dart';
import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/models/device/device_transfer.dart';
import 'package:test_sa/models/device/device_transfer_info.dart';
import 'package:test_sa/models/device/device_transfer_search.dart';
import 'package:test_sa/models/user.dart';
import '../../../models/hospital.dart';
@ -14,6 +16,8 @@ class DeviceTransferProvider extends ChangeNotifier {
// number of items call in each request
final pageItemNumber = 12;
DeviceTransferSearch deviceTransferSearch = DeviceTransferSearch();
//reset provider data
void reset() {
items = null;
@ -63,16 +67,15 @@ class DeviceTransferProvider extends ChangeNotifier {
}) async {
if (isLoading == true) return -2;
isLoading = true;
if (items?.isEmpty ?? true) notifyListeners();
Response response;
try {
Map<String, dynamic> body = {};
body["pageNumber"] = (items?.length ?? 0) ~/ pageItemNumber + 1;
body["pageSize"] = pageItemNumber;
body.addAll(deviceTransferSearch.toMap());
response = await ApiManager.instance.post(
URLs.getDeviceTransfer,
body: body,
);
response = await ApiManager.instance.post(URLs.getDeviceTransfer, body: body);
stateCode = response.statusCode;
if (stateCode >= 200 && stateCode < 300) {
@ -80,8 +83,8 @@ class DeviceTransferProvider extends ChangeNotifier {
List listJson = json.decode(response.body)["data"];
List<DeviceTransfer> itemsPage = listJson.map((request) => DeviceTransfer.fromJson(request)).toList();
items ??= [];
items.addAll(itemsPage);
print(listJson);
items.addAll(itemsPage.toSet().toList());
notifyListeners();
if (itemsPage.length == pageItemNumber) {
nextPage = true;
} else {
@ -99,6 +102,23 @@ class DeviceTransferProvider extends ChangeNotifier {
}
}
Future<DeviceTransfer> getRequestById({int assetTransferId}) async {
Response response;
try {
response = await ApiManager.instance.get(
URLs.getAssetTransferById + "?assetTransferId=$assetTransferId",
enableToastMessage: false,
);
if (response.statusCode >= 200 && response.statusCode < 300) {
return DeviceTransfer.fromJson(json.decode(response.body)["data"]);
}
return null;
} catch (error) {
print(error);
return null;
}
}
Future<int> createRequest({
@required String host,
@required User user,
@ -107,18 +127,22 @@ class DeviceTransferProvider extends ChangeNotifier {
Map<String, dynamic> body = {
"id": 0,
"assetId": model.device.id ?? "",
"destSiteId": model.receiver.client.id ?? "",
"destDepartmentId": model.receiver.department.id ?? "",
"senderSiteId": model.receiver.client.id ?? "",
"destSiteId": hospital.id ?? "",
"destDepartmentId": department.id ?? "",
"senderSiteId": model.sender.client.id ?? "",
// "transferNo": 0,
// "transferCode": "string",
"destBuildingId": building?.id,
"destFloorId": floor.id,
"destRoom": room,
// "senderBuildingId": 0,
// "senderFloorId": 0,
// "senderDepartmentId": 0,
// "senderRoom": "string",
/////
"senderBuildingId": model.device.destBuildingId,
"senderFloorId": model.device.destFloorId,
"senderDepartmentId": model.device.destDepartmentId,
"senderRoom": model.device.destRoom,
if (model?.sender?.attachments?.isNotEmpty ?? false)
"senderAttachments":
model?.sender?.attachments?.map((file) => {"attachmentName": _isLocalUrl(file.path) ? ("${file.path.split("/").last}|${base64Encode(file.readAsBytesSync())}") : file.path})?.toList(),
// "senderAssignedEmployeeId": "string",
// "senderMachineStatusId": 0,
// "senderComment": "string",
@ -181,17 +205,27 @@ class DeviceTransferProvider extends ChangeNotifier {
"senderStartDate": newModel.timer?.startAt?.toIso8601String(),
"senderEndDate": newModel.timer?.endAt?.toIso8601String(),
"senderTravelingHours": newModel.travelingHours,
"senderAttachmentName": newModel?.signature ?? "",
"destSiteId": oldModel.receiver.client.id,
"destDepartmentId": oldModel.receiver.department.id,
"senderEngSignature": newModel.engSignature,
if (newModel?.attachments?.isNotEmpty ?? false)
"senderAttachments":
newModel?.attachments?.map((file) => {"attachmentName": _isLocalUrl(file.path) ? ("${file.path.split("/").last}|${base64Encode(file.readAsBytesSync())}") : file.path})?.toList(),
"destSiteId": oldModel.receiver.client?.id,
"destDepartmentId": oldModel.receiver.department?.id,
"destBuildingId": oldModel.device?.destBuildingId,
"destFloorId": oldModel.device?.destFloorId,
"destRoom": oldModel.device?.destRoom,
"receiverAssignedEmployeeId": oldModel.receiver.userId,
"receiverMachineStatusId": oldModel.receiver.status.id ?? "",
"receiverComment": oldModel.receiver.comment,
"receiverWorkingHours": oldModel.receiver.workingHours,
"receiverStartDate": oldModel.receiver.timer?.startAt?.toIso8601String(),
"receiverEndDate": oldModel.receiver.timer?.endAt?.toIso8601String(),
"receiverTravelingHours": oldModel.receiver.travelingHours,
"receiverAttachmentName": oldModel.receiver?.signature ?? "",
"receiverTravelingHours": oldModel.receiver?.travelingHours,
"receiverEngSignature": oldModel.receiver?.engSignature,
if (oldModel.receiver?.attachments?.isNotEmpty ?? false)
"receiverAttachments": oldModel.receiver?.attachments
?.map((file) => {"attachmentName": _isLocalUrl(file.path) ? ("${file.path.split("/").last}|${base64Encode(file.readAsBytesSync())}") : file.path})
?.toList(),
});
} else {
body.addAll({
@ -203,10 +237,16 @@ class DeviceTransferProvider extends ChangeNotifier {
"senderWorkingHours": oldModel.sender.workingHours,
"senderStartDate": oldModel.sender.timer?.startAt?.toIso8601String(),
"senderEndDate": oldModel.sender.timer?.endAt?.toIso8601String(),
"senderTravelingHours": oldModel.sender.travelingHours,
"senderAttachmentName": oldModel.sender?.signature ?? "",
"destSiteId": newModel.client.id,
"destDepartmentId": newModel.department.id,
"senderTravelingHours": oldModel.sender?.travelingHours,
"senderEngSignature": oldModel.sender?.engSignature,
if (oldModel.sender?.attachments?.isNotEmpty ?? false)
"senderAttachments":
oldModel.sender?.attachments?.map((file) => {"attachmentName": _isLocalUrl(file.path) ? ("${file.path.split("/").last}|${base64Encode(file.readAsBytesSync())}") : file.path})?.toList(),
"destSiteId": newModel.client?.id,
"destDepartmentId": newModel.department?.id,
"destBuildingId": oldModel.device?.destBuildingId,
"destFloorId": oldModel.device?.destFloorId,
"destRoom": oldModel.device?.destRoom,
"receiverAssignedEmployeeId": newModel.userId,
"receiverMachineStatusId": newModel.status?.id ?? "",
"receiverComment": newModel.comment,
@ -214,18 +254,20 @@ class DeviceTransferProvider extends ChangeNotifier {
"receiverStartDate": newModel.timer?.startAt?.toIso8601String(),
"receiverEndDate": newModel.timer?.endAt?.toIso8601String(),
"receiverTravelingHours": newModel.travelingHours,
"receiverAttachmentName": newModel?.signature ?? "",
"receiverEngSignature": newModel.engSignature,
if (newModel?.attachments?.isNotEmpty ?? false)
"receiverAttachments":
newModel?.attachments?.map((file) => {"attachmentName": _isLocalUrl(file.path) ? ("${file.path.split("/").last}|${base64Encode(file.readAsBytesSync())}") : file.path})?.toList(),
});
}
//body.addAll(newModel.toJson(isSender));
print(body);
log(body?.toString());
Response response;
try {
response = await ApiManager.instance.put(URLs.updateDeviceTransfer, body: body);
print(response.body);
print("${newModel.signature}.png");
print("${newModel.engSignature}.png");
// response = await post(
// Uri.parse("$host${URLs.updateDeviceTransfer}/$requestId"),
// body: body,
@ -246,4 +288,9 @@ class DeviceTransferProvider extends ChangeNotifier {
return -1;
}
}
bool _isLocalUrl(String url) {
if (url?.isEmpty != false) return false;
return url.startsWith("/") || url.startsWith("file://") || url.substring(1).startsWith(':\\');
}
}

@ -17,20 +17,25 @@ class DevicesProvider extends ChangeNotifier {
final pageItemNumber = 10;
bool nextPage = true;
// state code of current request to defied error message
// like 400 customer request failed
// 500 service not available
int _stateCode;
int get stateCode => _stateCode;
List<Device> _devices = [];
List<Device> get devices => _devices;
// when categories in-process _loading = true
// done _loading = true
// failed _loading = false
bool _loading;
bool get isLoading => _loading;
set isLoading(bool isLoading) {
_loading = isLoading;
notifyListeners();
@ -47,6 +52,7 @@ class DevicesProvider extends ChangeNotifier {
@required int hospitalId,
String serialNumber,
String number,
bool isQr = false,
}) async {
if (_loading == true) return -2;
_loading = true;
@ -70,7 +76,15 @@ class DevicesProvider extends ChangeNotifier {
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
List equipmentListJson = json.decode(response.body)["data"];
_devices.addAll(equipmentListJson.map<Device>((device) => Device.fromJson(device)).toList());
var dList = equipmentListJson.map<Device>((device) => Device.fromJson(device, startKeyWithDest: false)).toList();
try {
if (isQr) {
dList = dList.where((element) => number?.toLowerCase() == element?.number?.toLowerCase())?.toList() ?? [];
}
} catch (e) {
print(e);
}
_devices.addAll(dList);
nextPage = true;
} else {
nextPage = false;
@ -111,8 +125,8 @@ class DevicesProvider extends ChangeNotifier {
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
List equipmentListJson = json.decode(response.body)["data"];
page = equipmentListJson.map((device) => Device.fromJson(device)).toList();
_devices.addAll(equipmentListJson.map<Device>((device) => Device.fromJson(device)).toList());
page = equipmentListJson.map((device) => Device.fromJson(device, startKeyWithDest: false)).toList();
_devices.addAll(equipmentListJson.map<Device>((device) => Device.fromJson(device, startKeyWithDest: false)).toList());
notifyListeners();
}
return page;
@ -147,31 +161,31 @@ class DevicesProvider 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
// /// for more details check http state manager
// /// lib\controllers\http_status_manger\http_status_manger.dart
// Future<List<Device>> getDevicesListBySN({@required String host, @required User user, @required int hospitalId, @required String sn}) async {
// Response response;
// try {
// response = await get(
// Uri.parse(URLs.getEquipment + "?client=$hospitalId" + (sn == null || sn.isEmpty ? "" : "&serial_qr=$sn")),
// );
//
// _stateCode = response.statusCode;
// List<Device> _page = [];
// if (response.statusCode >= 200 && response.statusCode < 300) {
// // client's request was successfully received
// List categoriesListJson = json.decode(utf8.decode(response.bodyBytes));
// _page = categoriesListJson.map((device) => Device.fromJson(device)).toList();
// }
// return _page;
// } catch (error) {
// _loading = false;
// _stateCode = -1;
// notifyListeners();
// return [];
// }
// }
// /// 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
// /// for more details check http state manager
// /// lib\controllers\http_status_manger\http_status_manger.dart
// Future<List<Device>> getDevicesListBySN({@required String host, @required User user, @required int hospitalId, @required String sn}) async {
// Response response;
// try {
// response = await get(
// Uri.parse(URLs.getEquipment + "?client=$hospitalId" + (sn == null || sn.isEmpty ? "" : "&serial_qr=$sn")),
// );
//
// _stateCode = response.statusCode;
// List<Device> _page = [];
// if (response.statusCode >= 200 && response.statusCode < 300) {
// // client's request was successfully received
// List categoriesListJson = json.decode(utf8.decode(response.bodyBytes));
// _page = categoriesListJson.map((device) => Device.fromJson(device)).toList();
// }
// return _page;
// } catch (error) {
// _loading = false;
// _stateCode = -1;
// notifyListeners();
// return [];
// }
// }
}

@ -1,4 +1,5 @@
import 'dart:convert';
import 'dart:developer';
import 'package:flutter/cupertino.dart';
import 'package:http/http.dart';
@ -6,6 +7,7 @@ import 'package:test_sa/controllers/api_routes/api_manager.dart';
import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/models/gas_refill/gas_refill_model.dart';
import 'package:test_sa/models/hospital.dart';
import 'package:test_sa/models/timer_model.dart';
import 'package:test_sa/models/user.dart';
class GasRefillProvider extends ChangeNotifier {
@ -47,20 +49,19 @@ class GasRefillProvider extends ChangeNotifier {
Future<int> getRequests({
@required String host,
@required User user,
@required bool mostRecent,
}) async {
if (isLoading == true) return -2;
isLoading = true;
if (items?.isEmpty ?? true) notifyListeners();
Response response;
Map<String, dynamic> body = {};
body["pageNumber"] = (items?.length ?? 0) ~/ pageItemNumber + 1;
body["pageSize"] = pageItemNumber;
print("url:${URLs.getGasRefill}:body:$body");
body["mostRecent"] = mostRecent;
response = await ApiManager.instance.post(
URLs.getGasRefill,
body: body,
);
response = await ApiManager.instance.post(URLs.getGasRefill, body: body);
stateCode = response.statusCode;
if (stateCode >= 200 && stateCode < 300) {
// client's request was successfully received
@ -68,6 +69,7 @@ class GasRefillProvider extends ChangeNotifier {
List<GasRefillModel> itemsPage = requestsListJson.map((request) => GasRefillModel.fromJson(request)).toList();
items ??= [];
items.addAll(itemsPage);
notifyListeners();
if (itemsPage.length == pageItemNumber) {
nextPage = true;
} else {
@ -91,24 +93,22 @@ class GasRefillProvider extends ChangeNotifier {
@required User user,
@required GasRefillModel model,
}) async {
print("ss");
Map<String, dynamic> body = {
"uid": user.id.toString(),
"token": user.token ?? "",
"site": hospital?.toMap(),
"building": {"id": building?.id, "name": building?.name, "value": building?.value},
"floor": {"id": floor?.id, "name": floor?.name, "value": floor?.value},
if (expectedDateTime != null) "expectedDate": expectedDateTime?.toIso8601String(),
//if (expectedDateTime != null) "expectedDate": expectedDateTime?.toIso8601String(),
if (expectedDateTime != null) "expectedTime": expectedDateTime?.toIso8601String(),
if (startDate != null) "startDate": startDate?.toIso8601String(),
if (startDate != null) "startTime": startDate?.toIso8601String(),
if (endDate != null) "endDate": endDate?.toIso8601String(),
if (endDate != null) "endTime": endDate?.toIso8601String(),
if (timer?.startAt != null) "startDate": timer.startAt.toIso8601String(),
if (timer?.startAt != null) "startTime": timer.startAt.toIso8601String(),
if (timer?.endAt != null) "endDate": timer.endAt.toIso8601String(),
if (timer?.endAt != null) "endTime": timer.endAt.toIso8601String(),
"department": {"id": department?.id, "departmentName": department?.name, "departmentCode": "", "ntCode": ""},
"GazRefillNo": "GR-${DateTime.now().toString().split(" ").first}",
"status": model.status.toMap(),
};
print("ss1");
body["gazRefillDetails"] = model.details
.map((model) => {
"gasType": model.type.toMap(),
@ -121,7 +121,6 @@ class GasRefillProvider extends ChangeNotifier {
Response response;
try {
response = await ApiManager.instance.post(URLs.requestGasRefill, body: body);
print("ss2");
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
if (items != null) {
@ -146,13 +145,14 @@ class GasRefillProvider extends ChangeNotifier {
"id": newModel.id,
"gazRefillNo": newModel.title ?? "",
"status": newModel.status.toMap(),
"expectedDate": oldModel.expectedDate?.toIso8601String(),
"expectedTime": oldModel.expectedDate?.toIso8601String(),
"startDate": startDate?.toIso8601String(),
"startTime": startDate?.toIso8601String(),
"endDate": endDate?.toIso8601String(),
"endTime": endDate?.toIso8601String(),
"workingHours": ((endDate?.difference(startDate)?.inMinutes ?? 0) / 60),
//"expectedDate": newModel.expectedDate?.toIso8601String(),
"expectedTime": newModel.expectedDate?.toIso8601String(),
if (timer?.startAt != null) "startDate": timer.startAt.toIso8601String(),
if (timer?.startAt != null) "startTime": timer.startAt.toIso8601String(),
if (timer?.endAt != null) "endDate": timer.endAt.toIso8601String(),
if (timer?.endAt != null) "endTime": timer.endAt.toIso8601String(),
// "workingHours": ((endDate?.difference(startDate)?.inMinutes ?? 0) / 60),
'workingHours': timer.durationInSecond != null ? timer.durationInSecond / 60 / 60 : newModel.workingHours,
"assignedEmployee": oldModel?.assignedEmployee?.id == null ? null : oldModel?.assignedEmployee?.toJson(),
"site": hospital?.toMap(),
"building": building?.toJson(includeFloors: false),
@ -171,7 +171,7 @@ class GasRefillProvider extends ChangeNotifier {
"deliverdQty": model.deliveredQuantity,
})
.toList();
log(body.toString());
Response response;
try {
response = await ApiManager.instance.put(URLs.updateGasRefill, body: body);
@ -196,6 +196,5 @@ class GasRefillProvider extends ChangeNotifier {
Floors floor;
Departments department;
DateTime expectedDateTime;
DateTime startDate;
DateTime endDate;
TimerModel timer;
}

@ -22,22 +22,27 @@ class HospitalsProvider extends ChangeNotifier {
// like 400 customer request failed
// 500 service not available
int _stateCode;
int get stateCode => _stateCode;
// true if there is next page in product list and false if not
bool _nextPage = true;
bool get nextPage => _nextPage;
// contain user data
// when user not login or register _user = null
List<Hospital> _hospitals;
List<Hospital> get hospitals => _hospitals;
// when categories in-process _loading = true
// done _loading = true
// failed _loading = false
bool _loading;
bool get isLoading => _loading;
set isLoading(bool isLoading) {
_loading = isLoading;
notifyListeners();

@ -22,22 +22,27 @@ class PartsProvider extends ChangeNotifier {
// like 400 customer request failed
// 500 service not available
int _stateCode;
int get stateCode => _stateCode;
// true if there is next page in product list and false if not
bool _nextPage = true;
bool get nextPage => _nextPage;
// contain user data
// when user not login or register _user = null
List<Part> _parts;
List<Part> get parts => _parts;
// when categories in-process _loading = true
// done _loading = true
// failed _loading = false
bool _loading;
bool get isLoading => _loading;
set isLoading(bool isLoading) {
_loading = isLoading;
notifyListeners();
@ -85,17 +90,21 @@ class PartsProvider extends ChangeNotifier {
/// return state code if request complete may be 200, 404 or 403
/// for more details check http state manager
/// lib\controllers\http_status_manger\http_status_manger.dart
Future<List<Part>> getPartsList({String host, User user, String title}) async {
Future<List<Part>> getPartsList({String host, User user, num assetId, String title}) async {
Response response;
try {
response = await ApiManager.instance.post(URLs.getPartNumber, body: {if (title != null && title.isNotEmpty) "partName": title});
List<Part> _page = [];
if (int.tryParse(title) != null) {
response = await ApiManager.instance.post(URLs.getPartNumber, body: {if (title != null && title.isNotEmpty) "partNo": title, "assetId": assetId});
} else {
response = await ApiManager.instance.post(URLs.getPartNumber, body: {if (title != null && title.isNotEmpty) "partName": title, "assetId": assetId});
}
List<Part> 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) => Part.fromJson(part)).toList();
page = categoriesListJson.map((part) => Part.fromJson(part)).toList();
}
return _page;
return page;
} catch (error) {
return [];
}

@ -69,7 +69,7 @@ class PreventiveMaintenanceVisitsProvider extends ChangeNotifier {
// client's request was successfully received
List requestsListJson = json.decode(utf8.decode(response.bodyBytes));
List<Visit> _visits = requestsListJson.map((request) => Visit.fromJson(request)).toList();
if (visits == null) visits = [];
visits ??= [];
visits.addAll(_visits);
if (_visits.length == pageItemNumber) {
nextPage = true;

@ -13,7 +13,7 @@ import 'package:test_sa/models/visits/visits_search.dart';
class RegularVisitsProvider extends ChangeNotifier {
// number of items call in each request
final pageItemNumber = 20;
final pageItemNumber = 12;
//reset provider data
void reset() {
@ -52,7 +52,7 @@ class RegularVisitsProvider extends ChangeNotifier {
}) async {
if (isLoading == true) return -2;
isLoading = true;
if (visits == null) notifyListeners();
if (visits?.isEmpty ?? true) notifyListeners();
Response response;
//userId = 397.toString(); // testing id to view data
@ -77,10 +77,11 @@ class RegularVisitsProvider extends ChangeNotifier {
// client's request was successfully received
try {
List requestsListJson = json.decode(response.body)["data"];
List<Visit> _visits = requestsListJson.map((request) => Visit.fromJson(request)).toList();
visits ??= [];
visits.addAll(_visits);
if (_visits.length == pageItemNumber) {
List<Visit> visits = requestsListJson.map((request) => Visit.fromJson(request)).toList();
this.visits ??= [];
this.visits.addAll(visits);
notifyListeners();
if (visits.length == pageItemNumber) {
nextPage = true;
} else {
nextPage = false;

@ -16,6 +16,7 @@ import 'package:test_sa/models/subtitle.dart';
import 'package:test_sa/models/timer_model.dart';
import '../../../models/service_request/search_work_order.dart';
import '../../../models/service_request/sub_work_order_details.dart';
import '../../../models/user.dart';
class ServiceRequestsProvider extends ChangeNotifier {
@ -57,7 +58,7 @@ class ServiceRequestsProvider extends ChangeNotifier {
Future<int> getRequests({@required int hospitalId}) async {
if (isLoading == true) return -2;
isLoading = true;
if (serviceRequests == null) notifyListeners();
if (serviceRequests?.isEmpty ?? false) notifyListeners();
Response response;
try {
Map<String, dynamic> body = {};
@ -77,6 +78,7 @@ class ServiceRequestsProvider extends ChangeNotifier {
List<ServiceRequest> serviceRequestsPage = requestsListJson.map((request) => ServiceRequest.fromJson(request)).toList();
serviceRequests ??= [];
serviceRequests.addAll(serviceRequestsPage);
notifyListeners();
if (serviceRequestsPage.length == pageItemNumber) {
nextPage = true;
} else {
@ -144,10 +146,10 @@ class ServiceRequestsProvider extends ChangeNotifier {
"client": user.clientId,
"callComments": serviceRequest.callComments,
if (serviceRequest.devicePhotos.isNotEmpty) "attachmentsCallRequest": serviceRequest.devicePhotos.map((e) => {"name": e}).toList(),
"priority": serviceRequest.priority.toMap(),
"defectType": serviceRequest.defectType.toMap(),
"typeofRequest": serviceRequest.type.toMap(),
"requestedThrough": serviceRequest.requestedThrough.toMap(),
"priority": serviceRequest.priority?.toMap(),
"defectType": serviceRequest.defectType?.toMap(),
"typeofRequest": serviceRequest.type?.toMap(),
"requestedThrough": serviceRequest.requestedThrough?.toMap(),
"reviewComment": null,
if (serviceRequest.audio != null) "voiceNote": serviceRequest.audio,
"callSiteContactPerson": [
@ -176,17 +178,26 @@ class ServiceRequestsProvider extends ChangeNotifier {
body["voiceNote"] = serviceRequest.audio;
}
Response response;
try {
response = await ApiManager.instance.post(URLs.createRequest, body: body);
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
if (serviceRequests != null) serviceRequests.insert(0, ServiceRequest.fromJson(json.decode(utf8.decode(response.bodyBytes))[0]));
notifyListeners();
//try {
response = await ApiManager.instance.post(URLs.createRequest, body: body);
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
if (serviceRequests != null) {
var data = json.decode(utf8.decode(response.bodyBytes));
if (data is List) {
serviceRequests.insert(0, ServiceRequest.fromJson(data[0]));
} else {
if (data["data"] != null && data["data"] == true) {
// serviceRequests.insert(0, ServiceRequest.fromJson(data[0]));
}
}
}
return response.statusCode;
} catch (error) {
return -1;
notifyListeners();
}
return response.statusCode;
// } catch (error) {
// return -1;
// }
}
Future<int> createIssueReport({
@ -221,7 +232,6 @@ class ServiceRequestsProvider extends ChangeNotifier {
Map<String, dynamic> serviceRequest = await getServiceRequestById(requestId: request.id) ?? "";
final List callSiteContacts = (serviceRequest['callSiteContactPerson'] as List);
final Map<String, dynamic> callSiteContactPerson = callSiteContacts.isEmpty ? {} : callSiteContacts[0];
print(callSiteContactPerson);
Response response;
var body = {
"id": request.id,
@ -305,7 +315,7 @@ class ServiceRequestsProvider extends ChangeNotifier {
},
"assetType": report.assetType?.toMap(),
"assignedEmployee": {"id": report.engineer?.id, "name": report.engineer?.name ?? ""},
"visitDate": report.visitDate?.toIso8601String() ?? "",
"visitDate": report.returnToService?.toIso8601String() ?? "",
// "assistantEmployees": [
// {"id": report.engineer.id, "name": report.engineer.name},
// ],
@ -337,7 +347,7 @@ class ServiceRequestsProvider extends ChangeNotifier {
?.map(
(p) => {
"id": p.reportPartID ?? 0,
"sparePart": {"id": p.id, "partNo": p.code, "partName": p.name},
"sparePart": {"id": p.id, "partNo": p.partNo, "partName": p.partName},
"qty": p.quantity
},
)
@ -354,7 +364,6 @@ class ServiceRequestsProvider extends ChangeNotifier {
// body["uid"] = user.id;
// body["token"] = user.token;
response = await ApiManager.instance.post(URLs.createServiceReport, body: body);
print(response.body);
// response = await post(
// Uri.parse(
// host+URLs.createServiceReport),
@ -380,8 +389,6 @@ class ServiceRequestsProvider extends ChangeNotifier {
try {
Map<String, dynamic> body = workOrder.toJson();
response = await ApiManager.instance.post(URLs.createServiceReport, body: body);
print(response.body);
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
reset();
@ -432,7 +439,6 @@ class ServiceRequestsProvider extends ChangeNotifier {
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
List workOrdersJson = json.decode(response.body)["data"];
print(workOrdersJson);
workOrders = workOrdersJson.map<SearchWorkOrder>((request) => SearchWorkOrder.fromJson(request)).toList();
if (workOrders.length == pageItemNumber) {
nextPage = true;
@ -446,6 +452,23 @@ class ServiceRequestsProvider extends ChangeNotifier {
}
}
Future<SubWorkOrderDetails> getSubWorkOrderDetails({@required String parentId}) async {
Response response;
try {
response = await ApiManager.instance.get(URLs.getSubWorkerInfoAccordingToPreviousStep + "?parentId=$parentId");
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
final workOrderJson = json.decode(response.body)["data"];
return SubWorkOrderDetails.fromJson(workOrderJson);
}
return null;
} catch (e) {
print("getSubWorkOrderDetails [error] : $e");
return null;
}
}
Future<int> createDuplicatedReport({
@required String host,
@required User user,
@ -595,6 +618,19 @@ class ServiceRequestsProvider extends ChangeNotifier {
}
}
Future<ServiceRequest> getServiceRequestObjectById({@required String requestId}) async {
try {
Response response = await ApiManager.instance.get(URLs.getServiceRequestById + "?callRequestId=$requestId");
if (response.statusCode >= 200 && response.statusCode < 300) {
return ServiceRequest.fromJson(json.decode(response.body)["data"]);
} else {
return null;
}
} catch (error) {
return null;
}
}
Future<Map<String, dynamic>> getServiceRequestById({@required String requestId}) async {
Response response;
try {
@ -651,7 +687,6 @@ class ServiceRequestsProvider extends ChangeNotifier {
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
List workOrdersJson = json.decode(response.body)["data"];
print(workOrdersJson);
workOrders ??= [];
workOrders.addAll(workOrdersJson.map<SearchWorkOrder>((request) => SearchWorkOrder.fromJson(request)).toList());
if (workOrders.length == pageItemNumber) {

@ -0,0 +1,75 @@
import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.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/models/lookup.dart';
import 'package:test_sa/models/user.dart';
class AssetTransferStatusProvider extends ChangeNotifier {
//reset provider data
void reset() {
_items = null;
_loading = null;
_stateCode = null;
}
// state code of current request to defied error message
// like 400 customer request failed
// 500 service not available
int _stateCode;
int get stateCode => _stateCode;
// contain user data
// when user not login or register _user = null
List<Lookup> _items;
List<Lookup> get items => _items;
// when categories in-process _loading = true
// done _loading = true
// failed _loading = false
bool _loading;
bool get isLoading => _loading;
set isLoading(bool isLoading) {
_loading = isLoading;
notifyListeners();
}
/// 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
/// for more details check http state manager
/// lib\controllers\http_status_manger\http_status_manger.dart
Future<int> getData({
String host,
User user,
}) async {
if (_loading == true) return -2;
_loading = true;
notifyListeners();
Response response;
try {
response = await ApiManager.instance.get(URLs.getAssetTransferStatus);
_stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
List categoriesListJson = json.decode(response.body)["data"];
_items = categoriesListJson.map((item) => Lookup.fromJson(item)).toList();
}
_loading = false;
notifyListeners();
return response.statusCode;
} catch (error) {
_loading = false;
_stateCode = -1;
notifyListeners();
return -1;
}
}
}

@ -1,13 +1,12 @@
import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.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/models/engineer.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/models/user.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart';
class EngineersProvider extends ChangeNotifier {
//reset provider data

@ -1,8 +1,5 @@
import 'dart:convert';
import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/models/user.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart';

@ -1,8 +1,5 @@
import 'dart:convert';
import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/models/user.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart';

@ -1,12 +1,9 @@
import 'dart:convert';
import 'package:test_sa/controllers/api_routes/api_manager.dart';
import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/models/user.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.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/models/lookup.dart';
import 'package:test_sa/models/user.dart';

@ -1,12 +1,9 @@
import 'dart:convert';
import 'package:test_sa/controllers/api_routes/api_manager.dart';
import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/models/user.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.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/models/lookup.dart';
import 'package:test_sa/models/user.dart';

@ -0,0 +1,53 @@
import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.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/models/service_request/search_work_order.dart';
class VendorProvider extends ChangeNotifier {
void reset() {
_vendors = null;
_loading = null;
_stateCode = null;
}
int _stateCode;
int get stateCode => _stateCode;
List<Supplier> _vendors;
List<Supplier> get vendors => _vendors;
bool _loading;
bool get isLoading => _loading;
set isLoading(bool isLoading) {
_loading = isLoading;
notifyListeners();
}
Future<int> getVendors(String text) async {
if (_loading == true) return -2;
_loading = true;
notifyListeners();
Response response;
try {
response = await ApiManager.instance.get("${URLs.getSuppliersAutoComplete}?searchText=$text");
_stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
List suppliersJson = json.decode(response.body)["data"];
_vendors = suppliersJson.map((type) => Supplier.fromJson(type)).toList();
}
_loading = false;
notifyListeners();
return response.statusCode;
} catch (error) {
_loading = false;
_stateCode = -1;
notifyListeners();
return -1;
}
}
}

@ -66,4 +66,8 @@ class ServiceRequestedThroughProvider extends ChangeNotifier {
return -1;
}
}
Lookup getDefaultItem() {
return items?.firstWhere((element) => element.name.toLowerCase().contains("app"));
}
}

@ -66,4 +66,8 @@ class ServiceRequestTypeProvider extends ChangeNotifier {
return -1;
}
}
Lookup getDefaultItem() {
return items?.firstWhere((element) => element.name.toLowerCase().contains("maintenance"));
}
}

@ -63,6 +63,7 @@ class UserProvider extends ChangeNotifier {
notifyListeners();
return response.statusCode;
} catch (error) {
print(error);
_loading = false;
notifyListeners();
return -1;
@ -112,45 +113,45 @@ class UserProvider extends ChangeNotifier {
/// return state code if request complete may be 200, 404 or 403
/// for more details about state codes check http state manager
/// lib\controllers\http_status_manger\http_status_manger.dart
Future<int> updateProfile({
@required String host,
@required User user,
}) async {
if (_loading == true) return -2;
_loading = true;
notifyListeners();
Response response;
Map<String, dynamic> jsonObject = {};
jsonObject["uid"] = user.id;
jsonObject["token"] = user.token;
if (user.departmentId != _user.departmentId) jsonObject["department"] = user.departmentId;
// if (user.whatsApp != _user.whatsApp) jsonObject["whatsapp"] = user.whatsApp;
if (user.phoneNumber != _user.phoneNumber) jsonObject["phone"] = user.phoneNumber;
try {
response = response = await ApiManager.instance.post(
URLs.login,
body: jsonObject,
);
} catch (error) {
_loading = false;
notifyListeners();
return -1;
}
_loading = false;
notifyListeners();
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
_user = User.fromJson(jsonDecode(utf8.decode(response.bodyBytes))[0]);
_user.clientId = user.clientId;
_user.clientName = user.clientName;
_user.departmentName = user.departmentName;
_user.departmentId = user.departmentId;
notifyListeners();
return response.statusCode;
}
return response.statusCode;
}
// Future<int> updateProfile({
// @required String host,
// @required User user,
// }) async {
// if (_loading == true) return -2;
// _loading = true;
// notifyListeners();
// Response response;
//
// Map<String, dynamic> jsonObject = {};
// jsonObject["uid"] = user.id;
// jsonObject["token"] = user.token;
// if (user.departmentId != _user.departmentId) jsonObject["department"] = user.departmentId;
// // if (user.whatsApp != _user.whatsApp) jsonObject["whatsapp"] = user.whatsApp;
// if (user.phoneNumber != _user.phoneNumber) jsonObject["phone"] = user.phoneNumber;
// try {
// response = response = await ApiManager.instance.post(
// URLs.login,
// body: jsonObject,
// );
// } catch (error) {
// _loading = false;
// notifyListeners();
// return -1;
// }
//
// _loading = false;
// notifyListeners();
//
// if (response.statusCode >= 200 && response.statusCode < 300) {
// // client's request was successfully received
// _user = User.fromJson(jsonDecode(utf8.decode(response.bodyBytes))[0]);
// _user.clientId = user.clientId;
// _user.clientName = user.clientName;
// _user.departmentName = user.departmentName;
// _user.departmentId = user.departmentId;
// notifyListeners();
// return response.statusCode;
// }
// return response.statusCode;
// }
}

@ -1,10 +1,11 @@
import 'dart:async';
import 'dart:convert';
import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/models/user.dart';
import 'package:flutter/foundation.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/models/user.dart';
import '../settings/app_settings.dart';
class SettingProvider extends ChangeNotifier {

@ -1,4 +1,3 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:test_sa/views/app_style/colors.dart';

@ -1,5 +1,4 @@
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
extension WidgetExtensions on Widget {
Widget onPress(VoidCallback onTap) => InkWell(onTap: onTap, child: this);

@ -13,6 +13,7 @@ import 'package:test_sa/controllers/providers/api/hospitals_provider.dart';
import 'package:test_sa/controllers/providers/api/notifications_provider.dart';
import 'package:test_sa/controllers/providers/api/regular_visits_provider.dart';
import 'package:test_sa/controllers/providers/api/service_requests_provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/asset_transfer_status_provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/employee/assigned_to_provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/employee/engineers_provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/gas_refill/gas_cylinder_size_provider.dart';
@ -63,6 +64,7 @@ import 'controllers/providers/api/status_drop_down/report/service_report_repair_
import 'controllers/providers/api/status_drop_down/report/service_report_status_provider.dart';
import 'controllers/providers/api/status_drop_down/report/service_report_types_provider.dart';
import 'controllers/providers/api/status_drop_down/report/service_types_provider.dart';
import 'controllers/providers/api/status_drop_down/report/vendor_provider.dart';
import 'controllers/providers/api/user_provider.dart';
import 'controllers/providers/settings/setting_provider.dart';
import 'views/pages/device_transfer/request_device_transfer.dart';
@ -81,20 +83,23 @@ void main() async {
}
runApp(ChangeNotifierProvider(
create: (_) => SettingProvider(),
child: MyApp(),
child: const MyApp(),
));
}
class MyApp extends StatelessWidget {
const MyApp({Key key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
final _settingProvider = Provider.of<SettingProvider>(context);
final settingProvider = Provider.of<SettingProvider>(context);
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => UserProvider()),
ChangeNotifierProvider(create: (_) => HospitalsProvider()),
ChangeNotifierProvider(create: (_) => DevicesProvider()),
ChangeNotifierProvider(create: (_) => AssetTransferStatusProvider()),
ChangeNotifierProvider(create: (_) => ServiceRequestsProvider()),
ChangeNotifierProvider(create: (_) => DepartmentsProvider()),
ChangeNotifierProvider(create: (_) => NotificationsProvider()),
@ -131,6 +136,7 @@ class MyApp extends StatelessWidget {
ChangeNotifierProvider(create: (_) => ServiceReportMaintenanceSituationProvider()),
ChangeNotifierProvider(create: (_) => ServiceReportUsersProvider()),
ChangeNotifierProvider(create: (_) => ServiceReportAssistantsEmployeeProvider()),
ChangeNotifierProvider(create: (_) => VendorProvider()),
],
child: GestureDetector(
onTap: () {
@ -160,7 +166,7 @@ class MyApp extends StatelessWidget {
Locale('en'),
Locale('ar'),
],
locale: Locale(_settingProvider.language ?? 'en'),
locale: Locale(settingProvider.language ?? 'en'),
initialRoute: SplashScreen.id,
routes: {
SplashScreen.id: (_) => const SplashScreen(),

@ -1,3 +1,5 @@
import 'package:test_sa/models/lookup.dart';
class CallRequestForWorkOrder {
int id;
String callNo;
@ -71,11 +73,11 @@ class Asset {
String ipAddress;
String macAddress;
String portNumber;
String assetReplace;
Lookup assetReplace;
String oldAsset;
bool isParent;
Lookup isParent;
String parentAsset;
int assetType;
Lookup assetType;
Site site;
Building building;
String floor;
@ -171,11 +173,11 @@ class Asset {
ipAddress = json['ipAddress'];
macAddress = json['macAddress'];
portNumber = json['portNumber'];
assetReplace = json['assetReplace'];
assetReplace = json['assetReplace'] != null ? Lookup.fromJson(json['assetReplace']) : null;
oldAsset = json['oldAsset'];
isParent = json['isParent'];
isParent = json['isParent'] != null ? Lookup.fromJson(json['isParent']) : null;
parentAsset = json['parentAsset'];
assetType = json['assetType'];
assetType = json['assetType'] != null ? Lookup.fromJson(json['assetType']) : null;
site = json['site'] != null ? new Site.fromJson(json['site']) : null;
building = json['building'];
floor = json['floor'];
@ -457,12 +459,12 @@ class AssignedEmployee {
class CallSiteContactPerson {
int id;
Null employeeCode;
String employeeCode;
String name;
String telephone;
String job;
String email;
Null land;
String land;
String contactUserId;
CallSiteContactPerson({this.id, this.employeeCode, this.name, this.telephone, this.job, this.email, this.land, this.contactUserId});

@ -9,10 +9,14 @@ class Device {
String number;
String assetName;
String destBuildingName;
int destBuildingId;
String destDepartmentName;
int destDepartmentId;
String destRoom;
String destFloor;
int destFloorId;
String destSiteName;
// String brand;
// String model;
ModelDefinition modelDefinition;
@ -32,10 +36,12 @@ class Device {
// this.brand,
// this.model,
this.modelDefinition,
this.destFloorId,
this.destDepartmentId,
this.destBuildingId,
});
factory Device.fromJson(Map<String, dynamic> parsedJson) {
print("parsedJson:$parsedJson");
factory Device.fromJson(Map<String, dynamic> parsedJson, {bool startKeyWithDest = true}) {
return Device(
id: parsedJson["id"],
serialNumber: parsedJson["assetSerialNo"],
@ -43,10 +49,13 @@ class Device {
assetName: parsedJson["assetName"],
modelDefinition: ModelDefinition.fromJson(parsedJson["modelDefinition"]),
hospital: Hospital.fromJson(parsedJson["site"]),
destBuildingName: parsedJson["destBuildingName"],
destDepartmentName: parsedJson["destDepartmentName"],
destRoom: parsedJson["destRoom"],
destFloor: parsedJson["destFloor"],
destBuildingName: startKeyWithDest ? parsedJson["destBuildingName"] : parsedJson['building']['name'],
destBuildingId: startKeyWithDest ? parsedJson["destBuildingName"] : parsedJson['building']['id'],
destDepartmentName: startKeyWithDest ? parsedJson["destDepartmentName"] : parsedJson['department']['departmentName'],
destDepartmentId: startKeyWithDest ? parsedJson["destDepartmentName"] : parsedJson['department']['id'],
destRoom: startKeyWithDest ? parsedJson["destRoom"] : parsedJson['room'],
destFloor: startKeyWithDest ? parsedJson["destFloor"] : parsedJson['floor']['name'],
destFloorId: startKeyWithDest ? null : parsedJson['floor']['id'],
destSiteName: parsedJson['destSiteName']
// parsedJson["modelDefinition"] == null ? "" :
// parsedJson["modelDefinition"]["manufacturerName"],

@ -1,3 +1,5 @@
import 'dart:io';
import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/models/department.dart';
import 'package:test_sa/models/device/device.dart';
@ -14,6 +16,7 @@ class DeviceTransfer {
Device device;
DeviceTransferInfo sender;
DeviceTransferInfo receiver;
String createdOn;
DeviceTransfer({
this.id,
@ -22,6 +25,7 @@ class DeviceTransfer {
this.userId,
this.sender,
this.receiver,
this.createdOn,
});
bool validate() {
@ -40,20 +44,35 @@ class DeviceTransfer {
final receiver = DeviceTransferInfo();
receiver.fromDetails(old.receiver);
this.receiver = receiver;
createdOn = old.createdOn;
}
factory DeviceTransfer.fromJson(Map<String, dynamic> parsedJson) {
List<String> senderFiles = [];
if (parsedJson["senderAttachments"] != null && parsedJson["senderAttachments"] is List) {
List list = parsedJson["senderAttachments"];
senderFiles = list.map((e) => (URLs.getFileUrl(e["attachmentName"]))).toList();
}
List<String> receiverFiles = [];
if (parsedJson["receiverAttachments"] != null && parsedJson["receiverAttachments"] is List) {
List list = parsedJson["receiverAttachments"];
receiverFiles = list.map((e) => (URLs.getFileUrl(e["attachmentName"]))).toList();
}
return DeviceTransfer(
id: parsedJson["id"],
title: parsedJson["transferCode"],
userId: parsedJson["uid"],
createdOn: parsedJson['createdOn'],
device: Device(
id: parsedJson["assetId"],
number: parsedJson["assetNumber"],
assetName: parsedJson["assetName"],
serialNumber: parsedJson["assetSerialNo"],
destBuildingId: parsedJson["destBuildingId"],
destBuildingName: parsedJson["destBuildingName"],
destDepartmentId: parsedJson["destDepartmentId"],
destDepartmentName: parsedJson["destDepartmentName"],
destFloorId: parsedJson["destFloorId"],
destFloor: parsedJson["destFloorName"],
destRoom: parsedJson["destRoom"],
destSiteName: parsedJson["destSiteName"],
@ -62,6 +81,7 @@ class DeviceTransfer {
travelingHours: parsedJson["senderTravelingHours"],
comment: parsedJson["senderComment"],
workingHours: parsedJson["senderWorkingHours"],
attachments: senderFiles?.map((e) => File(e))?.toList(),
timer: TimerModel(
startAt: DateTime.tryParse(parsedJson["senderStartDate"] ?? ""),
endAt: DateTime.tryParse(parsedJson["senderEndDate"] ?? ""),
@ -77,8 +97,7 @@ class DeviceTransfer {
id: parsedJson["senderDepartmentId"],
name: parsedJson["senderDepartmentName"],
),
// todo add segnature
signature: URLs.getFileUrl(parsedJson["senderAttachmentName"]),
engSignature: URLs.getFileUrl(parsedJson["senderEngSignature"]),
status: Lookup(
id: parsedJson["senderMachineStatusId"],
name: parsedJson["senderMachineStatusName"],
@ -88,6 +107,7 @@ class DeviceTransfer {
travelingHours: parsedJson["receiverTravelingHours"],
comment: parsedJson["receiverComment"],
workingHours: parsedJson["receiverWorkingHours"],
attachments: receiverFiles?.map((e) => File(e))?.toList(),
timer: parsedJson["receiverStartDate"] != null || parsedJson["receiverEndDate"] != null
? TimerModel(startAt: DateTime.tryParse(parsedJson["receiverStartDate"] ?? ""), endAt: DateTime.tryParse(parsedJson["receiverEndDate"] ?? ""))
: null,
@ -101,8 +121,7 @@ class DeviceTransfer {
id: parsedJson["destDepartmentId"],
name: parsedJson["destDepartmentName"],
),
// todo add segnature
signature: URLs.getFileUrl(parsedJson["receiverAttachmentName"]),
engSignature: URLs.getFileUrl(parsedJson["receiverEngSignature"]),
status: Lookup(
id: parsedJson["receiverMachineStatusId"],
name: parsedJson["receiverMachineStatusName"],

@ -1,3 +1,5 @@
import 'dart:io';
import 'package:test_sa/models/department.dart';
import 'package:test_sa/models/hospital.dart';
import 'package:test_sa/models/lookup.dart';
@ -10,11 +12,13 @@ class DeviceTransferInfo {
Hospital client;
Department department;
String workingHours;
// DateTime startDate;
// DateTime endDate;
String travelingHours;
String userName;
String signature;
String engSignature;
List<File> attachments;
String assignedEmployeeName;
Lookup status;
TimerModel timer;
@ -29,10 +33,11 @@ class DeviceTransferInfo {
// this.startDate,
// this.endDate,
this.workingHours,
this.signature,
this.engSignature,
this.status,
this.assignedEmployeeName,
this.timer,
this.attachments,
});
Map<String, String> toJson(bool isSender) {
@ -47,7 +52,7 @@ class DeviceTransferInfo {
if (timer?.endAt != null) body["${baseKey}end_date"] = timer?.endAt?.toIso8601String();
if (travelingHours != null && travelingHours.isNotEmpty) body["${baseKey}travel_hours"] = travelingHours;
if (status != null) body["${baseKey}status"] = status.id.toString();
if (signature != null && signature.isNotEmpty) body["${baseKey}image"] = signature;
if (engSignature != null && engSignature.isNotEmpty) body["${baseKey}image"] = engSignature;
return body;
}
@ -63,40 +68,37 @@ class DeviceTransferInfo {
client = Hospital.fromHospital(old.client);
department = Department.fromDepartment(old.department);
workingHours = old.workingHours;
attachments = old.attachments ?? [];
// startDate = old.startDate;
// endDate = old.endDate;
timer = old.timer;
travelingHours = old.travelingHours;
comment = old.comment;
if (withSignature) signature = old.signature;
if (withSignature) engSignature = old.engSignature;
status = old.status;
}
factory DeviceTransferInfo.fromJson(Map<String, dynamic> parsedJson, String key) {
return DeviceTransferInfo(
workingHours: parsedJson["${key}working_hours"],
// startDate: parsedJson["${key}start_date"],
// endDate: parsedJson["${key}end_date"],
timer: TimerModel(
startAt: DateTime.tryParse(parsedJson["${key}start_date"] ?? ""),
endAt: DateTime.tryParse(parsedJson["${key}end_date"] ?? ""),
durationInSecond: ((parsedJson["${key}working_hours"] ?? 0) * 60 * 60).toInt(),
),
travelingHours: parsedJson["${key}travel_hours"],
userName: parsedJson["${key}name"],
signature: parsedJson["${key}image"],
userId: parsedJson["${key}id"],
comment: parsedJson["${key}comment"],
assignedEmployeeName: parsedJson["${key}AssignedEmployeeName"],
client: Hospital(id: parsedJson["${key}SiteId"], name: parsedJson["${key}SiteName"]),
department: Department(
id: parsedJson["${key}DepartmentId"],
name: parsedJson["${key}DepartmentName"],
),
status: Lookup(
id: parsedJson["${key}status"],
name: parsedJson["${key}status"],
),
);
}
// factory DeviceTransferInfo.fromJson(Map<String, dynamic> parsedJson, String key) {
// return DeviceTransferInfo(
// workingHours: parsedJson["${key}working_hours"],
// // startDate: parsedJson["${key}start_date"],
// // endDate: parsedJson["${key}end_date"],
// timer: TimerModel(
// startAt: DateTime.tryParse(parsedJson["${key}start_date"] ?? ""),
// endAt: DateTime.tryParse(parsedJson["${key}end_date"] ?? ""),
// durationInSecond: ((parsedJson["${key}working_hours"] ?? 0) * 60 * 60).toInt(),
// ),
// travelingHours: parsedJson["${key}travel_hours"],
// userName: parsedJson["${key}name"],
// signature: parsedJson["${key}image"],
// userId: parsedJson["${key}id"],
// comment: parsedJson["${key}comment"],
// assignedEmployeeName: parsedJson["${key}AssignedEmployeeName"],
// client: Hospital(id: parsedJson["${key}SiteId"], name: parsedJson["${key}SiteName"]),
// department: Department(
// id: parsedJson["${key}DepartmentId"],
// name: parsedJson["${key}DepartmentName"],
// ),
// );
// }
}

@ -0,0 +1,67 @@
import 'package:test_sa/models/device/device.dart';
import '../hospital.dart';
class DeviceTransferSearch {
Device device;
String title, room;
bool mostRecent;
Hospital hospital;
Buildings building;
List<Buildings> buildingsList;
Floors floor;
List<Floors> floorsList;
Departments department;
List<Departments> departmentsList;
DeviceTransferSearch({
this.device,
this.hospital,
this.building,
this.floor,
this.department,
this.room,
this.title,
this.mostRecent = true,
});
Map<String, dynamic> toMap() {
Map<String, dynamic> search = {};
if (title != null && title.isNotEmpty) {
search["transferCode"] = title;
}
if (device != null) {
search["assetId"] = device.id;
}
if (mostRecent != null) {
search["mostRecent"] = mostRecent;
}
if (hospital?.id != null) {
search["destSiteId"] = hospital.id;
}
if (building?.id != null) {
search["destBuildingId"] = building.id;
}
if (floor?.id != null) {
search["destFloorId"] = floor.id;
}
if (department?.id != null) {
search["destDepartmentId"] = department.id;
}
if (room != null && room.isNotEmpty) {
search["destRoom"] = department.id;
}
return search;
}
void fromSearch(DeviceTransferSearch newSearch) {
title = newSearch.title;
room = newSearch.room;
mostRecent = newSearch.mostRecent;
device = newSearch.device;
hospital = newSearch.hospital;
building = newSearch.building;
floor = newSearch.floor;
department = newSearch.department;
}
}

@ -8,6 +8,7 @@ import '../call_request_for_work_order_model.dart';
class GasRefillModel {
int id;
//String userId;
String clientName;
String title;
@ -21,8 +22,9 @@ class GasRefillModel {
String signatureEngineer;
Uint8List localNurseSignature;
Uint8List localEngineerSignature;
num workingHours;
DateTime startDate, endDate, expectedDate;
GasRefillModel({
this.id,
//this.userId,
@ -41,6 +43,7 @@ class GasRefillModel {
this.signatureEngineer,
this.localEngineerSignature,
this.localNurseSignature,
this.workingHours,
});
bool validate() {
@ -73,6 +76,7 @@ class GasRefillModel {
localNurseSignature = model.localNurseSignature;
signatureEngineer = model.signatureEngineer;
signatureNurse = model.signatureNurse;
workingHours = model.workingHours;
}
factory GasRefillModel.fromJson(Map<String, dynamic> parsedJson) {
@ -97,6 +101,7 @@ class GasRefillModel {
assignedEmployee: AssignedEmployee.fromJson(parsedJson['assignedEmployee'] ?? {}),
signatureEngineer: URLs.getFileUrl(parsedJson["engSignature"]),
signatureNurse: URLs.getFileUrl(parsedJson["nurseSignature"]),
workingHours: parsedJson["workingHours"],
);
}
}

@ -22,7 +22,7 @@ class CalibrationTool {
factory CalibrationTool.fromMap(Map<String, dynamic> map) {
return CalibrationTool(
assetsNumber: Lookup(id: map["assetId"], name: map['assetSerialNo']),
assetsNumber: Lookup(id: map["assetId"], name: map['assetNumber']),
dataOfTesting: DateTime.tryParse(map['calibrationDateOfTesters'] ?? ""),
);
}

@ -18,7 +18,8 @@ class Pentry {
DateTime expectedVisitDate;
String travelingHours;
String image;
File imageFile;
List<File> files = [];
// List<Contact> contacts;
List<PPMCheckList> ppmCheckLists;
List<CalibrationTool> calibrationTools;
@ -36,7 +37,7 @@ class Pentry {
this.actualVisitDate,
this.expectedVisitDate,
this.image,
this.imageFile,
this.files,
// this.contacts,
this.ppmCheckLists,
this.calibrationTools,
@ -74,8 +75,8 @@ class Pentry {
Map<String, dynamic> toMap(int visitId) {
Map<String, dynamic> map = {};
map["visitStatusId"] = ppmVisitStatus?.id.toString();
if (status != null) map["deviceStatusId"] = status?.id.toString();
map["visitStatusId"] = ppmVisitStatus?.id?.toString();
if (status != null) map["deviceStatusId"] = status?.id?.toString();
if (travelingHours != null) map["travelingHours"] = travelingHours;
//if(imageFile != null) map["file_attachement"] = base64Encode(imageFile.readAsBytesSync());
map["actualDate"] = actualVisitDate.toIso8601String();
@ -85,10 +86,8 @@ class Pentry {
map["endDate"] = timer.endAt?.toIso8601String() ?? DateTime.now().toIso8601String();
map["workingHours"] = (timer.durationInSecond / 60 / 60).toStringAsFixed(5);
}
if (imageFile != null) {
map["vAttachments"] = [
{"attachmentName": (imageFile.path.split("/").last + base64Encode(imageFile.readAsBytesSync()))}
];
if (files?.isNotEmpty ?? false) {
map["vAttachments"] = files.map((file) => {"attachmentName": _isLocalUrl(file.path) ? (file.path.split("/").last + "|" + base64Encode(file.readAsBytesSync())) : file.path}).toList();
}
map["travelingHours"] = travelingHours;
// if(contacts?.isNotEmpty == true) {
@ -101,11 +100,16 @@ class Pentry {
map["vChecklists"] = ppmCheckLists.map((e) => e.toMap(visitId)).toList();
map["vCalibrationTools"] = calibrationTools.map((e) => e.toMap(visitId)).toList();
map["vKits"] = pmKits.map((e) => e.toMap(visitId)).toList();
map["nurseSignature"] = signatureNurse;//"${DateTime.now().toIso8601String()}.png|$signatureNurse";
map["engSignature"] = signatureEngineer;//"${DateTime.now().toIso8601String()}.png|$signatureEngineer";
map["nurseSignature"] = signatureNurse; //"${DateTime.now().toIso8601String()}.png|$signatureNurse";
map["engSignature"] = signatureEngineer; //"${DateTime.now().toIso8601String()}.png|$signatureEngineer";
return map;
}
bool _isLocalUrl(String url) {
if (url?.isEmpty != false) return false;
return url.startsWith("/") || url.startsWith("file://") || url.substring(1).startsWith(':\\');
}
factory Pentry.fromMap(Map<String, dynamic> map) {
// List<Contact> contacts = [];
// if(map['contacts'] != null){
@ -118,7 +122,12 @@ class Pentry {
if (map['vKits'] != null) {
pmKits = (map['vKits'] as List<dynamic>).map((e) => PMKit.fromMap(e as Map<String, dynamic>)).toList();
}
List<String> files = [];
if (map["vAttachments"] != null) if (map["vAttachments"] is List) {
List list = map["vAttachments"];
list.removeWhere((element) => (element["attachmentURL"]?.toString() ?? "").isEmpty);
files = list.map((e) => URLs.getFileUrl(e["attachmentName"])).toList();
}
List<PPMCheckList> ppmCheckLists = [];
if (map['vChecklists'] != null) {
ppmCheckLists = (map['vChecklists'] as List<dynamic>).map((e) => PPMCheckList.fromMap(e as Map<String, dynamic>)).toList();
@ -129,7 +138,7 @@ class Pentry {
calibrationTools = (map['vCalibrationTools'] as List<dynamic>).map((e) => CalibrationTool.fromMap(e as Map<String, dynamic>)).toList();
}
return Pentry(
status: Lookup(id: map["taskStatusId"], name: map["taskStatusName"]),
status: Lookup(id: map["deviceStatusId"], name: map["deviceStatusName"]),
ppmVisitStatus: Lookup(id: map["visitStatusId"], name: map["visitStatusName"]),
actualVisitDate: DateTime.tryParse(map["actualDate"] ?? ""),
expectedVisitDate: DateTime.tryParse(map["expectedDate"] ?? ""),
@ -143,6 +152,10 @@ class Pentry {
ppmCheckLists: ppmCheckLists,
calibrationTools: calibrationTools,
pmKits: pmKits,
files: files?.map((e) {
return File(e);
})?.toList() ??
[],
signatureNurse: URLs.getFileUrl(map["nurseSignature"]),
signatureEngineer: URLs.getFileUrl(map["engSignature"]),
);
@ -156,7 +169,7 @@ class Pentry {
DateTime expectedVisitDate,
String travelingHours,
String image,
File imageFile,
List<File> files,
List<PPMCheckList> ppmCheckLists,
List<CalibrationTool> calibrationTools,
List<PMKit> pmKits,
@ -171,11 +184,17 @@ class Pentry {
expectedVisitDate: expectedVisitDate ?? this.expectedVisitDate,
travelingHours: travelingHours ?? this.travelingHours,
image: image ?? this.image,
imageFile: imageFile ?? this.imageFile,
files: files ?? this.files,
ppmCheckLists: ppmCheckLists ?? this.ppmCheckLists?.map((e) => e.copyWith())?.toList(),
calibrationTools: calibrationTools ?? this.calibrationTools?.map((e) => e.copyWith())?.toList(),
pmKits: pmKits ?? this.pmKits.map((e) => e.copyWith()).toList(),
signatureNurse: signatureNurse ?? this.signatureNurse,
signatureEngineer: signatureEngineer ?? this.signatureEngineer);
}
void clearEmptyObjects() {
ppmCheckLists.removeWhere((element) => (element?.title?.isEmpty ?? true) && (element?.comment?.isEmpty ?? true) && (element?.measuredValue?.isEmpty ?? true) && element.status == null);
calibrationTools.removeWhere((element) => (element?.assetsNumber == null) && (element?.dataOfTesting == null));
pmKits.removeWhere((element) => (element?.itemCode == null));
}
}

@ -1,23 +1,28 @@
class Part {
int id;
int reportPartID;
String code;
String name;
String partNo;
String partName;
int quantity;
double returnQty, installQty;
Part({
this.id,
this.reportPartID,
this.code,
this.name,
this.partNo,
this.partName,
this.quantity = 1,
this.installQty,
this.returnQty,
});
Map<String, dynamic> toJson() {
return {
"id": reportPartID ?? 0,
"sparePart": {"id": id, "partNo": code, "partName": name},
"qty": quantity
"sparePart": {"id": id, "partNo": partNo, "partName": partName},
"qty": quantity,
if (returnQty != null) "returnQty": returnQty,
if (installQty != null) "installQty": installQty,
};
}
@ -25,9 +30,11 @@ class Part {
return Part(
id: parsedJson["id"],
reportPartID: reportJson != null ? reportJson["id"] : null,
code: parsedJson["partNo"],
name: parsedJson["partName"],
partNo: parsedJson["partNo"],
partName: parsedJson["partName"],
quantity: reportJson != null ? (reportJson["qty"] ?? 1).toInt() : 1,
returnQty: parsedJson["returnQty"],
installQty: parsedJson["installQty"],
);
}
}

@ -14,6 +14,8 @@ class ServiceReport {
int id;
double operatingHours;
DateTime visitDate;
DateTime returnToService;
// DateTime endDate;
// DateTime startDate;
Lookup assetType;
@ -32,7 +34,7 @@ class ServiceReport {
String invoiceNumber;
String invoiceCode;
List<Part> parts;
String image;
List<String> files;
Device device;
String quantity;
String jobSheetNumber;
@ -46,46 +48,48 @@ class ServiceReport {
String reviewComment;
FaultDescription faultDescription;
ServiceReport({
this.id,
this.visitDate,
// this.endDate,
this.assetType,
this.equipmentStatus,
this.type,
this.faultDescriptionId,
this.workingHours,
this.travelingHours,
this.parts,
this.engineer,
this.workPreformed,
this.reason,
this.operatingHours,
this.callLastSituation,
this.currentSituation,
this.jobSheetNumber,
this.image,
this.device,
this.invoiceCode,
this.invoiceNumber,
this.quantity = "1",
this.timer,
this.signatureNurse,
this.signatureEngineer,
this.localNurseSignature,
this.localEngineerSignature,
this.comment,
this.repairLocation,
this.travelingExpense,
// this.startDate,
this.reviewComment,
this.faultDescription,
});
ServiceReport(
{this.id,
this.visitDate,
// this.endDate,
this.assetType,
this.equipmentStatus,
this.type,
this.faultDescriptionId,
this.workingHours,
this.travelingHours,
this.parts,
this.engineer,
this.workPreformed,
this.reason,
this.operatingHours,
this.callLastSituation,
this.currentSituation,
this.jobSheetNumber,
this.files,
this.device,
this.invoiceCode,
this.invoiceNumber,
this.quantity = "1",
this.timer,
this.signatureNurse,
this.signatureEngineer,
this.localNurseSignature,
this.localEngineerSignature,
this.comment,
this.repairLocation,
this.travelingExpense,
// this.startDate,
this.reviewComment,
this.faultDescription,
this.returnToService});
Map<String, dynamic> toMap(ServiceRequest request) {
Map<String, dynamic> _map = {};
if (id != null) _map["id"] = id;
if (visitDate != null) _map["visitDate"] = visitDate.toIso8601String();
if (returnToService != null) _map["replacementDate"] = returnToService.toIso8601String();
//if(serviceType != null) _map["service_type"] = serviceType.id.toString();
if (equipmentStatus != null) _map["equipmentStatus"] = equipmentStatus?.toMap();
if (type != null) _map["typeOfWO"] = type?.toMap();
@ -132,10 +136,8 @@ class ServiceReport {
//if(image != null) _map["image"] = image;
//if(invoiceCode != null) _map["invoice_no"] = invoiceCode;
//if(invoiceNumber != null) _map["invoice_code"] = invoiceNumber;
if (image != null) {
_map["attachmentsWorkOrder"] = [
{"name": image}
];
if (files != null) {
_map["attachmentsWorkOrder"] = files.map((e) => {"name": e}).toList();
}
_map["nurseSignature"] = signatureNurse;
_map["engSignature"] = signatureEngineer;
@ -152,15 +154,14 @@ class ServiceReport {
}
Future<bool> validate() async {
print("visitDate:$visitDate");
print("equipmentStatus:${equipmentStatus?.toMap()}");
print("callLastSituation:${callLastSituation?.toMap()}");
print("parts:$parts");
print("reason:${reason?.toMap()}");
if (visitDate == null) {
await Fluttertoast.showToast(msg: "Visit Date Required");
return false;
}
// if (visitDate == null) {
// await Fluttertoast.showToast(msg: "Visit Date Required");
// return false;
// }
// if (returnToService == null) {
// await Fluttertoast.showToast(msg: "Return To Service Date Required");
// return false;
// }
if (timer?.startAt == null) {
await Fluttertoast.showToast(msg: "Working Hours Required");
return false;
@ -196,6 +197,11 @@ class ServiceReport {
_parts = partsList.map((e) => Part.fromJson(e["sparePart"], reportJson: e)).toList();
}
}
List<String> _files = [];
if (parsedJson["attachmentsWorkOrder"] != null && parsedJson["attachmentsWorkOrder"] is List) {
List list = parsedJson["attachmentsWorkOrder"];
_files = list.map((e) => (URLs.getFileUrl(e["name"]))).toList();
}
return ServiceReport(
id: id,
assetType: Lookup.fromJson(parsedJson["assetType"]),
@ -206,7 +212,7 @@ class ServiceReport {
equipmentStatus: Lookup.fromJson(parsedJson["equipmentStatus"]),
type: Lookup.fromJson(parsedJson["typeOfWO"]),
faultDescription: parsedJson['faultDescription'] != null ? FaultDescription.fromJson(parsedJson['faultDescription']) : null,
files: _files,
// faultDescription: parsedJson["faultDescription"],
// startDate: DateTime.tryParse(parsedJson["startofWorkTime"] ?? ""),
// endDate: DateTime.tryParse(parsedJson["endofWorkTime"] ?? ""),
@ -219,7 +225,8 @@ class ServiceReport {
//quantity: parsedJson["nid"],
travelingHours: parsedJson["travelingHours"],
travelingExpense: parsedJson["travelingExpenses"],
visitDate: DateTime.tryParse(parsedJson["visitDate"]),
visitDate: DateTime.tryParse(parsedJson["visitDate"] ?? ""),
returnToService: DateTime.tryParse(parsedJson["replacementDate"] ?? ""),
workingHours: parsedJson["workingHours"],
timer: TimerModel(
startAt: DateTime.tryParse(parsedJson["startofWorkTime"] ?? ""),

File diff suppressed because it is too large Load Diff

@ -1,5 +1,6 @@
import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/models/device/device.dart';
import 'package:test_sa/models/fault_description.dart';
import 'package:test_sa/models/lookup.dart';
class ServiceRequest {
@ -27,8 +28,9 @@ class ServiceRequest {
bool viewReport;
String engineerMobile;
String deviceModel;
String faultDescription;
String workPerformed;
FaultDescription faultDescription;
//String workPerformed;
String visitDate;
DateTime nextVisitDate;
String jobSheetNumber;
@ -68,7 +70,7 @@ class ServiceRequest {
this.jobSheetNumber,
this.visitDate,
this.nextVisitDate,
this.workPerformed,
//this.workPerformed,
this.reportID,
this.defectType,
this.priority,
@ -86,7 +88,7 @@ class ServiceRequest {
List<String> images = [];
if (parsedJson["attachmentsCallRequest"] != null) if (parsedJson["attachmentsCallRequest"] is List) {
List list = parsedJson["attachmentsCallRequest"];
images = list.map((e) => URLs.getFileUrl(e["attachmentsCallRequest"])).toList();
images = list.map((e) => URLs.getFileUrl(e["name"])).toList();
}
return ServiceRequest(
id: parsedJson["id"].toString(),
@ -114,16 +116,21 @@ class ServiceRequest {
viewReport: parsedJson["workOrder"] != null,
deviceModel: parsedJson["asset"]["modelDefinition"]["modelName"],
engineerMobile: parsedJson["assignedEmployee"] == null ? null : parsedJson["assignedEmployee"]["phone"],
faultDescription: parsedJson["workOrder"] != null ? parsedJson["workOrder"]["faultDescription"] : null,
faultDescription: parsedJson["workOrder"] != null
? parsedJson["workOrder"]["faultDescription"] != null
? FaultDescription.fromJson(parsedJson["workOrder"]["faultDescription"])
: null
: null,
jobSheetNumber: parsedJson["workOrder"] != null ? parsedJson["workOrder"]["jobSheetNumber"] : null,
visitDate: DateTime.tryParse(parsedJson["visitDate"] ?? "").toString().split(" ").first,
nextVisitDate: DateTime.tryParse(parsedJson["nextVisitDate"] ?? ""),
workPerformed: parsedJson["workOrder"] != null ? parsedJson["workOrder"]["workPerformed"] : null,
//workPerformed: parsedJson["workOrder"] != null ? parsedJson["workOrder"]["workPerformed"] : null,
device: Device.fromJson(parsedJson["asset"]),
reviewComment: parsedJson["reviewComment"],
type: Lookup.fromJson(parsedJson['typeofRequest']),
defectType: Lookup.fromJson(parsedJson['defectType']),
loanAvailability: Lookup.fromJson(parsedJson['loanAvailability']),
loanAvailability: Lookup.fromJson(parsedJson['loanAvailablity']),
firstAction: Lookup.fromJson(parsedJson['firstAction']),
requestedThrough: Lookup.fromJson(parsedJson['requestedThrough']),
priority: Lookup.fromJson(parsedJson['priority']),

@ -1,13 +1,20 @@
import 'package:test_sa/models/hospital.dart';
import 'package:test_sa/models/lookup.dart';
import '../call_request_for_work_order_model.dart';
class ServiceRequestSearch {
String callId;
String deviceSerialNumber;
String deviceNumber;
String deviceName;
Hospital hospital;
String model;
Lookup statusValue;
bool mostRecent;
String from, to;
Lookup dateOperator;
AssignedEmployee assignedEmployee;
ServiceRequestSearch({
this.deviceSerialNumber,
@ -16,6 +23,12 @@ class ServiceRequestSearch {
this.deviceName,
this.model,
this.hospital,
this.callId,
this.from,
this.to,
this.assignedEmployee,
this.dateOperator,
this.mostRecent = true,
});
fromSearch(ServiceRequestSearch newSearch) {
@ -24,6 +37,12 @@ class ServiceRequestSearch {
statusValue = newSearch.statusValue;
hospital = newSearch.hospital;
model = newSearch.model;
mostRecent = newSearch.mostRecent;
callId = newSearch.callId;
from = newSearch.from;
to = newSearch.to;
assignedEmployee = newSearch.assignedEmployee;
dateOperator = newSearch.dateOperator;
}
Map<String, dynamic> toMap() {
@ -32,6 +51,10 @@ class ServiceRequestSearch {
search["assetSerialNumber"] = deviceSerialNumber;
}
if (mostRecent != null) {
search["mostRecent"] = mostRecent;
}
if (deviceNumber != null && deviceNumber.isNotEmpty) {
search["assetNo"] = deviceNumber;
}
@ -48,9 +71,24 @@ class ServiceRequestSearch {
search["site"] = hospital.name;
}
if (model != null) {
if (model != null && model.isNotEmpty) {
search["modelDefinition"] = model;
}
if (callId != null && callId.isNotEmpty) {
search["callId"] = callId;
}
if (dateOperator != null && from != null) {
search["requestedDateSymbol"] = dateOperator.toMap();
search["requestedDateFrom"] = from;
}
if (dateOperator != null && to != null) {
search["requestedDateTo"] = to;
}
if (assignedEmployee != null) {
search["assignedEmployee"] = assignedEmployee.toJson();
}
return search;
}
}

@ -0,0 +1,73 @@
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/models/service_request/search_work_order.dart';
import '../fault_description.dart';
class SubWorkOrderDetails {
Lookup equipmentStatus;
Lookup reason;
FaultDescription faultDescription;
List<SparePartsWorkOrders> sparePartsWorkOrders;
List<SuppEngineerWorkOrders> suppEngineerWorkOrders;
SupplierModel supplier;
SubWorkOrderDetails({
this.equipmentStatus,
this.reason,
this.faultDescription,
this.sparePartsWorkOrders,
this.supplier,
this.suppEngineerWorkOrders,
});
SubWorkOrderDetails.fromJson(dynamic json) {
if (json['equipmentStatus'] != null) equipmentStatus = Lookup.fromJson(json['equipmentStatus']);
if (json['reason'] != null) reason = Lookup.fromJson(json['reason']);
if (json['faultDescription'] != null) faultDescription = FaultDescription.fromJson(json['faultDescription']);
if (json['supplier'] != null) supplier = SupplierModel.fromJson(json['supplier']);
if (json['sparePartsWorkOrders'] != null) {
sparePartsWorkOrders = [];
json['sparePartsWorkOrders'].forEach((v) {
sparePartsWorkOrders.add(SparePartsWorkOrders.fromJson(v));
});
}
if (json['suppEngineerWorkOrders'] != null) {
suppEngineerWorkOrders = [];
json['suppEngineerWorkOrders'].forEach((v) {
suppEngineerWorkOrders.add(SuppEngineerWorkOrders.fromJson(v));
});
}
}
SubWorkOrderDetails copyWith({
Lookup equipmentStatus,
Lookup reason,
FaultDescription faultDescription,
List<SparePartsWorkOrders> sparePartsWorkOrders,
SupplierModel supplier,
SuppEngineerWorkOrders suppEngineerWorkOrders,
}) =>
SubWorkOrderDetails(
equipmentStatus: equipmentStatus ?? this.equipmentStatus,
reason: reason ?? this.reason,
faultDescription: faultDescription ?? this.faultDescription,
sparePartsWorkOrders: sparePartsWorkOrders ?? this.sparePartsWorkOrders,
supplier: supplier ?? this.supplier,
suppEngineerWorkOrders: suppEngineerWorkOrders ?? this.suppEngineerWorkOrders,
);
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['equipmentStatus'] = equipmentStatus?.toMap();
map['reason'] = reason?.toMap();
map['faultDescription'] = faultDescription?.toJson();
if (sparePartsWorkOrders?.isNotEmpty ?? false) {
map['sparePartsWorkOrders'] = sparePartsWorkOrders?.map((e) => e.toJson())?.toList();
}
if (suppEngineerWorkOrders?.isNotEmpty ?? false) {
map['suppEngineerWorkOrders'] = suppEngineerWorkOrders?.map((e) => e.toJson())?.toList();
}
map['supplier'] = supplier?.toJson();
return map;
}
}

@ -84,6 +84,7 @@ class Subtitle {
String hospital;
String device;
String deviceImages;
String deviceFiles;
String pickDevice;
String maintenanceIssue;
String create;
@ -186,6 +187,7 @@ class Subtitle {
String image;
String pickImage;
String requiredImage;
String requiredFile;
String taskStatus;
String activationAlert;
@ -205,7 +207,7 @@ class Subtitle {
String reasons;
String attachImage;
String operatingHours;
String partNumber;
String partNumberName;
String number;
String quantity;
String orderWorkNumber;
@ -236,6 +238,8 @@ class Subtitle {
String department;
String room;
String actions;
String pickFromFiles;
String pickFile;
void setIssues(List<String> issues) {
issues.clear();
@ -359,6 +363,7 @@ class Subtitle {
@required this.createServiceRequest,
@required this.delete,
@required this.deviceImages,
@required this.deviceFiles,
@required this.deviceRequired,
@required this.general,
@required this.maintenanceIssueRequired,
@ -404,6 +409,7 @@ class Subtitle {
@required this.image,
@required this.pickImage,
@required this.requiredImage,
@required this.requiredFile,
@required this.activationAlert,
@required this.callId,
@required this.requiredWord,
@ -417,7 +423,7 @@ class Subtitle {
@required this.newServiceReport,
@required this.number,
@required this.operatingHours,
@required this.partNumber,
@required this.partNumberName,
@required this.reasons,
@required this.reportStatus,
@required this.reportType,
@ -447,6 +453,8 @@ class Subtitle {
@required this.department,
@required this.room,
@required this.actions,
@required this.pickFromFiles,
@required this.pickFile,
});
factory Subtitle.fromJson(Map<String, dynamic> parsedJson) {
@ -520,6 +528,7 @@ class Subtitle {
device: parsedJson["device"],
deviceArName: parsedJson["deviceArName"],
deviceImages: parsedJson["deviceImages"],
deviceFiles: parsedJson["deviceFiles"],
deviceModel: parsedJson["deviceModel"],
deviceName: parsedJson["deviceName"],
deviceRequired: parsedJson["deviceRequired"],
@ -607,6 +616,7 @@ class Subtitle {
image: parsedJson["image"],
pickImage: parsedJson["pickImage"],
requiredImage: parsedJson["requiredImage"],
requiredFile: parsedJson["requiredFile"],
taskStatus: parsedJson["taskStatus"],
activationAlert: parsedJson["activationAlert"],
attachImage: parsedJson["attachImage"],
@ -618,7 +628,7 @@ class Subtitle {
newServiceReport: parsedJson["newServiceReport"],
number: parsedJson["number"],
operatingHours: parsedJson["operatingHours"],
partNumber: parsedJson["partNumber"],
partNumberName: parsedJson["partNumberName"],
quantity: parsedJson["quantity"],
reasons: parsedJson["reasons"],
reportStatus: parsedJson["reportStatus"],
@ -651,6 +661,8 @@ class Subtitle {
department: parsedJson["department"],
room: parsedJson["room"],
actions: parsedJson["actions"],
pickFromFiles: parsedJson["pickFromFiles"],
pickFile: parsedJson["pickFile"],
);
}
}

@ -2,6 +2,7 @@ class TimerModel {
DateTime startAt;
DateTime endAt;
int durationInSecond;
// bool stopped;
TimerModel({this.startAt, this.endAt, this.durationInSecond});

@ -4,8 +4,8 @@ import 'package:test_sa/models/enums/user_types.dart';
class User {
int clientId;
String clientName;
int departmentId;
String departmentName;
List<int> departmentId;
List<String> departmentName;
String message;
String username;
String userID;
@ -76,10 +76,10 @@ class User {
}
UsersTypes get type {
switch (userRoles?.first?.name) {
case "Engineer":
switch (userRoles?.first?.value) {
case "R-6":
return UsersTypes.engineer;
case "Hospital":
case "R-7":
return UsersTypes.normal_user;
default:
return null;
@ -148,8 +148,18 @@ class User {
User.fromJson(dynamic json) {
clientId = json['client_id'];
clientName = json['client_name'];
departmentId = json['department_id'];
departmentName = json['department_name'];
if (json['department_id'] != null) {
departmentId = [];
json['department_id'].forEach((v) {
departmentId.add(v);
});
}
if (json['department_name'] != null) {
departmentId = [];
json['department_name'].forEach((v) {
departmentId.add(v);
});
}
message = json['message'];
username = json['username'];
userID = json['userID'];

@ -1,3 +1,4 @@
import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/models/pantry/pentry.dart';
@ -6,6 +7,7 @@ class Visit {
String serialNumber;
String expectDate;
String actualDate;
String createdOn;
int hospitalId;
String hospitalName;
int deviceId;
@ -42,37 +44,42 @@ class Visit {
this.images,
this.assignTo,
this.deviceNumber,
this.createdOn,
});
factory Visit.fromJson(Map<String, dynamic> parsedJson) {
List<String> images = [];
if (parsedJson["vAttachments"] is List) {
List list = parsedJson["vAttachments"];
images = list.map((e) => e["attachmentURL"].toString()).toList();
images = list.map((e) {
return URLs.getFileUrl(e["attachmentURL"].toString());
}).toList();
}
return Visit(
id: parsedJson["id"],
serialNumber: parsedJson["visitCode"],
ppmScheduleId: parsedJson["ppmScheduleId"],
hospitalId: parsedJson["siteId"],
deviceNumber: parsedJson["assetNumber"],
hospitalName: parsedJson["siteName"],
deviceId: parsedJson["assetId"],
deviceSerialNumber: parsedJson["assetSerialNo"],
deviceEnglishName: parsedJson["assetName"],
deviceArabicName: parsedJson["assetName"],
employId: parsedJson["assignedEmployeeId"].toString(),
employName: parsedJson["assignedEmployeeName"],
expectDate: parsedJson["expectedDate"].toString().split("T").first,
actualDate: parsedJson["actualDate"].toString().split("T").first,
modelAndBrand: "${parsedJson["modelName"]} / ${parsedJson["manufacturerName"]}",
// contactStatus: parsedJson["contactStatus"],
images: images,
status: Lookup(
id: parsedJson["visitStatusId"], // actual value (0,1,2)
name: parsedJson["visitStatusName"] // text value
),
assignTo: parsedJson["assignedToName"],
pentry: Pentry.fromMap(parsedJson));
id: parsedJson["id"],
serialNumber: parsedJson["visitCode"],
ppmScheduleId: parsedJson["ppmScheduleId"],
hospitalId: parsedJson["siteId"],
deviceNumber: parsedJson["assetNumber"],
hospitalName: parsedJson["siteName"],
deviceId: parsedJson["assetId"],
deviceSerialNumber: parsedJson["assetSerialNo"],
deviceEnglishName: parsedJson["assetName"],
deviceArabicName: parsedJson["assetName"],
employId: parsedJson["assignedEmployeeId"].toString(),
employName: parsedJson["assignedEmployeeName"],
expectDate: parsedJson["expectedDate"].toString().split("T").first,
actualDate: parsedJson["actualDate"].toString().split("T").first,
modelAndBrand: "${parsedJson["modelName"]} / ${parsedJson["manufacturerName"]}",
// contactStatus: parsedJson["contactStatus"],
images: images,
status: Lookup(
id: parsedJson["visitStatusId"], // actual value (0,1,2)
name: parsedJson["visitStatusName"] // text value
),
assignTo: parsedJson["assignedToName"],
pentry: Pentry.fromMap(parsedJson),
createdOn: parsedJson['createdOn'],
);
}
}

@ -3,6 +3,8 @@ import 'package:test_sa/models/lookup.dart';
class VisitsSearch {
String deviceSerialNumber;
String deviceName;
String deviceNumber;
Hospital hospital;
String brand;
Lookup model;
@ -12,6 +14,7 @@ class VisitsSearch {
DateTime actualDateFrom;
DateTime actualDateTo;
Lookup statusValue;
bool mostRecent;
VisitsSearch({
this.deviceSerialNumber,
@ -24,6 +27,9 @@ class VisitsSearch {
this.contactStatus,
this.expectedDateFrom,
this.expectedDateTo,
this.deviceNumber,
this.deviceName,
this.mostRecent = true,
});
fromSearch(VisitsSearch newSearch) {
@ -37,6 +43,9 @@ class VisitsSearch {
expectedDateFrom = newSearch.expectedDateFrom;
expectedDateTo = newSearch.expectedDateTo;
statusValue = newSearch.statusValue;
mostRecent = newSearch.mostRecent;
deviceNumber = newSearch.deviceNumber;
deviceName = newSearch.deviceName;
}
Map<String, dynamic> toMap() {
@ -49,6 +58,10 @@ class VisitsSearch {
_search["siteId"] = hospital.id;
}
if (mostRecent != null) {
_search["mostRecent"] = mostRecent;
}
if (brand != null && brand.isNotEmpty) {
// todo get new key
_search[""] = brand;

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
class AColors {
AColors._();
static const Color white = Color(0xffffffff);
static const Color black = Color(0xff000000);
static const Color grey3A = Color(0xff2e303a);

@ -3,9 +3,7 @@ import 'package:provider/provider.dart';
import 'package:test_sa/controllers/localization/localization.dart';
import 'package:test_sa/controllers/providers/api/device_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/models/device/device_transfer.dart';
import 'package:test_sa/models/device/device_transfer_info.dart';
import 'package:test_sa/models/subtitle.dart';
import 'package:test_sa/views/app_style/colors.dart';
import 'package:test_sa/views/app_style/sizing.dart';
@ -13,6 +11,7 @@ import 'package:test_sa/views/pages/device_transfer/update_device_transfer.dart'
import 'package:test_sa/views/widgets/buttons/app_back_button.dart';
import 'package:test_sa/views/widgets/buttons/app_small_button.dart';
import 'package:test_sa/views/widgets/device_trancfer/device_transfer_info_section.dart';
import 'package:test_sa/views/widgets/loaders/app_loading.dart';
import 'package:test_sa/views/widgets/loaders/loading_manager.dart';
import 'package:test_sa/views/widgets/requests/info_row.dart';
@ -28,12 +27,10 @@ class DeviceTransferDetails extends StatefulWidget {
}
class _DeviceTransferDetailsState extends State<DeviceTransferDetails> {
final DeviceTransferInfo _model = DeviceTransferInfo();
DeviceTransfer _model;
bool _isSender = false;
bool _isReceiver = false;
UserProvider _userProvider;
SettingProvider _settingProvider;
DeviceTransferProvider _deviceTransferProvider;
bool _isLoading = false;
Subtitle _subtitle;
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
@ -41,150 +38,168 @@ class _DeviceTransferDetailsState extends State<DeviceTransferDetails> {
@override
void initState() {
_model = widget.model;
super.initState();
}
Future<void> _getDeviceTransfer() async {
_model = await Provider.of<DeviceTransferProvider>(context).getRequestById(assetTransferId: widget.model.id);
}
@override
Widget build(BuildContext context) {
_subtitle = AppLocalization.of(context).subtitle;
_userProvider = Provider.of<UserProvider>(context);
_settingProvider = Provider.of<SettingProvider>(context);
_deviceTransferProvider = Provider.of<DeviceTransferProvider>(context);
_isSender = _userProvider.user.userID == widget.model.sender?.userId;
_isReceiver = _userProvider.user.userID == widget.model.receiver?.userId;
return Scaffold(
key: _scaffoldKey,
body: SafeArea(
child: Form(
key: _formKey,
child: LoadingManager(
isLoading: _isLoading,
isFailedLoading: false,
stateCode: 200,
onRefresh: () async {},
child: Column(
children: [
Container(
color: Theme.of(context).colorScheme.primary,
padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 4),
child: Row(
child: FutureBuilder(
future: _getDeviceTransfer(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const ALoading();
} else {
_subtitle = AppLocalization.of(context).subtitle;
_userProvider = Provider.of<UserProvider>(context);
_isSender = _userProvider.user.userID == _model.sender?.userId;
_isReceiver = _userProvider.user.userID == _model.receiver?.userId;
return Form(
key: _formKey,
child: LoadingManager(
isLoading: _isLoading,
isFailedLoading: false,
stateCode: 200,
onRefresh: () async {},
child: Column(
children: [
const ABackButton(),
Expanded(
child: Center(
child: Text(
_subtitle.details,
style: Theme.of(context).textTheme.headline6.copyWith(color: AColors.white, fontStyle: FontStyle.italic),
),
),
),
const SizedBox(width: 58),
],
),
),
Expanded(
child: SingleChildScrollView(
padding: EdgeInsets.all(16 * AppStyle.getScaleFactor(context)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
RequestInfoRow(
title: "Transfer Id",
info: widget.model.title?.toString(),
),
RequestInfoRow(
title: _subtitle.assetName,
info: widget.model.device.assetName,
),
RequestInfoRow(
title: _subtitle.assetSN,
info: widget.model.device.serialNumber,
),
RequestInfoRow(
title: _subtitle.assetNumber,
info: widget.model.device.number,
),
RequestInfoRow(
title: _subtitle.destinationSite,
info: widget.model.device.destSiteName,
),
RequestInfoRow(
title: _subtitle.building,
info: widget.model.device.destBuildingName,
),
RequestInfoRow(
title: _subtitle.floor,
info: widget.model.device.destFloor,
),
RequestInfoRow(
title: _subtitle.department,
info: widget.model.device.destDepartmentName,
),
RequestInfoRow(
title: _subtitle.room,
info: widget.model.device.destRoom,
),
RequestInfoRow(
title: _subtitle.actions,
info: "",
),
const SizedBox(height: 8),
Row(
Container(
color: Theme.of(context).colorScheme.primary,
padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 4),
child: Row(
children: [
const ABackButton(),
Expanded(
child: Text("Sender", style: Theme.of(context).textTheme.headline6),
),
if (_userProvider.user?.type == UsersTypes.engineer)
ASmallButton(
text: _subtitle.edit,
onPressed: (_isSender || false)
? () {
Navigator.of(context).push(MaterialPageRoute(
builder: (_) => UpdateDeviceTransfer(
model: widget.model,
isSender: true,
)));
}
: null,
child: Center(
child: Text(
_subtitle.details,
style: Theme.of(context).textTheme.headline6.copyWith(color: AColors.white, fontStyle: FontStyle.italic),
),
),
],
),
const SizedBox(height: 12),
DeviceTransferInfoSection(
info: widget.model.sender,
),
const SizedBox(height: 8),
Row(
children: [
Expanded(
child: Text("Receiver", style: Theme.of(context).textTheme.headline6),
),
if (_userProvider.user?.type == UsersTypes.engineer)
ASmallButton(
text: _subtitle.edit,
onPressed: (_isReceiver || false)
? () {
Navigator.of(context).push(MaterialPageRoute(
builder: (_) => UpdateDeviceTransfer(
model: widget.model,
isSender: false,
)));
}
: null,
),
const SizedBox(width: 58),
],
),
const SizedBox(height: 12),
DeviceTransferInfoSection(
info: widget.model.receiver,
),
Expanded(
child: SingleChildScrollView(
padding: EdgeInsets.all(16 * AppStyle.getScaleFactor(context)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
RequestInfoRow(
title: "Transfer Id",
info: _model.title?.toString(),
),
RequestInfoRow(
title: _subtitle.assetName,
info: _model.device.assetName,
),
RequestInfoRow(
title: _subtitle.assetSN,
info: _model.device.serialNumber,
),
RequestInfoRow(
title: _subtitle.assetNumber,
info: _model.device.number,
),
RequestInfoRow(
title: _subtitle.destinationSite,
info: _model.device.destSiteName,
),
RequestInfoRow(
title: _subtitle.building,
info: _model.device.destBuildingName,
),
RequestInfoRow(
title: _subtitle.floor,
info: _model.device.destFloor,
),
RequestInfoRow(
title: _subtitle.department,
info: _model.device.destDepartmentName,
),
RequestInfoRow(
title: _subtitle.room,
info: _model.device.destRoom,
),
RequestInfoRow(
title: _subtitle.actions,
info: "",
),
const SizedBox(height: 8),
Row(
children: [
Expanded(
child: Text("Sender", style: Theme.of(context).textTheme.headline6),
),
if (_userProvider.user?.type == UsersTypes.engineer)
ASmallButton(
text: _subtitle.edit,
onPressed: (_isSender)
? (_model.sender.status?.name == "Closed"
? null
: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (_) => UpdateDeviceTransfer(
model: _model,
isSender: true,
)));
})
: null,
),
],
),
const SizedBox(height: 12),
DeviceTransferInfoSection(
info: _model.sender,
isSender: true,
),
const SizedBox(height: 8),
Row(
children: [
Expanded(
child: Text("Receiver", style: Theme.of(context).textTheme.headline6),
),
if (_userProvider.user?.type == UsersTypes.engineer)
ASmallButton(
text: _subtitle.edit,
onPressed: (_isReceiver)
? (_model.receiver.status?.name == "Closed"
? null
: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (_) => UpdateDeviceTransfer(
model: _model,
isSender: false,
)));
})
: null,
),
],
),
const SizedBox(height: 12),
DeviceTransferInfoSection(
info: _model.receiver,
isSender: false,
),
],
),
),
],
),
),
],
),
),
],
),
),
);
}
},
),
),
);

@ -1,7 +1,5 @@
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/api_routes/http_status_manger.dart';
import 'package:test_sa/controllers/providers/api/device_transfer_provider.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart';
import 'package:test_sa/controllers/providers/settings/setting_provider.dart';
@ -12,14 +10,13 @@ import 'package:test_sa/models/device/device_transfer_info.dart';
import 'package:test_sa/models/subtitle.dart';
import 'package:test_sa/views/app_style/sizing.dart';
import 'package:test_sa/views/widgets/buttons/app_button.dart';
import 'package:test_sa/views/widgets/departments/department_button.dart';
import 'package:test_sa/views/widgets/equipment/device_button.dart';
import 'package:test_sa/views/widgets/hospitals/hospital_button.dart';
import 'package:test_sa/views/widgets/loaders/loading_manager.dart';
import 'package:test_sa/views/widgets/titles/app_sub_title.dart';
import '../../../../controllers/localization/localization.dart';
import '../../../controllers/validator/validator.dart';
import '../../app_style/colors.dart';
import '../../widgets/app_text_form_field.dart';
import '../../widgets/gas_refill/building_type_menu.dart';
import '../../widgets/gas_refill/department_type_menu.dart';
@ -28,6 +25,7 @@ import '../../widgets/hospitals/hospital_auto_complete_field_new.dart';
class RequestDeviceTransfer extends StatefulWidget {
static const String id = "/request-device-transfer";
const RequestDeviceTransfer({Key key}) : super(key: key);
@override
@ -66,7 +64,7 @@ class _RequestDeviceTransferState extends State<RequestDeviceTransfer> {
_isLoading = true;
setState(() {});
_formModel.sender?.client?.id = _userProvider.user?.clientId;
// _formModel.sender?.client?.id = _userProvider.user?.clientId;
int status = await _deviceTransferProvider.createRequest(
user: _userProvider.user,
host: _settingProvider.host,
@ -120,7 +118,7 @@ class _RequestDeviceTransferState extends State<RequestDeviceTransfer> {
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"Transfer Device",
"Transfer Asset",
style: Theme.of(context).textTheme.headline5.copyWith(color: Theme.of(context).primaryColor, fontSize: 28, fontWeight: FontWeight.bold),
),
),
@ -140,7 +138,7 @@ class _RequestDeviceTransferState extends State<RequestDeviceTransfer> {
// },
// ),
12.height,
const ASubTitle("Device"),
const ASubTitle("Asset"),
if (_validate && _formModel.device == null)
ASubTitle(
_subtitle.requiredWord,
@ -151,9 +149,19 @@ class _RequestDeviceTransferState extends State<RequestDeviceTransfer> {
device: _formModel.device,
onDevicePick: (device) {
_formModel.device = device;
_formModel.sender.client = device.hospital;
setState(() {});
},
),
if (_formModel.device != null) 8.height,
if (_formModel.device != null) AdditionalAssetInfo(title: "Asset Site", value: _formModel.device.hospital?.name),
if (_formModel.device != null) 4.height,
if (_formModel.device != null) AdditionalAssetInfo(title: "Asset Department", value: _formModel.device.destDepartmentName),
if (_formModel.device != null) 4.height,
if (_formModel.device != null) AdditionalAssetInfo(title: "Asset Floor", value: _formModel.device.destFloor),
if (_formModel.device != null) 4.height,
if (_formModel.device != null) AdditionalAssetInfo(title: "Asset Room", value: _formModel.device.destRoom),
if (_formModel.device != null) 8.height,
// const SizedBox(height: 8,),
// const ASubTitle("Sender Department"),
// if(_validate && _formModel.senderDepartment == null)
@ -202,6 +210,8 @@ class _RequestDeviceTransferState extends State<RequestDeviceTransfer> {
Divider(
color: Theme.of(context).colorScheme.primary,
),
const SizedBox(height: 8),
const ASubTitle("Destination"),
const SizedBox(
height: 4,
),
@ -250,8 +260,8 @@ class _RequestDeviceTransferState extends State<RequestDeviceTransfer> {
},
),
const SizedBox(height: 8),
ASubTitle("Room"),
SizedBox(
const ASubTitle("Room"),
const SizedBox(
height: 4,
),
ATextFormField(
@ -281,3 +291,31 @@ class _RequestDeviceTransferState extends State<RequestDeviceTransfer> {
);
}
}
class AdditionalAssetInfo extends StatelessWidget {
final String title, value;
const AdditionalAssetInfo({@required this.title, @required this.value, Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ASubTitle(title ?? ""),
Container(
width: double.infinity,
alignment: Alignment.center,
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 16),
decoration: BoxDecoration(
color: AColors.inputFieldBackgroundColor,
border: Border.all(
color: const Color(0xffefefef),
),
borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)),
),
child: ASubTitle(value ?? ""),
),
],
);
}
}

@ -1,14 +1,16 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/localization/localization.dart';
import 'package:test_sa/controllers/providers/api/device_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/models/subtitle.dart';
import 'package:test_sa/models/device/device_transfer_search.dart';
import 'package:test_sa/views/app_style/colors.dart';
import 'package:test_sa/views/widgets/buttons/app_back_button.dart';
import 'package:test_sa/views/widgets/device_trancfer/device_transfer_list.dart';
import 'package:test_sa/views/widgets/loaders/loading_manager.dart';
import 'package:test_sa/views/widgets/search/asset_transfer_search_dialog.dart';
import '../../widgets/buttons/app_icon_button.dart';
class TrackDeviceTransferPage extends StatefulWidget {
static const String id = "/track-device-transfer";
@ -23,12 +25,12 @@ class _TrackDeviceTransferPageState extends State<TrackDeviceTransferPage> with
DeviceTransferProvider _deviceTransferProvider;
UserProvider _userProvider;
SettingProvider _settingProvider;
@override
Widget build(BuildContext context) {
_deviceTransferProvider = Provider.of<DeviceTransferProvider>(context);
_userProvider = Provider.of<UserProvider>(context);
_settingProvider = Provider.of<SettingProvider>(context);
Subtitle _subtitle = AppLocalization.of(context).subtitle;
return Scaffold(
body: SafeArea(
@ -54,18 +56,40 @@ class _TrackDeviceTransferPageState extends State<TrackDeviceTransferPage> with
children: [
Row(
children: [
ABackButton(),
const ABackButton(),
Expanded(
child: Center(
child: Text(
"Device Transfer",
"Asset Transfer",
style: Theme.of(context).textTheme.headline6.copyWith(color: AColors.white, fontStyle: FontStyle.italic),
),
),
),
const SizedBox(
width: 48,
)
AIconButton(
iconData: Icons.search,
color: AColors.secondaryColor,
buttonSize: 42,
backgroundColor: AColors.white,
onPressed: () async {
DeviceTransferSearch temp = await showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (context) {
return AssetTransferSearchDialog(initialSearchValue: _deviceTransferProvider.deviceTransferSearch);
},
);
if (temp != null) {
_deviceTransferProvider.deviceTransferSearch = temp;
_deviceTransferProvider.reset();
setState(() {});
await _deviceTransferProvider.getRequests(
user: _userProvider.user,
host: _settingProvider.host,
);
}
},
),
const SizedBox(width: 16),
],
),
],

@ -14,8 +14,9 @@ import 'package:test_sa/views/app_style/sizing.dart';
import 'package:test_sa/views/widgets/app_text_form_field.dart';
import 'package:test_sa/views/widgets/buttons/app_button.dart';
import 'package:test_sa/views/widgets/e_signature/e_signature.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/gas_refill/gas_status.dart';
import 'package:test_sa/views/widgets/status/asset_status.dart';
import 'package:test_sa/views/widgets/titles/app_sub_title.dart';
import '../../../../controllers/localization/localization.dart';
@ -40,7 +41,7 @@ class _UpdateDeviceTransferState extends State<UpdateDeviceTransfer> {
Uint8List _signature;
DeviceTransferProvider _deviceTransferProvider;
final TextEditingController _requestedQuantityController = TextEditingController();
final DeviceTransferInfo _formModel = DeviceTransferInfo();
final DeviceTransferInfo _formModel = DeviceTransferInfo(attachments: []);
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
@ -72,7 +73,6 @@ class _UpdateDeviceTransferState extends State<UpdateDeviceTransfer> {
);
_validate = false;
Navigator.of(context).pop();
Navigator.of(context).pop();
}
}
@ -118,7 +118,7 @@ class _UpdateDeviceTransferState extends State<UpdateDeviceTransfer> {
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"Edit Transfer Device",
"Edit Transfer Asset",
style: Theme.of(context).textTheme.headline5.copyWith(color: Theme.of(context).primaryColor, fontSize: 28, fontWeight: FontWeight.bold),
),
),
@ -180,7 +180,7 @@ class _UpdateDeviceTransferState extends State<UpdateDeviceTransfer> {
const SizedBox(
height: 4,
),
GasStatusMenu(
AssetStatusMenu(
initialValue: _formModel.status,
onSelect: (status) {
if (status == null) return;
@ -189,7 +189,14 @@ class _UpdateDeviceTransferState extends State<UpdateDeviceTransfer> {
},
),
const SizedBox(
height: 8,
height: 16,
),
MultiFilesPicker(
label: "Attachments",
files: _formModel.attachments,
),
const SizedBox(
height: 16,
),
const ASubTitle("Signature"),
// if(_validate && _formModel.signature == null)
@ -198,12 +205,12 @@ class _UpdateDeviceTransferState extends State<UpdateDeviceTransfer> {
height: 4,
),
ESignature(
oldSignature: widget.isSender ? widget.model.sender.signature : widget.model.receiver.signature,
oldSignature: widget.isSender ? widget.model.sender.engSignature : widget.model.receiver.engSignature,
newSignature: _signature,
onSaved: (signature) {
_signature = signature;
if (signature == null || signature.isEmpty) return;
_formModel.signature = "${DateTime.now().toIso8601String()}.png|${base64Encode(signature)}";
_formModel.engSignature = "${DateTime.now().toIso8601String()}.png|${base64Encode(signature)}";
// base64Encode(signature);
},
),

@ -6,14 +6,12 @@ import 'package:test_sa/controllers/localization/localization.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/models/department.dart';
import 'package:test_sa/models/hospital.dart';
import 'package:test_sa/models/subtitle.dart';
import 'package:test_sa/models/user.dart';
import 'package:test_sa/views/widgets/app_text_form_field.dart';
import 'package:test_sa/views/widgets/buttons/app_back_button.dart';
import 'package:test_sa/views/widgets/buttons/app_button.dart';
import 'package:test_sa/views/widgets/departments/department_button.dart';
import 'package:test_sa/views/widgets/hospitals/hospital_button.dart';
import 'package:test_sa/views/widgets/loaders/loading_manager.dart';
@ -131,15 +129,15 @@ class _RegisterState extends State<Register> {
setState(() {});
},
),
const SizedBox(height: 12),
DepartmentButton(
department: Department(id: _user.departmentId, name: _user.departmentName),
onDepartmentPick: (department) {
_user.departmentId = department.id;
_user.departmentName = department.name;
setState(() {});
},
),
// const SizedBox(height: 12),
// DepartmentButton(
// department: Department(id: _user.departmentId, name: _user.departmentName),
// onDepartmentPick: (department) {
// _user.departmentId = department.id;
// _user.departmentName = department.name;
// setState(() {});
// },
// ),
const SizedBox(height: 12),
ATextFormField(
initialValue: _user.phoneNumber,

@ -0,0 +1,85 @@
import 'package:flutter/material.dart';
import 'package:flutter_typeahead/flutter_typeahead.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/models/service_request/search_work_order.dart';
import '../../../controllers/providers/api/status_drop_down/report/vendor_provider.dart';
import '../../app_style/colors.dart';
import '../../app_style/sizing.dart';
class AutoGeneratedVendorName extends StatefulWidget {
final String initialValue;
final Function(Supplier) onSearch;
const AutoGeneratedVendorName({Key key, this.initialValue, this.onSearch}) : super(key: key);
@override
State<AutoGeneratedVendorName> createState() => _AutoGeneratedVendorNameState();
}
class _AutoGeneratedVendorNameState extends State<AutoGeneratedVendorName> {
TextEditingController _controller;
@override
void initState() {
super.initState();
_controller = TextEditingController(text: widget.initialValue ?? "");
}
@override
void didUpdateWidget(covariant AutoGeneratedVendorName oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.initialValue != widget.initialValue) {
_controller = TextEditingController(text: widget.initialValue ?? "");
}
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final vendorProvider = Provider.of<VendorProvider>(context, listen: false);
return Container(
padding: const EdgeInsets.symmetric(horizontal: 16),
decoration: BoxDecoration(
color: AColors.inputFieldBackgroundColor,
border: Border.all(
color: const Color(0xffefefef),
),
borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)),
// boxShadow: [
// AppStyle.boxShadow
// ]
),
child: TypeAheadField<Supplier>(
textFieldConfiguration: TextFieldConfiguration(
style: Theme.of(context).textTheme.titleLarge,
controller: _controller,
textAlign: TextAlign.center,
decoration: const InputDecoration(
hintText: "Vendor Name",
border: InputBorder.none,
disabledBorder: InputBorder.none,
focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none,
),
textInputAction: TextInputAction.search,
),
suggestionsCallback: (vale) async {
await vendorProvider.getVendors(_controller.text.trim());
return vendorProvider.vendors;
},
itemBuilder: (context, vendor) {
return ListTile(title: Text(vendor.suppliername));
},
onSuggestionSelected: (hospital) {
widget.onSearch(hospital);
},
),
);
}
}

@ -16,6 +16,7 @@ import 'package:test_sa/views/app_style/colors.dart';
import 'package:test_sa/views/pages/sub_workorder/spare_parts_details_bottom_sheet.dart';
import 'package:test_sa/views/pages/sub_workorder/work_order_details_bottom_sheet.dart';
import 'package:test_sa/views/pages/sub_workorder/workorder_details.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/status/service_request/service_request_defect_types_mune.dart';
@ -27,7 +28,6 @@ import '../../widgets/app_text_form_field.dart';
import '../../widgets/buttons/app_back_button.dart';
import '../../widgets/buttons/app_button.dart';
import '../../widgets/date_and_time/date_picker.dart';
import '../../widgets/images/mini_one_image_picker.dart';
import '../../widgets/status/report/service_report_fault_description.dart';
import '../../widgets/status/report/service_report_reasons.dart';
import '../../widgets/titles/app_sub_title.dart';
@ -47,7 +47,7 @@ class _CreateSubWorkOrderPageState extends State<CreateSubWorkOrderPage> {
SearchWorkOrder _subWorkOrders;
Lookup _serviceReportReason = const Lookup();
ServiceReport _serviceReport;
File _image;
final List<File> _files = [];
bool _isLoading = false;
bool _validate = false;
@ -58,6 +58,7 @@ class _CreateSubWorkOrderPageState extends State<CreateSubWorkOrderPage> {
callRequest: CallRequest(id: widget?.workOrder?.callRequest?.id),
currentSituation: null,
supplier: null,
parentWOId: widget.workOrder.id,
);
_serviceReport = ServiceReport(id: widget.workOrder.id, type: widget.workOrder.assetType, equipmentStatus: widget.workOrder.equipmentStatus);
_isLoading = true;
@ -69,9 +70,19 @@ class _CreateSubWorkOrderPageState extends State<CreateSubWorkOrderPage> {
Future getAssetType() async {
//if (assetTypesProvider == null) {
final serviceRequestProvider = Provider.of<ServiceRequestsProvider>(context);
Provider.of<ServiceRequestFaultDescriptionProvider>(context, listen: false).reset();
assetTypesProvider = Provider.of<ServiceStatusProvider>(context, listen: false);
_callRequestForWorkOrder = await Provider.of<ServiceRequestsProvider>(context).getCallRequestForWorkOrder(callId: widget.workOrder.callRequest.id.toString());
_callRequestForWorkOrder = await serviceRequestProvider.getCallRequestForWorkOrder(callId: widget.workOrder.callRequest.id.toString());
if (_subWorkOrders?.parentWOId != null) {
print(_subWorkOrders?.parentWOId.toString());
final subWoDetails = await serviceRequestProvider.getSubWorkOrderDetails(parentId: _subWorkOrders?.parentWOId.toString());
_subWorkOrders.copyDetails(subWoDetails);
_serviceReport.equipmentStatus = subWoDetails.equipmentStatus;
_serviceReport.reason = subWoDetails.reason;
_serviceReport.faultDescription = subWoDetails.faultDescription;
_serviceReportReason = _subWorkOrders.reason;
}
await assetTypesProvider.getTypes();
_subWorkOrders?.assetType = assetTypesProvider.statuses?.firstWhere(
(element) => element.value == _callRequestForWorkOrder?.assetType,
@ -112,7 +123,7 @@ class _CreateSubWorkOrderPageState extends State<CreateSubWorkOrderPage> {
Expanded(
child: Center(
child: Text(
"New Work Order",
"New Sub Work Order",
style: Theme.of(context).textTheme.titleLarge.copyWith(color: AColors.white, fontStyle: FontStyle.italic),
),
),
@ -158,11 +169,11 @@ class _CreateSubWorkOrderPageState extends State<CreateSubWorkOrderPage> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const ASubTitle("Return to Service"),
if (_validate && _subWorkOrders.visitDate == null)
ASubTitle(
subtitle.requiredWord,
color: Colors.red,
),
// if (_validate && _subWorkOrders.visitDate == null)
// ASubTitle(
// subtitle.requiredWord,
// color: Colors.red,
// ),
const SizedBox(
height: 4,
),
@ -200,7 +211,7 @@ class _CreateSubWorkOrderPageState extends State<CreateSubWorkOrderPage> {
onSelect: (status) {
_serviceReportReason = status;
_subWorkOrders.reason = status;
setState(() {});
// setState(() {});
},
),
],
@ -238,6 +249,8 @@ class _CreateSubWorkOrderPageState extends State<CreateSubWorkOrderPage> {
],
),
const SizedBox(height: 8),
MultiFilesPicker(label: "Attachments", files: _files),
const SizedBox(height: 8),
InkWell(
onTap: () async {
await showModalBottomSheet(
@ -247,7 +260,7 @@ class _CreateSubWorkOrderPageState extends State<CreateSubWorkOrderPage> {
backgroundColor: Colors.transparent,
builder: (context) => WorkOrderDetailsBottomSheet(subWorkOrder: _subWorkOrders),
);
log(_subWorkOrders?.toJson()?.toString());
//log(_subWorkOrders?.toJson()?.toString());
},
child: Card(
child: ListTile(
@ -272,7 +285,10 @@ class _CreateSubWorkOrderPageState extends State<CreateSubWorkOrderPage> {
useSafeArea: true,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (context) => SparePartsBottomSheet(subWorkOrder: _subWorkOrders),
builder: (context) => SparePartsBottomSheet(
subWorkOrder: _subWorkOrders,
assetId: widget.workOrder?.callRequest?.asset?.id,
),
);
log(_subWorkOrders?.toJson()?.toString());
},
@ -291,15 +307,14 @@ class _CreateSubWorkOrderPageState extends State<CreateSubWorkOrderPage> {
),
),
),
const SizedBox(height: 8),
AMiniOneImagePicker(
image: _image,
onPick: (image) {
_image = image;
_subWorkOrders.attachmentsWorkOrder ??= [];
_subWorkOrders.attachmentsWorkOrder.add(AttachmentsWorkOrder(name: "${image.path.split("/").last}|${base64Encode(image.readAsBytesSync())}"));
},
),
// AMiniOneFilePicker(
// file: _file,
// onPick: (file) {
// _file = file;
// _subWorkOrders.attachmentsWorkOrder ??= [];
// _subWorkOrders.attachmentsWorkOrder.add(AttachmentsWorkOrder(name: "${file.path.split("/").last}|${base64Encode(file.readAsBytesSync())}"));
// },
// ),
const SizedBox(height: 50),
],
),
@ -313,10 +328,17 @@ class _CreateSubWorkOrderPageState extends State<CreateSubWorkOrderPage> {
child: AButton(
text: subtitle.create,
onPressed: () async {
_subWorkOrders.parentWOId = widget.workOrder.id;
_validate = true;
setState(() {});
if (validate()) {
if (_subWorkOrders.calllastSituation.value == 12 && (_subWorkOrders.sparePartsWorkOrders == null || _subWorkOrders.sparePartsWorkOrders.isEmpty)) {
await Fluttertoast.showToast(msg: "You have to add parts");
return;
}
_subWorkOrders.attachmentsWorkOrder ??= [];
for (var file in _files) {
_subWorkOrders.attachmentsWorkOrder.add(AttachmentsWorkOrder(name: "${file.path.split("/").last}|${base64Encode(file.readAsBytesSync())}"));
}
if (_subWorkOrders.timer?.startAt == null || _subWorkOrders.timer?.endAt == null) {
Fluttertoast.showToast(msg: "Working hours required");
return;
@ -330,6 +352,11 @@ class _CreateSubWorkOrderPageState extends State<CreateSubWorkOrderPage> {
if (_formKey.currentState?.validate() ?? false) {}
_formKey.currentState?.save();
final serviceRequestsProvider = Provider.of<ServiceRequestsProvider>(context, listen: false);
for (var element in (_subWorkOrders?.suppEngineerWorkOrders ?? [])) {
if (element != null) {
element.id = 0;
}
}
final status = await serviceRequestsProvider.createSubWorkOrder(workOrder: _subWorkOrders);
_isLoading = false;
setState(() {});
@ -354,7 +381,7 @@ class _CreateSubWorkOrderPageState extends State<CreateSubWorkOrderPage> {
}
bool validate() {
if (_subWorkOrders.faultDescription == null || _subWorkOrders.reason == null || _subWorkOrders.equipmentStatus == null || _subWorkOrders.visitDate == null) {
if (_subWorkOrders.faultDescription == null || _subWorkOrders.reason == null || _subWorkOrders.equipmentStatus == null) {
return false;
} else {
return true;

@ -1,5 +1,4 @@
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/service_requests_provider.dart';
import 'package:test_sa/models/engineer.dart';
@ -24,6 +23,7 @@ import '../../widgets/titles/app_sub_title.dart';
class SearchSubWorkOrderPage extends StatefulWidget {
static String id = "/SubWorkOrderPage";
const SearchSubWorkOrderPage({Key key}) : super(key: key);
@override

@ -6,6 +6,7 @@ import 'package:test_sa/views/app_style/colors.dart';
import '../../../controllers/localization/localization.dart';
import '../../../models/subtitle.dart';
import '../../app_style/sizing.dart';
import '../../widgets/app_text_form_field.dart';
import '../../widgets/buttons/app_button.dart';
import '../../widgets/parts/auto_complete_parts_field.dart';
import '../../widgets/parts/part_item.dart';
@ -13,7 +14,9 @@ import '../../widgets/titles/app_sub_title.dart';
class SparePartsBottomSheet extends StatefulWidget {
final SearchWorkOrder subWorkOrder;
const SparePartsBottomSheet({this.subWorkOrder, Key key}) : super(key: key);
final num assetId;
const SparePartsBottomSheet({this.subWorkOrder, this.assetId, Key key}) : super(key: key);
@override
State<SparePartsBottomSheet> createState() => _SparePartsBottomSheetState();
@ -86,7 +89,7 @@ class _SparePartsBottomSheetState extends State<SparePartsBottomSheet> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ASubTitle(subtitle.partNumber),
ASubTitle(subtitle.partNumberName),
_validate && _workOrder.sparePartsWorkOrders == null
? ASubTitle(
subtitle.requiredWord,
@ -95,12 +98,15 @@ class _SparePartsBottomSheetState extends State<SparePartsBottomSheet> {
: const SizedBox.shrink(),
const SizedBox(height: 4),
AutoCompletePartsField(
assetId: widget.assetId,
onPick: (part) {
_workOrder.sparePartsWorkOrders ??= [];
_workOrder.sparePartsWorkOrders.add(SparePartsWorkOrders(
id: part.reportPartID,
qty: part.quantity,
sparePart: SparePart(id: part.id, partName: part.name, partNo: part.code),
sparePart: SparePart(id: part.id, partName: part.partName, partNo: part.partNo),
installQty: part.installQty,
returnQty: part.returnQty,
));
},
),
@ -128,19 +134,55 @@ class _SparePartsBottomSheetState extends State<SparePartsBottomSheet> {
Part part = Part(
id: spare.sparePart?.id,
reportPartID: spare.id,
code: spare.sparePart?.partNo,
name: spare.sparePart?.partName,
quantity: spare.qty,
partNo: spare.sparePart?.partNo,
partName: spare.sparePart?.partName,
quantity: spare.qty?.toInt(),
installQty: spare.installQty,
returnQty: spare.returnQty,
);
return PartItem(
part: part,
onEdit: (qty) {
spare.qty = qty;
},
onDelete: (part) {
_workOrder.sparePartsWorkOrders.remove(spare);
setState(() {});
},
return Column(
children: [
PartItem(
part: part,
onEdit: (qty) {
spare.qty = qty;
},
onDelete: (part) {
_workOrder.sparePartsWorkOrders.remove(spare);
setState(() {});
},
),
if (_workOrder.calllastSituation?.name?.toLowerCase()?.contains("part installation") ?? false)
Row(
children: [
Expanded(
child: ATextFormField(
initialValue: part?.returnQty?.toString(),
labelText: "Return Quantity",
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.titleMedium,
textInputType: TextInputType.number,
onSaved: (value) {
spare.returnQty = num.tryParse(value)?.toDouble();
},
),
),
const SizedBox(width: 8),
Expanded(
child: ATextFormField(
initialValue: part?.installQty?.toString(),
labelText: "Install Quantity",
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.titleMedium,
textInputType: TextInputType.number,
onSaved: (value) {
spare.installQty = num.tryParse(value)?.toDouble();
},
),
),
],
),
],
);
},
),

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/models/service_request/search_work_order.dart';
import 'package:test_sa/models/subtitle.dart';
import 'package:test_sa/views/widgets/app_text_form_field.dart';
@ -8,11 +9,13 @@ import 'package:test_sa/views/widgets/buttons/app_button.dart';
import 'package:test_sa/views/widgets/status/report/service_report_assistant_employee_menu.dart';
import 'package:test_sa/views/widgets/status/report/service_report_maintenance_situation.dart';
import 'package:test_sa/views/widgets/status/report/service_report_repair_location.dart';
import 'package:test_sa/views/widgets/status/service_request/supplier_engineers_menu.dart';
import '../../../controllers/localization/localization.dart';
import '../../../controllers/providers/api/status_drop_down/report/service_report_maintenance_situation_provider.dart';
import '../../widgets/timer/app_timer.dart';
import '../../widgets/titles/app_sub_title.dart';
import 'auto_generated_vendor_name.dart';
class WorkOrderDetailsBottomSheet extends StatefulWidget {
final SearchWorkOrder subWorkOrder;
@ -25,17 +28,33 @@ class WorkOrderDetailsBottomSheet extends StatefulWidget {
class _WorkOrderDetailsBottomSheetState extends State<WorkOrderDetailsBottomSheet> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final SearchWorkOrder _workOrder = SearchWorkOrder();
bool _showVendorFields = false;
SuppEngineerWorkOrders engineer;
@override
void initState() {
super.initState();
_workOrder.copyFrom(widget.subWorkOrder);
if (checkVendorFieldsVisibility(_workOrder.calllastSituation)) {
if (_workOrder.suppEngineerWorkOrders?.isNotEmpty ?? false) {
engineer = _workOrder.suppEngineerWorkOrders?.last;
engineer?.id = engineer?.supplierContactId;
}
_workOrder.supplier ??= SupplierModel(id: _workOrder?.supplier?.id);
}
if (context.mounted) {
Provider.of<ServiceReportMaintenanceSituationProvider>(context, listen: false).reset();
}
}
bool checkVendorFieldsVisibility(Lookup callsLastSituation) {
bool result = (_workOrder.supplier?.suppliername?.isNotEmpty ?? false) ||
(callsLastSituation?.name?.toLowerCase()?.contains("under repair-vendor") ?? false) ||
(callsLastSituation?.name?.toLowerCase()?.contains("waiting for vendor") ?? false);
_showVendorFields = result;
return result;
}
@override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
@ -118,15 +137,53 @@ class _WorkOrderDetailsBottomSheetState extends State<WorkOrderDetailsBottomShee
ServiceReportMaintenanceSituation(
initialValue: _workOrder.calllastSituation,
onSelect: (status) {
if (checkVendorFieldsVisibility(status)) {
_workOrder.supplier ??= SupplierModel(id: _workOrder?.supplier?.id);
engineer = null;
}
if (status?.value == 12 || _workOrder.calllastSituation?.value == 12) {
_workOrder.calllastSituation = status;
_workOrder.mrNumber = null;
setState(() {});
} else {
_workOrder.calllastSituation = status;
}
setState(() {});
},
woId: widget.subWorkOrder?.callRequest?.id?.toString(),
woId: widget.subWorkOrder?.parentWOId?.toString(),
),
if (_workOrder.calllastSituation.value == 12) const ASubTitle(" You have to add parts", color: Colors.amber, padding: EdgeInsets.all(2), font: 11),
if (_workOrder.calllastSituation.value == 12) const SizedBox(height: 8),
if (_workOrder.calllastSituation.value == 12)
ATextFormField(
labelText: "MR number",
initialValue: _workOrder.mrNumber,
onSaved: (value) {
_workOrder.mrNumber = value;
},
),
if (_showVendorFields) const SizedBox(height: 8),
if (_showVendorFields)
AutoGeneratedVendorName(
initialValue: _workOrder.supplier?.suppliername,
onSearch: (supplier) {
_workOrder.supplier.id = supplier.id;
_workOrder.supplier.suppliername = supplier.suppliername;
_workOrder.supplier.suppPersons = supplier.suppPersons;
setState(() {});
},
),
if (_showVendorFields) const SizedBox(height: 8),
if (_showVendorFields)
SupplierEngineersMenu(
initialValue: engineer,
engineers: _workOrder?.supplier?.suppPersons,
onSelect: (engineer) {
if (engineer != null) {
this.engineer = engineer;
}
},
),
const SizedBox(height: 8),
const ASubTitle("Repair Location"),
const SizedBox(height: 4),
@ -158,6 +215,20 @@ class _WorkOrderDetailsBottomSheetState extends State<WorkOrderDetailsBottomShee
await Fluttertoast.showToast(msg: "Working Hours Timer Isn't Started");
return;
}
if (_showVendorFields && (_workOrder.supplier.suppliername == null || _workOrder.supplier.suppliername.isEmpty)) {
await Fluttertoast.showToast(msg: "Vendor Name Field is Required");
return;
}
if (_showVendorFields && _workOrder.suppEngineerWorkOrders == null) {
await Fluttertoast.showToast(msg: "Vendor Engineer Field is Required");
return;
}
_workOrder.suppEngineerWorkOrders ?? [];
if (engineer != null) _workOrder.suppEngineerWorkOrders.add(engineer..id = 0);
if (_workOrder.calllastSituation == null) {
await Fluttertoast.showToast(msg: "Call Last Situation Field is Required");
return;
}
_formKey.currentState.save();
widget.subWorkOrder.copyFrom(_workOrder);
Navigator.pop(context);

@ -1,5 +1,7 @@
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:test_sa/controllers/localization/localization.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/models/subtitle.dart';
import 'package:test_sa/views/app_style/colors.dart';
import 'package:test_sa/views/app_style/sizing.dart';
@ -11,6 +13,7 @@ class WorkOrderItem extends StatelessWidget {
final int index;
final SearchWorkOrder item;
final Function(SearchWorkOrder) onPressed;
const WorkOrderItem({Key key, this.item, this.onPressed, this.index}) : super(key: key);
@override
@ -30,7 +33,13 @@ class WorkOrderItem extends StatelessWidget {
),
),
onPressed: () {
onPressed(item);
item.callRequest.status.value == 5 || item.callRequest.status.value == 3
? Fluttertoast.showToast(
msg: "Request is ${item.callRequest.status.name}. No more sub work orders will be create.",
toastLength: Toast.LENGTH_LONG,
gravity: ToastGravity.BOTTOM,
)
: onPressed(item);
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@ -45,17 +54,39 @@ class WorkOrderItem extends StatelessWidget {
item.callRequest.callNo ?? "-----",
style: Theme.of(context).textTheme.headline6.copyWith(color: onItemColor, fontSize: 16, fontWeight: FontWeight.bold),
),
Text(
item.callRequest.asset.id.toString(),
style: Theme.of(context).textTheme.subtitle2.copyWith(
color: onItemColor,
// Text(
// item.callRequest.asset.id.toString(),
// style: Theme.of(context).textTheme.subtitle2.copyWith(
// color: onItemColor,
// ),
// ),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Asset Name:",
style: Theme.of(context).textTheme.subtitle2.copyWith(
color: onItemColor,
),
),
8.width,
Expanded(
child: Text(
//CallRequest.Asset.ModelDefinition.AssetND
// .AssetName
item.callRequest.asset.modelDefinition.assetName,
style: Theme.of(context).textTheme.subtitle2.copyWith(
color: onItemColor,
),
),
),
],
),
Row(
children: [
Expanded(
child: Text(
_subtitle.assetName,
"Asset Number:",
style: Theme.of(context).textTheme.subtitle2.copyWith(
color: onItemColor,
),
@ -70,8 +101,27 @@ class WorkOrderItem extends StatelessWidget {
),
],
),
Row(
children: [
Expanded(
child: Text(
"Asset SN:",
style: Theme.of(context).textTheme.subtitle2.copyWith(
color: onItemColor,
),
),
),
//if (item.clientName != null)
Text(
item.callRequest.asset.assetSerialNo,
style: Theme.of(context).textTheme.subtitle2.copyWith(
color: onItemColor,
),
),
],
),
Text(
item.calllastSituation.name,
item.currentSituation.name,
style: Theme.of(context).textTheme.subtitle2.copyWith(
color: onItemColor,
),

@ -17,6 +17,7 @@ import 'create_sub_workorder_page.dart';
class WorkOrderList extends StatefulWidget {
List<SearchWorkOrder> items;
final Future<List<SearchWorkOrder>> Function() onLazyLoading;
WorkOrderList({Key key, this.items, this.onLazyLoading}) : super(key: key);
@override
@ -25,6 +26,7 @@ class WorkOrderList extends StatefulWidget {
class _WorkOrderListState extends State<WorkOrderList> {
List<SearchWorkOrder> _items;
@override
void initState() {
super.initState();
@ -81,7 +83,6 @@ class _WorkOrderListState extends State<WorkOrderList> {
onPressed: (model) {
// Navigator.of(context).push(MaterialPageRoute(
// builder: (_) => WorkOrderUpdate(item: model,)));
log(model?.toJson()?.toString());
Navigator.push(
context,
MaterialPageRoute(builder: (context) => CreateSubWorkOrderPage(workOrder: model)),

@ -25,15 +25,16 @@ import '../../../../models/enums/user_types.dart';
import '../../../app_style/colors.dart';
class GasRefillDetails extends StatefulWidget {
final GasRefillModel model;
const GasRefillDetails({Key key, this.model}) : super(key: key);
GasRefillModel model;
GasRefillDetails({Key key, this.model}) : super(key: key);
@override
State<GasRefillDetails> createState() => _GasRefillDetailsState();
}
class _GasRefillDetailsState extends State<GasRefillDetails> {
final GasRefillModel _model = GasRefillModel();
GasRefillModel _model = GasRefillModel();
bool _enableEdit = false;
bool _validate = false;
UserProvider _userProvider;
@ -43,6 +44,7 @@ class _GasRefillDetailsState extends State<GasRefillDetails> {
Subtitle _subtitle;
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
_update() async {
_validate = true;
if (!_formKey.currentState.validate()) {
@ -73,7 +75,7 @@ class _GasRefillDetailsState extends State<GasRefillDetails> {
@override
void initState() {
_model.fromGasRefillModel(widget.model);
_model?.fromGasRefillModel(widget.model);
super.initState();
}
@ -100,11 +102,15 @@ class _GasRefillDetailsState extends State<GasRefillDetails> {
padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 4),
child: Row(
children: [
const ABackButton(),
ABackButton(
onPressed: () {
Navigator.of(context).pop(_model);
},
),
Expanded(
child: Center(
child: Text(
_subtitle.details,
"Gas Refill Request",
style: Theme.of(context).textTheme.headline6.copyWith(color: AColors.white, fontStyle: FontStyle.italic),
),
),
@ -115,21 +121,26 @@ class _GasRefillDetailsState extends State<GasRefillDetails> {
color: Theme.of(context).colorScheme.onPrimary,
buttonSize: 42,
backgroundColor: AColors.green,
onPressed: () async {
// _enableEdit = !_enableEdit;
print(widget.model.startDate);
_model.fromGasRefillModel(widget.model);
print(widget.model.startDate);
// setState(() {});
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => RequestGasRefill(
gasRefillModel: widget.model,
),
),
);
},
onPressed: (widget.model.status?.value ?? 0) == 2
? null
: () async {
// _enableEdit = !_enableEdit;
_model?.fromGasRefillModel(widget.model);
// setState(() {});
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => RequestGasRefill(
gasRefillModel: widget.model,
),
),
).then((value) {
if (value != null) {
_model = value;
}
});
setState(() {});
},
),
const SizedBox(
width: 16,
@ -144,7 +155,7 @@ class _GasRefillDetailsState extends State<GasRefillDetails> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
RequestInfoRow(
title: _subtitle.title,
title: "Gas Refill No",
info: _model.title,
),
RequestInfoRow(
@ -159,13 +170,17 @@ class _GasRefillDetailsState extends State<GasRefillDetails> {
title: "Floor",
info: _model.floor?.name,
),
RequestInfoRow(
title: "Department",
info: _model.department?.departmentName,
),
RequestInfoRow(
title: _subtitle.startDate,
info: _model.startDate == null ? null : DateFormat.yMd().format(_model.startDate),
info: _model.startDate == null ? null : "${DateFormat.yMd().format(_model.startDate)} ${DateFormat.Hms().format(_model.startDate)}",
),
RequestInfoRow(
title: _subtitle.endDate,
info: _model.endDate == null ? null : DateFormat.yMd().format(_model.endDate),
info: _model.endDate == null ? null : "${DateFormat.yMd().format(_model.endDate)} ${DateFormat.Hms().format(_model.endDate)}",
),
_enableEdit
? Column(

@ -12,10 +12,10 @@ import 'package:test_sa/models/gas_refill/gas_refill_details.dart';
import 'package:test_sa/models/gas_refill/gas_refill_model.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/models/subtitle.dart';
import 'package:test_sa/models/timer_model.dart';
import 'package:test_sa/views/app_style/sizing.dart';
import 'package:test_sa/views/widgets/app_text_form_field.dart';
import 'package:test_sa/views/widgets/buttons/app_button.dart';
import 'package:test_sa/views/widgets/date_and_time/time_picker.dart';
import 'package:test_sa/views/widgets/gas_refill/building_type_menu.dart';
import 'package:test_sa/views/widgets/gas_refill/department_type_menu.dart';
import 'package:test_sa/views/widgets/gas_refill/floor_type_menu.dart';
@ -30,12 +30,13 @@ import 'package:test_sa/views/widgets/titles/app_sub_title.dart';
import '../../../../controllers/localization/localization.dart';
import '../../../../controllers/providers/api/hospitals_provider.dart';
import '../../../../models/enums/user_types.dart';
import '../../../widgets/e_signature/e_signature.dart';
import '../../../widgets/timer/app_timer.dart';
class RequestGasRefill extends StatefulWidget {
static const String id = "/request-gas-refill";
final GasRefillModel gasRefillModel;
const RequestGasRefill({this.gasRefillModel, Key key}) : super(key: key);
@override
@ -85,6 +86,12 @@ class _RequestGasRefillState extends State<RequestGasRefill> {
return;
}
}
if (_gasRefillProvider.department?.name == null) {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("Select department")));
_isLoading = false;
setState(() {});
return;
}
int status = widget.gasRefillModel == null
? await _gasRefillProvider.createModel(
@ -104,7 +111,8 @@ class _RequestGasRefillState extends State<RequestGasRefill> {
Fluttertoast.showToast(
msg: _subtitle.requestCompleteSuccessfully,
);
Navigator.of(context).pop();
Navigator.of(context).pop(_formModel);
setState(() {});
} else {
String errorMessage = HttpStatusManger.getStatusMessage(status: status, subtitle: _subtitle);
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
@ -149,20 +157,25 @@ class _RequestGasRefillState extends State<RequestGasRefill> {
_settingProvider = Provider.of<SettingProvider>(context);
if (_gasRefillProvider == null) {
_gasRefillProvider = Provider.of<GasRefillProvider>(context, listen: false);
_gasRefillProvider.reset();
//_gasRefillProvider.reset();
}
if (widget.gasRefillModel != null && _firstTime) {
_formModel = widget.gasRefillModel;
_formModel.status = const Lookup(value: 0);
HospitalsProvider().getHospitalsListByVal(searchVal: widget.gasRefillModel.clientName).then((value) {
_gasRefillProvider.hospital = value?.firstWhere((element) => element.name == widget.gasRefillModel.clientName, orElse: () => null);
print(_gasRefillProvider.hospital?.buildings?.length);
print(widget.gasRefillModel?.building?.name);
if (_firstTime) {
String _clientName;
if (widget.gasRefillModel != null) {
_formModel.status = widget.gasRefillModel?.status ?? const Lookup(value: 0);
_gasRefillProvider.expectedDateTime = _formModel.expectedDate;
_gasRefillProvider.timer = TimerModel(startAt: widget.gasRefillModel?.startDate, endAt: widget.gasRefillModel?.endDate);
_clientName = _formModel.clientName;
} else {
_gasRefillProvider.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);
_gasRefillProvider.startDate = widget.gasRefillModel?.startDate;
_gasRefillProvider.endDate = widget.gasRefillModel?.endDate;
_firstTime = false;
setState(() {});
});
@ -217,7 +230,7 @@ class _RequestGasRefillState extends State<RequestGasRefill> {
),
GasStatusMenu(
initialValue: _formModel.status ?? const Lookup(value: 0),
enabled: false,
enabled: widget.gasRefillModel != null,
onSelect: (status) {
_formModel.status = status;
},
@ -232,6 +245,7 @@ class _RequestGasRefillState extends State<RequestGasRefill> {
height: 4,
),
HospitalAutoCompleteField(
enabled: false,
initialValue: _gasRefillProvider.hospital?.name,
// onSave: (value){
// _search.hospital = value;
@ -250,6 +264,8 @@ class _RequestGasRefillState extends State<RequestGasRefill> {
BuildingTypeMenu(
initialValue: _gasRefillProvider?.building,
building: _gasRefillProvider?.hospital?.buildings,
loading: _firstTime,
enabled: widget.gasRefillModel == null,
onSelect: (status) {
_gasRefillProvider.building = status;
setState(() {});
@ -259,6 +275,8 @@ class _RequestGasRefillState extends State<RequestGasRefill> {
FloorTypeMenu(
initialValue: _gasRefillProvider?.floor,
floors: _gasRefillProvider?.building?.floors,
enabled: widget.gasRefillModel == null,
loading: _firstTime,
onSelect: (status) {
_gasRefillProvider.floor = status;
setState(() {});
@ -268,31 +286,54 @@ class _RequestGasRefillState extends State<RequestGasRefill> {
DepartmentTypeMenu(
initialValue: _gasRefillProvider?.department,
departments: _gasRefillProvider?.floor?.departments,
loading: _firstTime,
enabled: widget.gasRefillModel == null,
onSelect: (status) {
_gasRefillProvider.department = status;
setState(() {});
},
),
const SizedBox(height: 8),
if (_userProvider.user?.type == UsersTypes.normal_user)
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
if (widget.gasRefillModel != null) ASubTitle(_subtitle.workingHours),
if (widget.gasRefillModel != null) const SizedBox(height: 8),
if (widget.gasRefillModel != null)
Row(
children: [
const ASubTitle("Expected Date Time"),
SizedBox(
height: 8 * AppStyle.getScaleFactor(context),
),
ADateTimePicker(
date: _gasRefillProvider.expectedDateTime,
from: DateTime.now().subtract(const Duration(days: 365)),
to: DateTime.now().add(const Duration(days: 365)),
onDateTimePicker: (date) {
_gasRefillProvider.expectedDateTime = date;
setState(() {});
},
Expanded(
child: AppTimer(
timer: _gasRefillProvider.timer,
onChange: (timer) async {
_gasRefillProvider.timer = timer;
_formModel.workingHours = num.tryParse((((timer?.durationInSecond ?? 0) / 60) / 60)?.toStringAsFixed(2) ?? "0");
_formModel.startDate = timer.startAt;
_formModel.endDate = timer.endAt;
return true;
},
),
),
],
),
//const SizedBox(height: 8),
// if (_userProvider.user?.type == UsersTypes.normal_user || widget.gasRefillModel != null)
// Column(
// crossAxisAlignment: CrossAxisAlignment.stretch,
// children: [
// const ASubTitle("Expected Date"),
// SizedBox(
// height: 8 * AppStyle.getScaleFactor(context),
// ),
// ADateTimePicker(
// date: _gasRefillProvider.expectedDateTime,
// from: DateTime.now().subtract(const Duration(days: 365)),
// to: DateTime.now().add(const Duration(days: 365)),
// onDateTimePicker: (date) {
// _gasRefillProvider.expectedDateTime = date;
// _formModel.expectedDate = _gasRefillProvider.expectedDateTime;
// setState(() {});
// },
// ),
// ],
// ),
// if (_userProvider.user?.type == UsersTypes.engineer)
// Column(
// children: [
@ -367,7 +408,7 @@ class _RequestGasRefillState extends State<RequestGasRefill> {
const SizedBox(height: 8),
Divider(color: Theme.of(context).colorScheme.primary),
const SizedBox(height: 4),
const ASubTitle("Type"),
const ASubTitle("Gas Type"),
if (_validate && _currentDetails.type == null) ASubTitle(_subtitle.requiredWord, color: Colors.red),
const SizedBox(height: 4),
GasTypeMenu(
@ -395,9 +436,6 @@ class _RequestGasRefillState extends State<RequestGasRefill> {
const SizedBox(
height: 8,
),
const SizedBox(
height: 8,
),
const ASubTitle("Cylinder Type"),
if (_validate && _currentDetails.cylinderSize == null)
ASubTitle(
@ -508,12 +546,12 @@ class _RequestGasRefillState extends State<RequestGasRefill> {
if (widget.gasRefillModel != null)
ESignature(
oldSignature: _formModel.signatureEngineer,
newSignature: _formModel.localNurseSignature,
newSignature: _formModel.localEngineerSignature,
onChange: (signature) {
if (signature == null || signature.isEmpty) {
return;
}
_formModel.localNurseSignature = signature;
_formModel.localEngineerSignature = signature;
_formModel.signatureEngineer = "${DateTime.now().toIso8601String()}.png|${base64Encode(signature)}";
},
),

@ -10,6 +10,8 @@ import 'package:test_sa/views/widgets/buttons/app_back_button.dart';
import 'package:test_sa/views/widgets/gas_refill/gas_refill_list.dart';
import 'package:test_sa/views/widgets/loaders/loading_manager.dart';
import '../../../widgets/switch_button.dart';
class TrackGasRefillPage extends StatefulWidget {
static const String id = "/track-gas-refill";
@ -23,6 +25,7 @@ class _TrackGasRefillPageState extends State<TrackGasRefillPage> with TickerProv
GasRefillProvider _gasRefillProvider;
UserProvider _userProvider;
SettingProvider _settingProvider;
bool mostRecent = true;
@override
Widget build(BuildContext context) {
@ -46,6 +49,7 @@ class _TrackGasRefillPageState extends State<TrackGasRefillPage> with TickerProv
await _gasRefillProvider.getRequests(
user: _userProvider.user,
host: _settingProvider.host,
mostRecent: mostRecent,
);
},
child: Stack(
@ -59,11 +63,11 @@ class _TrackGasRefillPageState extends State<TrackGasRefillPage> with TickerProv
children: [
Row(
children: [
ABackButton(),
const ABackButton(),
Expanded(
child: Center(
child: Text(
_subtitle.serviceRequests,
"Gas Refill Requests",
style: Theme.of(context).textTheme.headline6.copyWith(color: AColors.grey3A, fontStyle: FontStyle.italic),
),
),
@ -76,6 +80,22 @@ class _TrackGasRefillPageState extends State<TrackGasRefillPage> with TickerProv
],
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: ASwitchButton(
title: "Most Recent",
value: mostRecent,
onChange: (value) async {
mostRecent = value;
_gasRefillProvider.reset();
await _gasRefillProvider.getRequests(
user: _userProvider.user,
host: _settingProvider.host,
mostRecent: mostRecent,
);
},
),
),
Expanded(
child: GasRefillList(
nextPage: _gasRefillProvider.nextPage,
@ -83,6 +103,7 @@ class _TrackGasRefillPageState extends State<TrackGasRefillPage> with TickerProv
await _gasRefillProvider.getRequests(
user: _userProvider.user,
host: _settingProvider.host,
mostRecent: mostRecent,
);
},
items: _gasRefillProvider.items,

@ -199,14 +199,14 @@ class _LandPageState extends State<LandPage> {
},
),
LandPageItem(
text: "transfer Device",
text: "Transfer Asset",
icon: FontAwesomeIcons.rightLeft,
onPressed: () {
Navigator.of(context).pushNamed(RequestDeviceTransfer.id);
},
),
LandPageItem(
text: "Track Device Transfer",
text: "Track Asset Transfer",
icon: FontAwesomeIcons.peopleCarryBox,
onPressed: () {
Navigator.of(context).pushNamed(TrackDeviceTransferPage.id);
@ -214,7 +214,7 @@ class _LandPageState extends State<LandPage> {
),
if (_userProvider?.user != null && _userProvider?.user?.type != UsersTypes.normal_user)
LandPageItem(
text: "Search Work Order",
text: "Create Sub Work Order",
svgPath: "assets/images/sub_workorder_icon.svg",
onPressed: () {
Navigator.of(context).pushNamed(SearchSubWorkOrderPage.id);
@ -392,12 +392,12 @@ class _LandPageState extends State<LandPage> {
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Powered By NewTrack",
"Powered By Cloud Solutions",
style: Theme.of(context).textTheme.headline6.copyWith(fontWeight: FontWeight.w500, color: AColors.grey3A, fontSize: 12),
textScaleFactor: AppStyle.getScaleFactor(context),
),
6.width,
Image.asset("assets/images/qr.jpeg", width: 32, height: 32, color: AColors.grey3A)
Image.asset("assets/images/cloud_logo.png", width: 32, height: 32)
],
).paddingOnly(left: 20, right: 20, top: 8, bottom: 8),
],

@ -12,6 +12,7 @@ import 'package:test_sa/views/widgets/loaders/loading_manager.dart';
class NotificationsPage extends StatefulWidget {
static final String id = "/notifications";
@override
_NotificationsPageState createState() => _NotificationsPageState();
}
@ -21,6 +22,7 @@ class _NotificationsPageState extends State<NotificationsPage> with TickerProvid
UserProvider _userProvider;
SettingProvider _settingProvider;
Subtitle _subtitle;
@override
Widget build(BuildContext context) {
_notificationsProvider = Provider.of<NotificationsProvider>(context);

@ -1,11 +1,9 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/api_routes/http_status_manger.dart';
import 'package:test_sa/controllers/localization/localization.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/models/department.dart';
import 'package:test_sa/models/hospital.dart';
import 'package:test_sa/models/subtitle.dart';
import 'package:test_sa/models/user.dart';
@ -14,12 +12,12 @@ import 'package:test_sa/views/app_style/sizing.dart';
import 'package:test_sa/views/widgets/app_text_form_field.dart';
import 'package:test_sa/views/widgets/buttons/app_back_button.dart';
import 'package:test_sa/views/widgets/buttons/app_button.dart';
import 'package:test_sa/views/widgets/departments/department_button.dart';
import 'package:test_sa/views/widgets/hospitals/hospital_button.dart';
import 'package:test_sa/views/widgets/loaders/loading_manager.dart';
class ProfilePage extends StatefulWidget {
static final String id = "/user/profile";
@override
_ProfilePageState createState() => _ProfilePageState();
}
@ -33,6 +31,7 @@ class _ProfilePageState extends State<ProfilePage> {
bool _firstTime = true;
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
@override
Widget build(BuildContext context) {
_userProvider = Provider.of<UserProvider>(context);
@ -119,14 +118,14 @@ class _ProfilePageState extends State<ProfilePage> {
SizedBox(
height: 8,
),
DepartmentButton(
department: Department(name: _user.departmentName, id: _user.departmentId),
onDepartmentPick: (department) {
_user.departmentName = department.name;
_user.departmentId = department.id;
setState(() {});
},
),
// DepartmentButton(
// department: Department(name: _user.departmentName, id: _user.departmentId),
// onDepartmentPick: (department) {
// _user.departmentName = department.name;
// _user.departmentId = department.id;
// setState(() {});
// },
// ),
SizedBox(
height: 8,
),
@ -170,29 +169,29 @@ class _ProfilePageState extends State<ProfilePage> {
child: AButton(
text: _subtitle.update,
onPressed: () async {
if (!_formKey.currentState.validate()) return;
_formKey.currentState.save();
if (_user.departmentId == null) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(_subtitle.unitRequired),
));
return;
}
int status = await _userProvider.updateProfile(
user: _user,
host: _settingProvider.host,
);
if (status >= 200 && status < 300) {
_settingProvider.setUser(_userProvider.user);
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(_subtitle.requestCompleteSuccessfully),
));
} else {
String errorMessage = HttpStatusManger.getStatusMessage(status: status, subtitle: _subtitle);
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(errorMessage),
));
}
// if (!_formKey.currentState.validate()) return;
// _formKey.currentState.save();
// if (_user.departmentId == null) {
// ScaffoldMessenger.of(context).showSnackBar(SnackBar(
// content: Text(_subtitle.unitRequired),
// ));
// return;
// }
// int status = await _userProvider.updateProfile(
// user: _user,
// host: _settingProvider.host,
// );
// if (status >= 200 && status < 300) {
// _settingProvider.setUser(_userProvider.user);
// ScaffoldMessenger.of(context).showSnackBar(SnackBar(
// content: Text(_subtitle.requestCompleteSuccessfully),
// ));
// } else {
// String errorMessage = HttpStatusManger.getStatusMessage(status: status, subtitle: _subtitle);
// ScaffoldMessenger.of(context).showSnackBar(SnackBar(
// content: Text(errorMessage),
// ));
// }
},
),
),

@ -22,6 +22,7 @@ class ReportIssuesPage extends StatefulWidget {
final ServiceRequest serviceRequest;
const ReportIssuesPage({Key key, this.serviceRequest}) : super(key: key);
@override
_ReportIssuesPageState createState() => _ReportIssuesPageState();
}
@ -35,6 +36,7 @@ class _ReportIssuesPageState extends State<ReportIssuesPage> {
UserProvider _userProvider;
SettingProvider _settingProvider;
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
Subtitle _subtitle = AppLocalization.of(context).subtitle;

@ -20,10 +20,12 @@ import 'package:test_sa/views/app_style/colors.dart';
import 'package:test_sa/views/widgets/app_text_form_field.dart';
import 'package:test_sa/views/widgets/buttons/app_back_button.dart';
import 'package:test_sa/views/widgets/buttons/app_button.dart';
import 'package:test_sa/views/widgets/date_and_time/time_picker.dart';
import 'package:test_sa/views/widgets/equipment/device_button.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/sound/record_sound.dart';
import 'package:test_sa/views/widgets/sound/sound_player.dart';
import 'package:test_sa/views/widgets/speech_to_text/speech_to_text.dart';
import 'package:test_sa/views/widgets/status/service_request/service_request_defect_types_mune.dart';
import 'package:test_sa/views/widgets/status/service_request/service_request_priority_mune.dart';
@ -31,6 +33,9 @@ import 'package:test_sa/views/widgets/status/service_request/service_request_thr
import 'package:test_sa/views/widgets/status/service_request/service_request_types_mune.dart';
import 'package:test_sa/views/widgets/titles/app_sub_title.dart';
import '../../../../controllers/providers/api/status_drop_down/service_reqest/service_request_through_provider.dart';
import '../../../../controllers/providers/api/status_drop_down/service_reqest/service_request_type_provider.dart';
import '../../../app_style/sizing.dart';
import '../../../widgets/date_and_time/date_picker.dart';
import '../../../widgets/status/service_request/service_request_first_action.dart';
import '../../../widgets/status/service_request/service_request_loan_availability.dart';
@ -38,6 +43,7 @@ import '../../../widgets/status/service_request/service_request_loan_availabilit
class CreateRequestPage extends StatefulWidget {
static const String id = "/create-request";
final ServiceRequest serviceRequest;
const CreateRequestPage({this.serviceRequest, Key key}) : super(key: key);
@override
@ -57,9 +63,11 @@ class CreateRequestPageState extends State<CreateRequestPage> {
Subtitle _subtitle;
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
TextEditingController _maintenanceController, _commentController;
TextEditingController _maintenanceController, _commentController, _reviewCommentController;
DateTime _dateTime;
bool isFirstActionSubmitted = false;
@override
void initState() {
_maintenanceController = TextEditingController();
@ -69,12 +77,36 @@ class CreateRequestPageState extends State<CreateRequestPage> {
_device = _serviceRequest.device;
_deviceImages.addAll(_serviceRequest.devicePhotos.map((e) => File(e)).toList());
_showDatePicker = _serviceRequest.firstAction != null && _serviceRequest.firstAction.name == "Need a visit";
if (_showDatePicker && _serviceRequest.visitDate != null) {
_dateTime = DateTime.tryParse(_serviceRequest.visitDate);
}
} else {
_serviceRequest = ServiceRequest();
}
isFirstActionSubmitted = _serviceRequest?.firstAction != null;
super.initState();
}
//
// getServiceRequestById(String id) async {
// try {
// ServiceRequest request = await _serviceRequestsProvider.getServiceRequestObjectById(requestId: id) ?? "";
// _serviceRequest = request;
// _device = _serviceRequest.device;
// _deviceImages.addAll(_serviceRequest.devicePhotos.map((e) {
// return File(e);
// }).toList());
// _showDatePicker = _serviceRequest.firstAction != null && _serviceRequest.firstAction.name == "Need a visit";
// if (_showDatePicker && _serviceRequest.visitDate != null) {
// _dateTime = DateTime.tryParse(_serviceRequest.visitDate);
// }
// _isLoading = false;
// } catch (ex) {
// _isLoading = false;
// }
// setState(() {});
// }
@override
void dispose() {
_maintenanceController.dispose();
@ -82,13 +114,19 @@ class CreateRequestPageState extends State<CreateRequestPage> {
super.dispose();
}
bool _isLocalUrl(String url) {
if (url?.isEmpty != false) return false;
return url.startsWith("/") || url.startsWith("file://") || url.substring(1).startsWith(':\\');
}
@override
Widget build(BuildContext context) {
_height = MediaQuery.of(context).size.height;
_userProvider = Provider.of<UserProvider>(context);
_settingProvider = Provider.of<SettingProvider>(context);
_serviceRequestsProvider = Provider.of<ServiceRequestsProvider>(context);
_subtitle = AppLocalization.of(context).subtitle;
_serviceRequestsProvider = Provider.of<ServiceRequestsProvider>(context);
return Scaffold(
key: _scaffoldKey,
body: SafeArea(
@ -135,14 +173,39 @@ class CreateRequestPageState extends State<CreateRequestPage> {
style: Theme.of(context).textTheme.subtitle1,
),
12.height,
_userProvider.user.departmentId == null
_userProvider.user.departmentId == null || (_userProvider.user?.departmentId?.isEmpty ?? false)
? const SizedBox.shrink()
: ATextFormField(
enable: false,
initialValue: _userProvider.user.departmentName ?? _subtitle.noUniteFound,
hintText: _subtitle.unite,
prefixIconData: FontAwesomeIcons.hospitalUser,
style: Theme.of(context).textTheme.subtitle1,
: Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: const Color(0xfff5f5f5),
border: Border.all(
color: const Color(0xffefefef),
),
borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: _userProvider.user.departmentName
?.map(
(e) => Text(
e?.trim() ?? "",
style: Theme.of(context).textTheme.titleMedium.copyWith(color: AColors.black),
),
)
?.toList() ??
[],
),
Icon(
FontAwesomeIcons.hospitalUser,
size: 20 * AppStyle.getScaleFactor(context),
color: const Color(0xff2e303a),
),
],
),
),
12.height,
DeviceButton(
@ -160,15 +223,16 @@ class CreateRequestPageState extends State<CreateRequestPage> {
height: 4,
),
ServiceRequestPriorityMenu(
initialValue: _serviceRequest.priority,
initialValue: widget.serviceRequest?.priority,
onSelect: (status) {
_serviceRequest.priority = status;
},
enabled: widget.serviceRequest == null ? true : false,
),
const SizedBox(
height: 8,
),
const ASubTitle("Defect Type"),
const ASubTitle("Equipment Status"),
const SizedBox(
height: 4,
),
@ -177,12 +241,13 @@ class CreateRequestPageState extends State<CreateRequestPage> {
onSelect: (status) {
_serviceRequest.defectType = status;
},
enabled: widget.serviceRequest == null ? true : false,
),
12.height,
const SizedBox(
height: 8,
),
const ASubTitle("Type"),
const ASubTitle("Type of Request"),
const SizedBox(
height: 4,
),
@ -191,6 +256,8 @@ class CreateRequestPageState extends State<CreateRequestPage> {
onSelect: (status) {
_serviceRequest.type = status;
},
enabled: false,
withDefaultItem: widget.serviceRequest == null,
),
const SizedBox(
height: 8,
@ -201,9 +268,7 @@ class CreateRequestPageState extends State<CreateRequestPage> {
),
ServiceRequestedThroughMenu(
initialValue: _serviceRequest.requestedThrough,
onSelect: (status) {
_serviceRequest.requestedThrough = status;
},
enabled: false,
),
if (widget.serviceRequest != null) 12.height,
if (widget.serviceRequest != null) const ASubTitle("First Action"),
@ -213,6 +278,7 @@ class CreateRequestPageState extends State<CreateRequestPage> {
if (widget.serviceRequest != null)
ServiceRequestedFirstAction(
initialValue: _serviceRequest.firstAction,
enabled: !isFirstActionSubmitted,
onSelect: (status) {
_dateTime = null;
_serviceRequest.firstAction = status;
@ -222,10 +288,11 @@ class CreateRequestPageState extends State<CreateRequestPage> {
),
if (_showDatePicker) 12.height,
if (_showDatePicker)
ADatePicker(
ADateTimePicker(
date: _dateTime,
enable: !isFirstActionSubmitted,
from: DateTime.now(),
onDatePicker: (date) {
onDateTimePicker: (date) {
_dateTime = date;
setState(() {});
},
@ -249,7 +316,7 @@ class CreateRequestPageState extends State<CreateRequestPage> {
),
if (widget.serviceRequest != null)
ATextFormField(
controller: _commentController,
controller: _reviewCommentController,
initialValue: _serviceRequest.reviewComment,
hintText: _subtitle.comment,
style: Theme.of(context).textTheme.titleMedium,
@ -257,14 +324,19 @@ class CreateRequestPageState extends State<CreateRequestPage> {
onSaved: (value) {
_serviceRequest.reviewComment = value;
},
enable: widget.serviceRequest != null ? false : true,
),
12.height,
MultiImagesPicker(
label: _subtitle.deviceImages,
images: _deviceImages,
MultiFilesPicker(
label: _subtitle.deviceFiles,
files: _deviceImages,
enabled: widget.serviceRequest == null ? true : false,
),
12.height,
SpeechToTextButton(controller: _maintenanceController),
SpeechToTextButton(
controller: _maintenanceController,
enabled: widget.serviceRequest == null ? true : false,
),
12.height,
ATextFormField(
controller: _maintenanceController,
@ -273,15 +345,24 @@ class CreateRequestPageState extends State<CreateRequestPage> {
prefixIconData: FontAwesomeIcons.triangleExclamation,
style: Theme.of(context).textTheme.titleLarge,
textInputType: TextInputType.multiline,
validator: (value) => Validator.hasValue(value) ? null : _subtitle.maintenanceIssueRequired,
validator: (value) => widget.serviceRequest != null || Validator.hasValue(value) ? null : _subtitle.maintenanceIssueRequired,
onSaved: (value) {
_serviceRequest.callComments = value;
},
enable: widget.serviceRequest == null ? true : false,
),
12.height,
RecordSound(onRecord: (audio) {
_serviceRequest.audio = audio;
}),
if (_serviceRequest.audio?.isNotEmpty == true)
ASoundPlayer(
audio: _serviceRequest.audio,
)
else
RecordSound(
onRecord: (audio) {
_serviceRequest.audio = audio;
},
enabled: widget.serviceRequest == null ? true : false,
),
12.height,
if (widget.serviceRequest != null)
ATextFormField(
@ -307,7 +388,7 @@ class CreateRequestPageState extends State<CreateRequestPage> {
return;
}
if (_serviceRequest.firstAction?.name == "Need a visit" && _dateTime == null) {
Fluttertoast.showToast(msg: _subtitle.noDateFound);
Fluttertoast.showToast(msg: "first action is required");
return;
}
if (widget.serviceRequest != null && (_serviceRequest?.engineerId == null || (_serviceRequest?.engineerId?.isEmpty ?? false))) {
@ -316,12 +397,18 @@ class CreateRequestPageState extends State<CreateRequestPage> {
}
_formKey.currentState.save();
_serviceRequest.deviceId = _device?.id;
if (widget.serviceRequest == null) {
_serviceRequest.type = Provider.of<ServiceRequestTypeProvider>(context, listen: false).getDefaultItem();
}
_serviceRequest.requestedThrough = Provider.of<ServiceRequestedThroughProvider>(context, listen: false).getDefaultItem();
_isLoading = true;
setState(() {});
_serviceRequest.devicePhotos = _deviceImages.map((e) => "${e.path.split("/").last}|${base64Encode(e.readAsBytesSync())}").toList();
_serviceRequest.devicePhotos = _deviceImages.map((e) => _isLocalUrl(e.path) ? "${e.path.split("/").last}|${base64Encode(e.readAsBytesSync())}" : e.path).toList();
if (_serviceRequest.audio != null) {
final file = File(_serviceRequest.audio);
_serviceRequest.audio = "${file.path.split("/").last}|${base64Encode(file.readAsBytesSync())}";
if (_isLocalUrl(_serviceRequest.audio)) {
final File file = File(_serviceRequest.audio);
_serviceRequest.audio = "${file.path.split("/").last}|${base64Encode(file.readAsBytesSync())}";
}
}
int status = 0;
if (widget.serviceRequest == null) {

@ -20,6 +20,7 @@ class FutureRequestServiceDetails extends StatefulWidget {
class _FutureRequestServiceDetailsState extends State<FutureRequestServiceDetails> {
UserProvider _userProvider;
SettingProvider _settingProvider;
@override
Widget build(BuildContext context) {
_userProvider = Provider.of<UserProvider>(context);

@ -22,10 +22,8 @@ import 'package:test_sa/views/app_style/sizing.dart';
import 'package:test_sa/views/widgets/app_text_form_field.dart';
import 'package:test_sa/views/widgets/buttons/app_back_button.dart';
import 'package:test_sa/views/widgets/buttons/app_button.dart';
import 'package:test_sa/views/widgets/date_and_time/date_picker.dart';
import 'package:test_sa/views/widgets/e_signature/e_signature.dart';
import 'package:test_sa/views/widgets/equipment/auto_complete_devices_field.dart';
import 'package:test_sa/views/widgets/images/mini_one_image_picker.dart';
import 'package:test_sa/views/widgets/loaders/loading_manager.dart';
import 'package:test_sa/views/widgets/parts/auto_complete_parts_field.dart';
import 'package:test_sa/views/widgets/parts/part_item.dart';
@ -35,6 +33,8 @@ import 'package:test_sa/views/widgets/status/report/service_report_reasons.dart'
import 'package:test_sa/views/widgets/titles/app_sub_title.dart';
import '../../../../../controllers/providers/api/status_drop_down/report/service_types_provider.dart';
import '../../../../widgets/date_and_time/date_picker.dart';
import '../../../../widgets/images/multi_image_picker.dart';
import '../../../../widgets/status/report/service_report_fault_description.dart';
import '../../../../widgets/status/report/service_report_repair_location.dart';
import '../../../../widgets/timer/app_timer.dart';
@ -60,7 +60,7 @@ class _CreateServiceReportState extends State<CreateServiceReport> with TickerPr
bool _showCommentField = false;
Subtitle _subtitle;
File _image;
final List<File> _files = [];
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
final TextEditingController _faultController = TextEditingController();
@ -69,7 +69,7 @@ class _CreateServiceReportState extends State<CreateServiceReport> with TickerPr
@override
void initState() {
_serviceReport = ServiceReport(
visitDate: DateTime.now(),
returnToService: DateTime.now(),
//type: const Lookup(value: 2),
device: widget.request.device,
parts: [],
@ -155,12 +155,17 @@ class _CreateServiceReportState extends State<CreateServiceReport> with TickerPr
)
]),
child: Wrap(
direction: Axis.vertical,
spacing: 10,
children: [
ASubTitle(
"${_subtitle.callId}: ${widget.request.requestCode}",
font: 14,
),
ASubTitle(
"${_subtitle.assetNumber}: ${widget.request.deviceNumber}",
font: 14,
),
widget.request.deviceSerialNumber == null
? const SizedBox()
: ASubTitle(
@ -195,63 +200,6 @@ class _CreateServiceReportState extends State<CreateServiceReport> with TickerPr
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Report type and Reasons
Row(
children: [
// Report Status
// Expanded(
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// ASubTitle(_subtitle.reportType),
// _validate && _serviceReport.type == null ?
// ASubTitle(_subtitle.requiredWord,color: Colors.red,):
// const SizedBox.shrink(),
// const SizedBox(height: 4,),
// ServiceReportTypeMenu(
// initialValue: _serviceReport.type,
// onSelect: (status){
// _serviceReport.type = status;
// },
// ),
// ],
// ),
// ),
// const SizedBox(width: 8,),
// visit date
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ASubTitle(_subtitle.visitDate),
_validate && _serviceReport.visitDate == null
? ASubTitle(
_subtitle.requiredWord,
color: Colors.red,
)
: const SizedBox.shrink(),
Row(
children: [
Expanded(
child: ADatePicker(
date: _serviceReport.visitDate,
from: DateTime.now().subtract(const Duration(days: 365)),
to: DateTime.now().add(const Duration(days: 365)),
onDatePicker: (date) {
_serviceReport.visitDate = date;
setState(() {});
},
),
),
],
),
],
),
),
],
),
const SizedBox(
height: 8,
),
// device sn
Visibility(
visible: widget.request.deviceSerialNumber == null,
@ -281,7 +229,7 @@ class _CreateServiceReportState extends State<CreateServiceReport> with TickerPr
const SizedBox(
height: 8,
),
ASubTitle(_subtitle.assetType ??""),
ASubTitle(_subtitle.assetType ?? ""),
_validate && _serviceReport.assetType == null
? ASubTitle(
_subtitle.requiredWord,
@ -415,6 +363,63 @@ class _CreateServiceReportState extends State<CreateServiceReport> with TickerPr
SizedBox(
height: 8 * AppStyle.getScaleFactor(context),
),
Row(
children: [
// Report Status
// Expanded(
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// ASubTitle(_subtitle.reportType),
// _validate && _serviceReport.type == null ?
// ASubTitle(_subtitle.requiredWord,color: Colors.red,):
// const SizedBox.shrink(),
// const SizedBox(height: 4,),
// ServiceReportTypeMenu(
// initialValue: _serviceReport.type,
// onSelect: (status){
// _serviceReport.type = status;
// },
// ),
// ],
// ),
// ),
// const SizedBox(width: 8,),
// visit date
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const ASubTitle("Return to Service"),
// _validate && _serviceReport.returnToService == null
// ? ASubTitle(
// _subtitle.requiredWord,
// color: Colors.red,
// )
// : const SizedBox.shrink(),
Row(
children: [
Expanded(
child: ADatePicker(
date: _serviceReport.returnToService,
from: DateTime.now().subtract(const Duration(days: 365)),
to: DateTime.now().add(const Duration(days: 365)),
onDatePicker: (date) {
_serviceReport.returnToService = date;
setState(() {});
},
),
),
],
),
],
),
),
],
),
const SizedBox(
height: 8,
),
ASubTitle(_subtitle.workingHours),
const SizedBox(height: 8),
Row(
@ -541,8 +546,10 @@ class _CreateServiceReportState extends State<CreateServiceReport> with TickerPr
requestId: widget.request?.id,
initialValue: _serviceReport.faultDescription,
onSelect: (status) {
_serviceReport.faultDescription = status;
setState(() {});
if (status != null) {
_serviceReport.faultDescription = status;
setState(() {});
}
},
),
const SizedBox(
@ -564,7 +571,7 @@ class _CreateServiceReportState extends State<CreateServiceReport> with TickerPr
),
Row(
children: [
ASubTitle(_subtitle.workPreformed),
const ASubTitle("Solutions"),
// Expanded(
// child: SizedBox(
// height: 32 * AppStyle.getScaleFactor(context),
@ -604,7 +611,7 @@ class _CreateServiceReportState extends State<CreateServiceReport> with TickerPr
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ASubTitle(_subtitle.reasons),
const ASubTitle("Failure Reason"),
_validate && _serviceReport.reason?.id == null
? ASubTitle(
_subtitle.requiredWord,
@ -622,25 +629,27 @@ class _CreateServiceReportState extends State<CreateServiceReport> with TickerPr
),
),
const SizedBox(width: 8),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ASubTitle(_subtitle.attachImage),
AMiniOneImagePicker(
//error: _validate && _serviceReport.image == null,
image: _image,
onPick: (image) {
_image = image;
_serviceReport.image = "${image.path.split("/").last}|${base64Encode(image.readAsBytesSync())}";
},
),
],
),
),
// Expanded(
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// const ASubTitle("Attachments"),
// AMiniOneFilePicker(
// //error: _validate && _serviceReport.image == null,
// file: _file,
// onPick: (file) {
// _file = file;
// _serviceReport.files[0] = "${file.path.split("/").last}|${base64Encode(file.readAsBytesSync())}";
// },
// ),
// ],
// ),
// ),
],
),
const SizedBox(height: 8),
MultiFilesPicker(label: "Attachments", files: _files),
const SizedBox(height: 8),
ASubTitle(_subtitle.repairLocation),
const SizedBox(height: 4),
ServiceReportRepairLocation(
@ -650,7 +659,7 @@ class _CreateServiceReportState extends State<CreateServiceReport> with TickerPr
},
),
const SizedBox(height: 16),
ASubTitle(_subtitle.travelingExpense),
const ASubTitle("Travel Expenses"),
const SizedBox(
height: 4,
),
@ -786,7 +795,7 @@ class _CreateServiceReportState extends State<CreateServiceReport> with TickerPr
// ),
const SizedBox(height: 8),
ASubTitle(_subtitle.comment),
const ASubTitle("Technical comment"),
const SizedBox(height: 4),
ATextFormField(
initialValue: _serviceReport?.comment,
@ -853,7 +862,7 @@ class _CreateServiceReportState extends State<CreateServiceReport> with TickerPr
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ASubTitle(_subtitle.partNumber),
ASubTitle(_subtitle.partNumberName),
_validate && _serviceReport.parts == null
? ASubTitle(
_subtitle.requiredWord,
@ -864,6 +873,7 @@ class _CreateServiceReportState extends State<CreateServiceReport> with TickerPr
height: 4,
),
AutoCompletePartsField(
assetId: _serviceReport?.device?.id,
onPick: (part) {
_serviceReport.parts.add(part);
},
@ -918,15 +928,16 @@ class _CreateServiceReportState extends State<CreateServiceReport> with TickerPr
_isLoading = true;
setState(() {});
_serviceReport.files ??= [];
for (var file in _files) {
_serviceReport.files.add("${file.path.split("/").last}|${base64Encode(file.readAsBytesSync())}");
}
int status = await _serviceRequestsProvider.createServiceReport(
user: _userProvider.user,
host: _settingProvider.host,
report: _serviceReport,
request: widget.request,
);
print(6);
print(status);
_isLoading = false;
setState(() {});
if (status >= 200 && status < 300) {

@ -26,7 +26,6 @@ import 'package:test_sa/views/widgets/buttons/app_button.dart';
import 'package:test_sa/views/widgets/date_and_time/date_picker.dart';
import 'package:test_sa/views/widgets/e_signature/e_signature.dart';
import 'package:test_sa/views/widgets/equipment/auto_complete_devices_field.dart';
import 'package:test_sa/views/widgets/images/mini_one_image_picker.dart';
import 'package:test_sa/views/widgets/loaders/loading_manager.dart';
import 'package:test_sa/views/widgets/parts/auto_complete_parts_field.dart';
import 'package:test_sa/views/widgets/parts/part_item.dart';
@ -38,6 +37,8 @@ import 'package:test_sa/views/widgets/status/report/service_report_repair_locati
import 'package:test_sa/views/widgets/timer/app_timer.dart';
import 'package:test_sa/views/widgets/titles/app_sub_title.dart';
import '../../../../widgets/images/multi_image_picker.dart';
class EditServiceReport extends StatefulWidget {
static final String id = "/edit-service-report";
final ServiceRequest request;
@ -60,7 +61,7 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
bool _showCommentField = false;
Subtitle _subtitle;
File _image;
List<File> _images = [];
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
TextEditingController _faultController = TextEditingController();
@ -73,6 +74,7 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
@override
void initState() {
_serviceReport = widget.report;
_images = widget.report?.files?.map((e) => File(e))?.toList();
super.initState();
}
@ -149,12 +151,17 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
)
]),
child: Wrap(
direction: Axis.vertical,
spacing: 10,
children: [
ASubTitle(
"${_subtitle.callId}: ${widget.request.requestCode}",
font: 14,
),
ASubTitle(
"${_subtitle.assetNumber}: ${widget.request.deviceNumber}",
font: 14,
),
widget.request.deviceSerialNumber == null
? const SizedBox()
: ASubTitle(
@ -179,8 +186,8 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
width: double.infinity,
padding: const EdgeInsets.all(16),
margin: const EdgeInsets.symmetric(vertical: 16),
decoration: BoxDecoration(color: AColors.grey, borderRadius: BorderRadius.circular(AppStyle.getBorderRadius(context)), boxShadow: [
const BoxShadow(
decoration: BoxDecoration(color: AColors.grey, borderRadius: BorderRadius.circular(AppStyle.getBorderRadius(context)), boxShadow: const [
BoxShadow(
color: AColors.grey,
offset: Offset(0, -1),
)
@ -189,70 +196,70 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Report type and Reasons
Row(
children: [
// Report Status
// Expanded(
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// ASubTitle(_subtitle.reportType),
// _validate && _serviceReport.type == null
// ? ASubTitle(
// _subtitle.requiredWord,
// color: Colors.red,
// )
// : const SizedBox.shrink(),
// const SizedBox(
// height: 4,
// ),
// ServiceReportTypeMenu(
// initialValue: _serviceReport.type,
// onSelect: (status) {
// _serviceReport.type = status;
// },
// ),
// ],
// ),
// ),
// const SizedBox(
// width: 8,
// ),
// visit date
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ASubTitle(_subtitle.visitDate),
_validate && _serviceReport.visitDate == null
? ASubTitle(
_subtitle.requiredWord,
color: Colors.red,
)
: const SizedBox.shrink(),
Row(
children: [
Expanded(
child: ADatePicker(
date: _serviceReport.visitDate,
from: DateTime.now().subtract(const Duration(days: 365)),
to: DateTime.now().add(const Duration(days: 365)),
onDatePicker: (date) {
_serviceReport.visitDate = date;
setState(() {});
},
),
),
],
),
],
),
),
],
),
const SizedBox(
height: 8,
),
// Row(
// children: [
// // Report Status
// // Expanded(
// // child: Column(
// // crossAxisAlignment: CrossAxisAlignment.start,
// // children: [
// // ASubTitle(_subtitle.reportType),
// // _validate && _serviceReport.type == null
// // ? ASubTitle(
// // _subtitle.requiredWord,
// // color: Colors.red,
// // )
// // : const SizedBox.shrink(),
// // const SizedBox(
// // height: 4,
// // ),
// // ServiceReportTypeMenu(
// // initialValue: _serviceReport.type,
// // onSelect: (status) {
// // _serviceReport.type = status;
// // },
// // ),
// // ],
// // ),
// // ),
// // const SizedBox(
// // width: 8,
// // ),
// // visit date
// Expanded(
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// ASubTitle(_subtitle.visitDate),
// _validate && _serviceReport.visitDate == null
// ? ASubTitle(
// _subtitle.requiredWord,
// color: Colors.red,
// )
// : const SizedBox.shrink(),
// Row(
// children: [
// Expanded(
// child: ADatePicker(
// date: _serviceReport.visitDate,
// from: DateTime.now().subtract(const Duration(days: 365)),
// to: DateTime.now().add(const Duration(days: 365)),
// onDatePicker: (date) {
// _serviceReport.visitDate = date;
// setState(() {});
// },
// ),
// ),
// ],
// ),
// ],
// ),
// ),
// ],
// ),
// const SizedBox(
// height: 8,
// ),
// device sn
Visibility(
visible: widget.request.deviceSerialNumber == null,
@ -380,6 +387,7 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
setState(() {});
} else {
_serviceReport.callLastSituation = status;
setState(() {});
}
},
),
@ -390,6 +398,56 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
),
],
),
const SizedBox(
height: 8,
),
const ASubTitle("Return to Service"),
Row(
children: [
Expanded(
child: ADatePicker(
date: _serviceReport.returnToService,
from: DateTime.now().subtract(const Duration(days: 365)),
to: DateTime.now().add(const Duration(days: 365)),
onDatePicker: (date) {
_serviceReport.returnToService = date;
setState(() {});
},
),
),
],
),
if (_serviceReport?.callLastSituation?.value == 2)
Column(
children: [
const SizedBox(
height: 8,
),
ATextFormField(
initialValue: _serviceReport?.reviewComment,
hintText: "Vendor Name",
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.titleMedium,
textInputType: TextInputType.multiline,
onSaved: (value) {
_serviceReport.reviewComment = value;
},
),
const SizedBox(
height: 8,
),
ATextFormField(
initialValue: _serviceReport?.reviewComment,
hintText: "Vendor Engineer",
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.titleMedium,
textInputType: TextInputType.multiline,
onSaved: (value) {
_serviceReport.reviewComment = value;
},
),
],
),
if (_showCommentField)
const SizedBox(
height: 8,
@ -658,13 +716,14 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
requestId: widget.request?.id,
initialValue: _serviceReport.faultDescription,
onSelect: (status) {
print("faluttt:${status?.toJson()}");
_serviceReport.faultDescription = status;
if (mounted) setState(() {});
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
if (mounted) setState(() {});
});
},
),
const SizedBox(height: 8),
ASubTitle(_subtitle.workPreformed),
const ASubTitle("Solutions"),
const SizedBox(height: 4),
ATextFormField(
initialValue: _serviceReport?.workPreformed,
@ -680,50 +739,38 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
},
),
const SizedBox(height: 4),
Row(
children: [
// reasons
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ASubTitle(_subtitle.reasons),
const SizedBox(
height: 4,
),
ServiceReportReasonsMenu(
initialValue: _serviceReport.reason,
onSelect: (status) {
_serviceReport.reason = status;
},
),
],
),
),
const SizedBox(
width: 8,
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ASubTitle(_subtitle.attachImage),
AMiniOneImagePicker(
//error: _validate && _serviceReport.image == null,
image: _image,
onPick: (image) {
_image = image;
_serviceReport.image = base64Encode(image.readAsBytesSync());
},
),
],
),
),
],
ASubTitle("Failure Reason"),
const SizedBox(
height: 4,
),
ServiceReportReasonsMenu(
initialValue: _serviceReport.reason,
onSelect: (status) {
_serviceReport.reason = status;
},
),
const SizedBox(
height: 8,
),
ASubTitle(_subtitle.attachImage),
const SizedBox(
height: 4,
),
MultiFilesPicker(
label: "",
files: _images,
),
// AMiniOneImagePicker(
// //error: _validate && _serviceReport.image == null,
// image: _image,
// onPick: (image) {
// _image = image;
// _serviceReport.image = base64Encode(image.readAsBytesSync());
// },
// ),
const SizedBox(
height: 8,
),
const SizedBox(height: 8),
ASubTitle(_subtitle.repairLocation),
const SizedBox(height: 4),
@ -734,7 +781,7 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
},
),
const SizedBox(height: 16),
ASubTitle(_subtitle.travelingExpense),
ASubTitle("Travel Expenses"),
const SizedBox(
height: 4,
),
@ -746,9 +793,9 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
textInputType: TextInputType.number,
onSaved: (value) {
if (value != null && value.isEmpty) {
_serviceReport.travelingExpense = int.tryParse(_serviceReport?.travelingExpense?.toString() ?? "") ?? 0;
_serviceReport.travelingExpense = num.tryParse(_serviceReport?.travelingExpense?.toString() ?? "") ?? 0;
} else
_serviceReport.travelingExpense = int.tryParse(value) ?? 0;
_serviceReport.travelingExpense = num.tryParse(value) ?? 0;
},
),
@ -885,7 +932,7 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
//const SizedBox(height: 8,),
const SizedBox(height: 8),
ASubTitle(_subtitle.comment),
const ASubTitle("Technical comment"),
const SizedBox(height: 4),
ATextFormField(
initialValue: _serviceReport?.comment,
@ -955,7 +1002,7 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ASubTitle(_subtitle.partNumber),
ASubTitle(_subtitle.partNumberName),
_validate && _serviceReport.parts == null
? ASubTitle(
_subtitle.requiredWord,
@ -966,6 +1013,7 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
height: 4,
),
AutoCompletePartsField(
assetId: _serviceReport?.device?.id,
onPick: (part) {
_serviceReport.parts.add(part);
setState(() {});
@ -1011,7 +1059,6 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
return;
}
_validate = true;
print("jere1245");
// if (!_formKey.currentState.validate()) {
// setState(() {});
// return;
@ -1026,7 +1073,7 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
_isLoading = true;
setState(() {});
_serviceReport.files = _images.map((e) => _isLocalUrl(e.path) ? "${e.path.split("/").last}|${base64Encode(e.readAsBytesSync())}" : e.path).toList();
int status = await _serviceRequestsProvider.updateServiceReport(user: _userProvider.user, host: _settingProvider.host, report: _serviceReport, request: widget.request);
_isLoading = false;
setState(() {});
@ -1054,4 +1101,9 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
),
);
}
bool _isLocalUrl(String url) {
if (url?.isEmpty != false) return false;
return url.startsWith("/") || url.startsWith("file://") || url.substring(1).startsWith(':\\');
}
}

@ -26,30 +26,32 @@ class FutureServiceReport extends StatefulWidget {
class _FutureServiceReportState extends State<FutureServiceReport> {
UserProvider _userProvider;
SettingProvider _settingProvider;
@override
Widget build(BuildContext context) {
_userProvider = Provider.of<UserProvider>(context);
_settingProvider = Provider.of<SettingProvider>(context);
Subtitle _subtitle = AppLocalization.of(context).subtitle;
ServiceRequestsProvider().getSingleServiceReport(reportId: widget.workOrder.id, user: _userProvider.user, host: _settingProvider.host, subtitle: _subtitle);
Subtitle subtitle = AppLocalization.of(context).subtitle;
ServiceRequestsProvider().getSingleServiceReport(reportId: widget.workOrder.id, user: _userProvider.user, host: _settingProvider.host, subtitle: subtitle);
return Scaffold(
body: FutureBuilder<ServiceReport>(
future: ServiceRequestsProvider().getSingleServiceReport(reportId: widget.workOrder.id, user: _userProvider.user, host: _settingProvider.host, subtitle: _subtitle),
future: ServiceRequestsProvider().getSingleServiceReport(reportId: widget.workOrder.id, user: _userProvider.user, host: _settingProvider.host, subtitle: subtitle),
builder: (BuildContext context, AsyncSnapshot<ServiceReport> snapshot) {
if (snapshot.hasError)
if (snapshot.hasError) {
return FailedLoading(
message: snapshot.error.toString(),
onReload: () {
setState(() {});
},
);
if (snapshot.hasData) {
}
if (snapshot.connectionState == ConnectionState.done) {
return EditServiceReport(
report: snapshot.data,
request: widget.request,
);
}
return Center(child: ALoading());
return const Center(child: ALoading());
},
),
);

@ -6,6 +6,7 @@ import 'package:test_sa/controllers/providers/api/service_requests_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/int_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/enums/user_types.dart';
import 'package:test_sa/models/service_request/service_request.dart';
import 'package:test_sa/models/subtitle.dart';
@ -16,7 +17,9 @@ import 'package:test_sa/views/pages/user/requests/report/create_service_report.d
import 'package:test_sa/views/widgets/buttons/app_back_button.dart';
import 'package:test_sa/views/widgets/buttons/app_button.dart';
import 'package:test_sa/views/widgets/buttons/app_icon_button.dart';
import 'package:test_sa/views/widgets/images/files_list.dart';
import 'package:test_sa/views/widgets/images/images_list.dart';
import 'package:test_sa/views/widgets/loaders/app_loading.dart';
import 'package:test_sa/views/widgets/loaders/image_loader.dart';
import 'package:test_sa/views/widgets/requests/info_row.dart';
import 'package:test_sa/views/widgets/requests/request_status.dart';
@ -27,10 +30,10 @@ import '../../../../models/service_request/search_work_order.dart';
import 'report/future_service_report.dart';
class RequestDetailsPage extends StatelessWidget {
static final String id = "/call-details";
final ServiceRequest serviceRequest;
static const String id = "/call-details";
ServiceRequest serviceRequest;
const RequestDetailsPage({Key key, this.serviceRequest}) : super(key: key);
RequestDetailsPage({Key key, this.serviceRequest}) : super(key: key);
@override
Widget build(BuildContext context) {
@ -39,404 +42,431 @@ class RequestDetailsPage extends StatelessWidget {
SettingProvider _settingProvider = Provider.of<SettingProvider>(context);
List<SearchWorkOrder> workOrders = [];
ServiceRequestsProvider _serviceRequestsProvider = Provider.of<ServiceRequestsProvider>(context);
_serviceRequestsProvider.getServiceRequestObjectById(requestId: serviceRequest.id);
return DefaultTabController(
length: 2,
child: Scaffold(
body: SafeArea(
child: Column(
children: [
Container(
color: AColors.primaryColor,
padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 4),
child: Row(
children: [
ABackButton(),
Expanded(
child: Center(
child: Text(
_subtitle.details,
style: Theme.of(context).textTheme.headline6.copyWith(color: AColors.white, fontStyle: FontStyle.italic),
),
),
),
_userProvider.user.type == UsersTypes.normal_user
?
// AIconButton(
// iconData: Icons.warning_amber_rounded,
// color: AColors.white,
// buttonSize: 42,
// backgroundColor: AColors.deepOrange,
// onPressed: (){
// Navigator.of(context).push(
// MaterialPageRoute(
// builder: (_) => ReportIssuesPage(serviceRequest: serviceRequest,)
// )
// );
// },
// )
const SizedBox(
width: 48,
)
: AIconButton(
iconData: Icons.edit,
color: AColors.white,
buttonSize: 42,
backgroundColor: AColors.green,
onPressed: () async {
Navigator.of(context).push(
MaterialPageRoute(builder: (_) => CreateRequestPage(serviceRequest: serviceRequest)),
);
// showModalBottomSheet(
// context: context,
// builder: (context) {
// return ServiceRequestsUpdateDialog(
// request: serviceRequest,
// );
// });
// DateTime picked = await showDatePicker(
// context: context,
// initialDate: DateTime.now(),
// firstDate: DateTime.now(),
// lastDate: DateTime.now().add(Duration(days: 182))
// );
// if(picked == null){return;}
// showDialog<void>(
// context: context,
// barrierDismissible: false,
// builder: (BuildContext context) {
// return CupertinoAlertDialog(
// title: Text(_subtitle.updatingDots),
// content: Center(child: CircularProgressIndicator()),
// );
// },
// );
// int status = await _serviceRequestsProvider.updateDate(
// user: _userProvider.user,
// host: _settingProvider.host,
// request: serviceRequest,
// newDate: picked.toString().split(" ").first
// );
// Navigator.of(context).pop();
// Fluttertoast.showToast(
// msg: HttpStatusManger.getStatusMessage(status: status, subtitle: _subtitle),
// );
},
),
SizedBox(
width: 16,
)
],
),
),
serviceRequest.devicePhotos.isEmpty
? SizedBox.shrink()
: Column(
children: [
SizedBox(
height: 8,
),
MaterialButton(
padding: EdgeInsets.zero,
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (_) => Scaffold(
body: InteractiveViewer(
child: Center(
child: ImageLoader(
url: serviceRequest.devicePhotos.first,
boxFit: BoxFit.contain,
),
),
),
)));
},
child: SizedBox(
height: 140 * AppStyle.getScaleFactor(context),
width: MediaQuery.of(context).size.width,
child: ImageLoader(
url: serviceRequest.devicePhotos.first,
boxFit: BoxFit.cover,
),
),
),
SizedBox(height: 8),
SizedBox(
height: 60 * AppStyle.getScaleFactor(context),
child: ImagesList(
images: serviceRequest.devicePhotos,
),
),
],
),
TabBar(labelColor: AColors.primaryColor, tabs: [
Tab(
text: _subtitle.general,
),
Tab(
text: _subtitle.serviceRequestInformation,
),
]),
SizedBox(
height: 8,
),
Expanded(
child: TabBarView(
children: [
ListView(
padding: EdgeInsets.symmetric(horizontal: 16),
children: [
RequestInfoRow(
title: _subtitle.code,
info: serviceRequest.requestCode,
),
RequestInfoRow(
title: "Asset Number",
info: serviceRequest.deviceNumber,
),
RequestInfoRow(
title: _subtitle.assetName,
info: serviceRequest.deviceEnName,
),
RequestInfoRow(
title: _subtitle.deviceModel,
info: serviceRequest.deviceModel,
),
RequestInfoRow(
title: _subtitle.engineerName,
info: serviceRequest.engineerName,
),
RequestInfoRow(
title: _subtitle.engineerPhone,
info: serviceRequest.engineerMobile,
),
RequestInfoRow(
title: _subtitle.date,
info: serviceRequest.date,
),
serviceRequest.nextVisitDate == null
? SizedBox.shrink()
: RequestInfoRow(
title: _subtitle.nextVisitDate,
info: DateFormat('EE dd/MM/yyyy').format(serviceRequest.nextVisitDate),
),
Row(
child: FutureBuilder(
future: _serviceRequestsProvider.getServiceRequestObjectById(requestId: serviceRequest.id),
builder: (context, snap) {
if (snap.connectionState == ConnectionState.waiting) {
return const ALoading();
} else if (snap.hasData) {
serviceRequest = snap.data;
return Column(
children: [
Container(
color: AColors.primaryColor,
padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 4),
child: Row(
children: [
ABackButton(),
Expanded(
child: Text(
"${_subtitle.status} : ",
style: Theme.of(context).textTheme.subtitle1,
textScaleFactor: AppStyle.getScaleFactor(context),
child: Center(
child: Text(
_subtitle.details,
style: Theme.of(context).textTheme.headline6.copyWith(color: AColors.white, fontStyle: FontStyle.italic),
),
),
),
StatusLabel(label: serviceRequest.statusLabel, color: AColors.getRequestStatusColor(serviceRequest.statusValue)),
_userProvider.user.type == UsersTypes.normal_user
?
// AIconButton(
// iconData: Icons.warning_amber_rounded,
// color: AColors.white,
// buttonSize: 42,
// backgroundColor: AColors.deepOrange,
// onPressed: (){
// Navigator.of(context).push(
// MaterialPageRoute(
// builder: (_) => ReportIssuesPage(serviceRequest: serviceRequest,)
// )
// );
// },
// )
const SizedBox(
width: 48,
)
: AIconButton(
iconData: Icons.edit,
color: AColors.white,
buttonSize: 42,
backgroundColor: AColors.green,
onPressed: (serviceRequest.statusValue == 5 || serviceRequest.statusValue == 3)
? null
: () async {
Navigator.of(context).push(
MaterialPageRoute(builder: (_) => CreateRequestPage(serviceRequest: serviceRequest)),
);
// showModalBottomSheet(
// context: context,
// builder: (context) {
// return ServiceRequestsUpdateDialog(
// request: serviceRequest,
// );
// });
// DateTime picked = await showDatePicker(
// context: context,
// initialDate: DateTime.now(),
// firstDate: DateTime.now(),
// lastDate: DateTime.now().add(Duration(days: 182))
// );
// if(picked == null){return;}
// showDialog<void>(
// context: context,
// barrierDismissible: false,
// builder: (BuildContext context) {
// return CupertinoAlertDialog(
// title: Text(_subtitle.updatingDots),
// content: Center(child: CircularProgressIndicator()),
// );
// },
// );
// int status = await _serviceRequestsProvider.updateDate(
// user: _userProvider.user,
// host: _settingProvider.host,
// request: serviceRequest,
// newDate: picked.toString().split(" ").first
// );
// Navigator.of(context).pop();
// Fluttertoast.showToast(
// msg: HttpStatusManger.getStatusMessage(status: status, subtitle: _subtitle),
// );
},
),
SizedBox(
width: 16,
)
],
),
Divider(
color: Theme.of(context).primaryColor,
),
RequestInfoRow(
title: _subtitle.hospital,
info: serviceRequest.hospitalName,
),
RequestInfoRow(
title: _subtitle.unite,
info: serviceRequest.departmentName,
),
// RequestInfoRow(
// title: _subtitle.deviceArName,
// content: serviceRequest.deviceArName,
// ),
RequestInfoRow(
title: _subtitle.deviceName,
content: serviceRequest.deviceEnName,
),
serviceRequest.devicePhotos.isEmpty
? const SizedBox.shrink()
: SizedBox(
height: 60 * AppStyle.getScaleFactor(context),
child: FilesList(
images: serviceRequest.devicePhotos,
),
).paddingOnly(top: 4, bottom: 4),
// Column(
// children: [
// SizedBox(
// height: 8,
// ),
// MaterialButton(
// padding: EdgeInsets.zero,
// onPressed: () {
// Navigator.of(context).push(MaterialPageRoute(
// builder: (_) => Scaffold(
// body: InteractiveViewer(
// child: Center(
// child: ImageLoader(
// url: serviceRequest.devicePhotos.first,
// boxFit: BoxFit.contain,
// ),
// ),
// ),
// )));
// },
// child: SizedBox(
// height: 140 * AppStyle.getScaleFactor(context),
// width: MediaQuery.of(context).size.width,
// child: ImageLoader(
// url: serviceRequest.devicePhotos.first,
// boxFit: BoxFit.cover,
// ),
// ),
// ),
// SizedBox(height: 8),
// SizedBox(
// height: 60 * AppStyle.getScaleFactor(context),
// child: FilesList(
// images: serviceRequest.devicePhotos,
// ),
// ),
// ],
// ),
TabBar(labelColor: AColors.primaryColor, tabs: [
Tab(
text: _subtitle.general,
),
RequestInfoRow(
title: _subtitle.maintenanceIssue,
content: serviceRequest.callComments,
Tab(
text: _subtitle.serviceRequestInformation,
),
if (serviceRequest.audio?.isNotEmpty == true)
ASoundPlayer(
audio: serviceRequest.audio,
),
//
// Center(
// child: Padding(
// padding: EdgeInsets.all(32),
// child: AButton(
// text: _subtitle.duplicateRequest,
// onPressed: () async {
// bool result = await showDialog(
// context: context,
// builder: (_) => AAlertDialog(
// title: _subtitle.duplicateAlert,
// content: _subtitle.duplicateAlertMessage,
// )
// );
// if(result == true){
// showDialog(
// context: context,
// builder: (context){
// return Center(child: CircularProgressIndicator());
// }
// );
// int status = await _serviceRequestsProvider.createDuplicatedReport(
// host: _settingProvider.host,
// user: _userProvider.user,
// request: serviceRequest
// );
// Navigator.of(context).pop();
// ScaffoldMessenger.of(context).showSnackBar(
// SnackBar(
// content: Text(
// HttpStatusManger.getStatusMessage(status: status, subtitle: _subtitle)
// )
// )
// );
// }
// },
// ),
// ),
// )
],
),
// workOrders.isEmpty ?
FutureBuilder(
future: _serviceRequestsProvider.searchWorkOrders(callId: serviceRequest.requestCode),
builder: (context, snap) {
workOrders = snap.data as List<SearchWorkOrder>;
if (snap.connectionState == ConnectionState.waiting) return Center(child: CircularProgressIndicator());
if (snap.connectionState == ConnectionState.done && (snap.data?.length ?? 0) != 0) {
return SingleChildScrollView(
child: Column(
]),
SizedBox(
height: 8,
),
Expanded(
child: TabBarView(
children: [
ListView(
padding: EdgeInsets.symmetric(horizontal: 16),
children: [
ListView.separated(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
padding: EdgeInsets.all(21),
itemCount: workOrders.length,
separatorBuilder: (czt, index) => 21.height,
itemBuilder: (context, index) {
Color itemColor = index % 2 == 0 ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.onPrimary;
Color onItemColor = index % 2 != 0 ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.onPrimary;
return ElevatedButton(
style: ElevatedButton.styleFrom(
padding: EdgeInsets.symmetric(vertical: 8, horizontal: 8),
primary: itemColor.withOpacity(.7),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppStyle.getBorderRadius(context)),
),
),
//padding: EdgeInsets.symmetric(vertical: 8,horizontal: 8),
onPressed: () {
// onPressed(request);
},
child: Column(
children: [
RequestInfoRow(
title: _subtitle.callId,
content: serviceRequest.requestCode,
),
RequestInfoRow(
title: _subtitle.orderWorkNumber,
info: workOrders[index].workOrderNo.toString(),
),
RequestInfoRow(
title: _subtitle.visitDate,
info: workOrders[index].visitDate,
),
RequestInfoRow(title: _subtitle.assignedEmployee, info: workOrders[index].assignedEmployee?.name ?? ""),
RequestInfoRow(
title: _subtitle.assetSN,
info: workOrders[index].callRequest.asset.assetSerialNo,
),
RequestInfoRow(
title: _subtitle.assetName,
info: workOrders[index].callRequest.asset.modelDefinition.assetName,
),
RequestInfoRow(
title: _subtitle.model,
info: workOrders[index].callRequest.asset.modelDefinition.modelName,
),
RequestInfoRow(
title: _subtitle.site,
info: workOrders[index].callRequest.asset.site.custName,
),
RequestInfoRow(
title: _subtitle.maintenanceSituation,
info: workOrders[index].calllastSituation.name ?? '',
),
RequestInfoRow(
title: _subtitle.currentSituation,
info: workOrders[index].currentSituation.name ?? '',
),
_userProvider.user.type == UsersTypes.engineer && workOrders[index].workOrderNo != null
? Padding(
padding: EdgeInsets.all(32),
child: AButton(
text: _subtitle.editServiceReport,
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => FutureServiceReport(
request: serviceRequest,
workOrder: workOrders[index],
)),
);
},
),
)
: SizedBox.shrink(),
],
),
);
},
RequestInfoRow(
title: _subtitle.callId,
info: serviceRequest.requestCode,
),
RequestInfoRow(
title: "Asset Number",
info: serviceRequest.deviceNumber,
),
RequestInfoRow(
title: _subtitle.assetName,
info: serviceRequest.deviceEnName,
),
RequestInfoRow(
title: _subtitle.deviceModel,
info: serviceRequest.deviceModel,
),
if (_userProvider.user.type == UsersTypes.engineer)
Center(
child: Padding(
padding: const EdgeInsets.all(32),
child: AButton(
text: "Create Work Order",
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(builder: (_) => CreateServiceReport(request: serviceRequest)));
},
RequestInfoRow(
title: _subtitle.engineerName,
info: serviceRequest.engineerName,
),
RequestInfoRow(
title: _subtitle.engineerPhone,
info: serviceRequest.engineerMobile,
),
RequestInfoRow(
title: _subtitle.date,
info: serviceRequest.date,
),
serviceRequest.nextVisitDate == null
? SizedBox.shrink()
: RequestInfoRow(
title: _subtitle.nextVisitDate,
info: DateFormat('EE dd/MM/yyyy').format(serviceRequest.nextVisitDate),
),
Row(
children: [
Expanded(
child: Text(
"${_subtitle.status} : ",
style: Theme.of(context).textTheme.subtitle1,
textScaleFactor: AppStyle.getScaleFactor(context),
),
),
StatusLabel(label: serviceRequest.statusLabel, color: AColors.getRequestStatusColor(serviceRequest.statusValue)),
],
),
Divider(
color: Theme.of(context).primaryColor,
),
RequestInfoRow(
title: _subtitle.hospital,
info: serviceRequest.hospitalName,
),
RequestInfoRow(
title: _subtitle.unite,
info: serviceRequest.departmentName,
),
// RequestInfoRow(
// title: _subtitle.deviceArName,
// content: serviceRequest.deviceArName,
// ),
// RequestInfoRow(
// title: _subtitle.deviceName,
// content: serviceRequest.deviceEnName,
// ),
RequestInfoRow(
title: _subtitle.maintenanceIssue,
content: serviceRequest.callComments,
),
if (serviceRequest.audio?.isNotEmpty == true)
ASoundPlayer(
audio: serviceRequest.audio,
),
//
// Center(
// child: Padding(
// padding: EdgeInsets.all(32),
// child: AButton(
// text: _subtitle.duplicateRequest,
// onPressed: () async {
// bool result = await showDialog(
// context: context,
// builder: (_) => AAlertDialog(
// title: _subtitle.duplicateAlert,
// content: _subtitle.duplicateAlertMessage,
// )
// );
// if(result == true){
// showDialog(
// context: context,
// builder: (context){
// return Center(child: CircularProgressIndicator());
// }
// );
// int status = await _serviceRequestsProvider.createDuplicatedReport(
// host: _settingProvider.host,
// user: _userProvider.user,
// request: serviceRequest
// );
// Navigator.of(context).pop();
// ScaffoldMessenger.of(context).showSnackBar(
// SnackBar(
// content: Text(
// HttpStatusManger.getStatusMessage(status: status, subtitle: _subtitle)
// )
// )
// );
// }
// },
// ),
// ),
// )
],
),
);
} else {
return Column(
children: [
Expanded(
child: Center(
child: ASubTitle(_subtitle.dataNotFound),
),
),
if (_userProvider.user.type == UsersTypes.engineer)
Center(
child: Padding(
padding: const EdgeInsets.all(32),
child: AButton(
text: "Create Work Order",
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(builder: (_) => CreateServiceReport(request: serviceRequest)));
},
// workOrders.isEmpty ?
FutureBuilder(
future: _serviceRequestsProvider.searchWorkOrders(callId: serviceRequest.requestCode),
builder: (context, snap) {
workOrders = snap.data as List<SearchWorkOrder>;
if (snap.connectionState == ConnectionState.waiting) return Center(child: CircularProgressIndicator());
if (snap.connectionState == ConnectionState.done && (snap.data?.length ?? 0) != 0) {
return SingleChildScrollView(
child: Column(
children: [
ListView.separated(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
padding: EdgeInsets.all(21),
itemCount: workOrders.length,
separatorBuilder: (czt, index) => 21.height,
itemBuilder: (context, index) {
Color itemColor = index % 2 == 0 ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.onPrimary;
Color onItemColor = index % 2 != 0 ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.onPrimary;
return ElevatedButton(
style: ElevatedButton.styleFrom(
padding: EdgeInsets.symmetric(vertical: 8, horizontal: 8),
primary: itemColor.withOpacity(.7),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppStyle.getBorderRadius(context)),
),
),
//padding: EdgeInsets.symmetric(vertical: 8,horizontal: 8),
onPressed: () {
// onPressed(request);
},
child: Column(
children: [
RequestInfoRow(
title: _subtitle.callId,
content: serviceRequest.requestCode,
),
RequestInfoRow(
title: _subtitle.orderWorkNumber,
info: workOrders[index].workOrderNo.toString(),
),
RequestInfoRow(
title: _subtitle.visitDate,
info: workOrders[index].visitDate,
),
RequestInfoRow(title: _subtitle.assignedEmployee, info: workOrders[index].assignedEmployee?.name ?? ""),
RequestInfoRow(
title: _subtitle.assetSN,
info: workOrders[index].callRequest.asset.assetSerialNo,
),
RequestInfoRow(
title: _subtitle.assetName,
info: workOrders[index].callRequest.asset.modelDefinition.assetName,
),
RequestInfoRow(
title: _subtitle.assetNumber,
info: workOrders[index].callRequest.asset.assetNumber,
),
RequestInfoRow(
title: _subtitle.model,
info: workOrders[index].callRequest.asset.modelDefinition.modelName,
),
RequestInfoRow(
title: _subtitle.site,
info: workOrders[index].callRequest.asset.site.custName,
),
RequestInfoRow(
title: "Call last Situation",
info: workOrders[index].currentSituation.name ?? '',
),
_userProvider.user.type == UsersTypes.engineer && workOrders[index].workOrderNo != null
? Padding(
padding: EdgeInsets.all(32),
child: AButton(
text: _subtitle.editServiceReport,
onPressed: serviceRequest.statusValue == 5 || serviceRequest.statusValue == 3
? null
: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => FutureServiceReport(
request: serviceRequest,
workOrder: workOrders[index],
)),
);
},
),
)
: SizedBox.shrink(),
],
),
);
},
),
if (_userProvider.user.type == UsersTypes.engineer)
Center(
child: Padding(
padding: const EdgeInsets.all(32),
child: AButton(
text: "Create Work Order",
onPressed: serviceRequest.statusValue == 5 || serviceRequest.statusValue == 3
? null
: () {
Navigator.of(context).push(MaterialPageRoute(builder: (_) => CreateServiceReport(request: serviceRequest)));
},
),
),
),
],
),
),
),
],
);
}
},
),
],
),
),
],
),
);
} else {
return Column(
children: [
Expanded(
child: Center(
child: ASubTitle(_subtitle.dataNotFound),
),
),
if (_userProvider.user.type == UsersTypes.engineer)
Center(
child: Padding(
padding: const EdgeInsets.all(32),
child: AButton(
text: "Create Work Order",
onPressed: serviceRequest.statusValue == 5 || serviceRequest.statusValue == 3
? null
: () {
Navigator.of(context).push(MaterialPageRoute(builder: (_) => CreateServiceReport(request: serviceRequest)));
},
),
),
),
],
);
}
},
),
],
),
),
],
);
}
return const SizedBox();
}),
),
),
);

@ -15,6 +15,7 @@ import 'package:test_sa/views/widgets/search/service_request_search_bar.dart';
class ServiceRequestsPage extends StatefulWidget {
static final String id = "/service-requests";
@override
_ServiceRequestsPageState createState() => _ServiceRequestsPageState();
}
@ -25,6 +26,7 @@ class _ServiceRequestsPageState extends State<ServiceRequestsPage> with TickerPr
SettingProvider _settingProvider;
bool _expandedSearch = false;
bool _firstTime = true;
@override
Widget build(BuildContext context) {
_serviceRequestsProvider = Provider.of<ServiceRequestsProvider>(context);

@ -22,6 +22,7 @@ import '../../../../widgets/pentry/pentry_info_form.dart';
class EditPentry extends StatefulWidget {
final Pentry pentry;
final Visit visit;
const EditPentry({Key key, this.pentry, this.visit}) : super(key: key);
@override
@ -39,6 +40,7 @@ class _EditPentryState extends State<EditPentry> with SingleTickerProviderStateM
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
TabController _tabController;
_onSubmit() async {
_validate = true;
@ -46,10 +48,9 @@ class _EditPentryState extends State<EditPentry> with SingleTickerProviderStateM
setState(() {});
return;
}
_isLoading = true;
setState(() {});
_pentry.clearEmptyObjects();
int status = await _regularVisitsProvider.updatePentry(user: _userProvider.user, host: _settingProvider.host, pentry: _pentry, visit: widget.visit);
_isLoading = false;
setState(() {});
@ -145,6 +146,7 @@ class _EditPentryState extends State<EditPentry> with SingleTickerProviderStateM
PentryPMKitForm(
models: _pentry.pmKits,
enableValidate: _validate,
assetId: widget.visit?.deviceId,
),
PentryInfoForm(
model: _pentry,

@ -21,6 +21,7 @@ import 'package:test_sa/views/widgets/visits/visits_list.dart';
class PreventiveMaintenanceVisitsPage extends StatefulWidget {
static final String id = "/preventive-maintenance-visits";
@override
_PreventiveMaintenanceVisitsPageState createState() => _PreventiveMaintenanceVisitsPageState();
}

@ -21,6 +21,7 @@ import 'package:test_sa/views/widgets/visits/visits_list.dart';
class RegularVisitsPage extends StatefulWidget {
static final String id = "/Regular-visits";
@override
_RegularVisitsPageState createState() => _RegularVisitsPageState();
}
@ -31,6 +32,7 @@ class _RegularVisitsPageState extends State<RegularVisitsPage> with TickerProvid
SettingProvider _settingProvider;
bool _expandedSearch = false;
Subtitle _subtitle;
@override
Widget build(BuildContext context) {
_visitsProvider = Provider.of<RegularVisitsProvider>(context);
@ -105,7 +107,7 @@ class _RegularVisitsPageState extends State<RegularVisitsPage> with TickerProvid
),
),
Visibility(
visible: _visitsProvider.visitsSearch.toMap().isNotEmpty,
visible: (_visitsProvider.visitsSearch.toMap()..remove("mostRecent")).isNotEmpty,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: AButton(

@ -1,10 +1,5 @@
import 'package:flutter/material.dart';
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:test_sa/controllers/localization/localization.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/models/subtitle.dart';
import 'package:test_sa/models/visits/visit.dart';
import 'package:test_sa/models/visits/visits_group.dart';
@ -18,6 +13,7 @@ import 'package:test_sa/views/widgets/visits/visit_status.dart';
class UpdateVisitsGroupSheet extends StatefulWidget {
final List<Visit> visits;
final String title;
const UpdateVisitsGroupSheet({Key key, this.visits, this.title}) : super(key: key);
@override
@ -36,6 +32,7 @@ class _UpdateVisitsGroupSheetState extends State<UpdateVisitsGroupSheet> {
// Lookup(name: "Failed", id: 1),
// ];
VisitsGroup _group = VisitsGroup();
// File _image;
Subtitle _subtitle;

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/localization/localization.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/subtitle.dart';
import 'package:test_sa/models/visits/visit.dart';
import 'package:test_sa/views/app_style/colors.dart';
@ -8,25 +9,25 @@ import 'package:test_sa/views/app_style/sizing.dart';
import 'package:test_sa/views/pages/user/visits/pantry/edit_pentry.dart';
import 'package:test_sa/views/widgets/buttons/app_back_button.dart';
import 'package:test_sa/views/widgets/buttons/app_icon_button.dart';
import 'package:test_sa/views/widgets/images/files_list.dart';
import 'package:test_sa/views/widgets/images/images_list.dart';
import 'package:test_sa/views/widgets/loaders/image_loader.dart';
import 'package:test_sa/views/widgets/requests/info_row.dart';
import 'package:test_sa/views/widgets/visits/visit_status.dart';
import '../../../../controllers/providers/api/regular_visits_provider.dart';
import '../../../../controllers/providers/api/user_provider.dart';
import '../../../../models/enums/user_types.dart';
import '../../../widgets/loaders/image_loader.dart';
class VisitDetailsPage extends StatelessWidget {
static final String id = "/visit-details";
static const String id = "/visit-details";
final Visit visit;
const VisitDetailsPage({Key key, this.visit}) : super(key: key);
@override
Widget build(BuildContext context) {
Subtitle _subtitle = AppLocalization.of(context).subtitle;
final regularVisitsProvider = Provider.of<RegularVisitsProvider>(context);
UserProvider _userProvider = Provider.of<UserProvider>(context);
Subtitle subtitle = AppLocalization.of(context).subtitle;
UserProvider userProvider = Provider.of<UserProvider>(context);
return Scaffold(
body: SafeArea(
@ -37,80 +38,87 @@ class VisitDetailsPage extends StatelessWidget {
padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 4),
child: Row(
children: [
ABackButton(),
const ABackButton(),
Expanded(
child: Center(
child: Text(
_subtitle.visitInformation,
style: Theme.of(context).textTheme.headline6.copyWith(color: AColors.white, fontStyle: FontStyle.italic),
subtitle.visitInformation,
style: Theme.of(context).textTheme.titleLarge.copyWith(color: AColors.white, fontStyle: FontStyle.italic),
),
),
),
if (_userProvider?.user?.type == UsersTypes.engineer)
if (userProvider?.user?.type == UsersTypes.engineer)
AIconButton(
iconData: Icons.edit,
color: AColors.white,
buttonSize: 42,
backgroundColor: AColors.green,
onPressed: () async {
Navigator.of(context).push(MaterialPageRoute(
builder: (_) => EditPentry(
visit: visit,
pentry: visit.pentry,
)));
},
onPressed: visit?.status?.name == "Closed" || visit?.status?.name == "Complete"
? null
: () async {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => EditPentry(
visit: visit,
pentry: visit.pentry,
),
),
);
},
),
SizedBox(width: 42)
const SizedBox(width: 42)
],
),
),
Expanded(
child: ListView(
padding: EdgeInsets.symmetric(horizontal: 16),
padding: const EdgeInsets.symmetric(horizontal: 16),
children: [
SizedBox(
height: 8,
),
MaterialButton(
padding: EdgeInsets.zero,
onPressed: visit.images.isEmpty || (visit.images?.first?.isEmpty ?? false)
? () {}
: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (_) => Scaffold(
body: InteractiveViewer(
child: Center(
child: ImageLoader(
url: visit.images.first,
boxFit: BoxFit.contain,
),
),
),
)));
},
child: SizedBox(
height: 140 * AppStyle.getScaleFactor(context),
width: MediaQuery.of(context).size.width,
child: ImageLoader(
url: visit.images.isEmpty ? " " : visit.images.first,
boxFit: BoxFit.cover,
const SizedBox(height: 8),
// MaterialButton(
// padding: EdgeInsets.zero,
// onPressed: () {
// if ((visit.images?.isNotEmpty ?? false) && (visit.images?.first?.isNotEmpty ?? false)) {
// Navigator.of(context).push(
// MaterialPageRoute(
// builder: (_) => Scaffold(
// body: InteractiveViewer(
// child: Center(
// child: ImageLoader(
// url: visit.images.first,
// boxFit: BoxFit.contain,
// ),
// ),
// ),
// ),
// ),
// );
// }
// },
// child: SizedBox(
// height: 140 * AppStyle.getScaleFactor(context),
// width: MediaQuery.of(context).size.width,
// child: ImageLoader(
// url: visit.images.isEmpty ? " " : visit.images.first,
// boxFit: BoxFit.cover,
// ),
// ),
// ),
// const SizedBox(
// height: 8,
// ),
if (visit?.images?.isNotEmpty ?? false)
SizedBox(
height: 60 * AppStyle.getScaleFactor(context),
child: FilesList(
images: visit.images,
),
),
),
SizedBox(
height: 8,
),
SizedBox(
height: 60 * AppStyle.getScaleFactor(context),
child: ImagesList(
images: visit.images,
),
),
SizedBox(
).paddingOnly(top: 4, bottom: 4),
const SizedBox(
height: 8,
),
RequestInfoRow(
title: _subtitle.code,
title: subtitle.code,
info: visit.serialNumber,
),
RequestInfoRow(
@ -118,23 +126,27 @@ class VisitDetailsPage extends StatelessWidget {
info: visit.deviceNumber,
),
RequestInfoRow(
title: _subtitle.deviceSN,
title: subtitle.deviceName,
content: visit.deviceEnglishName,
),
RequestInfoRow(
title: subtitle.deviceSN,
info: visit.deviceSerialNumber,
),
RequestInfoRow(
title: _subtitle.expectDate,
title: subtitle.expectDate,
info: visit.expectDate,
),
RequestInfoRow(
title: _subtitle.actualDate,
title: subtitle.actualDate,
info: visit.actualDate,
),
Row(
children: [
Expanded(
child: Text(
"${_subtitle.status} : ",
style: Theme.of(context).textTheme.subtitle1.copyWith(fontWeight: FontWeight.bold),
"${subtitle.status} : ",
style: Theme.of(context).textTheme.titleMedium.copyWith(fontWeight: FontWeight.bold),
textScaleFactor: AppStyle.getScaleFactor(context),
),
),
@ -147,21 +159,17 @@ class VisitDetailsPage extends StatelessWidget {
color: Theme.of(context).primaryColor,
),
RequestInfoRow(
title: _subtitle.contactStatus,
title: subtitle.contactStatus,
info: visit.assignTo,
),
RequestInfoRow(
title: _subtitle.engineerName,
title: subtitle.engineerName,
info: visit.employName,
),
RequestInfoRow(
title: _subtitle.hospital,
title: subtitle.hospital,
content: visit.hospitalName,
),
RequestInfoRow(
title: _subtitle.deviceName,
content: visit.deviceEnglishName,
),
],
),
),

@ -9,6 +9,7 @@ class AFlatButton extends StatelessWidget {
final VoidCallback onPressed;
const AFlatButton({Key key, this.text, this.textColor, this.style, this.onPressed, this.padding}) : super(key: key);
@override
Widget build(BuildContext context) {
return TextButton(

@ -9,6 +9,7 @@ class ASmallButton extends StatelessWidget {
final VoidCallback onPressed;
const ASmallButton({Key key, this.text, this.style, this.onPressed, this.padding, this.color}) : super(key: key);
@override
Widget build(BuildContext context) {
return ElevatedButton(

@ -6,8 +6,9 @@ class ADatePicker extends StatelessWidget {
final DateTime from;
final DateTime to;
final Function(DateTime) onDatePicker;
final bool enable;
const ADatePicker({Key key, this.date, this.onDatePicker, this.from, this.to}) : super(key: key);
const ADatePicker({Key key, this.date, this.onDatePicker, this.from, this.to, this.enable = true}) : super(key: key);
@override
Widget build(BuildContext context) {
@ -19,14 +20,16 @@ class ADatePicker extends StatelessWidget {
borderRadius: BorderRadius.circular(12 * AppStyle.getScaleFactor(context)),
),
),
onPressed: enable
? () async {
DateTime picked = await showDatePicker(context: context, initialDate: DateTime.now(), firstDate: from ?? DateTime.now(), lastDate: to ?? DateTime.now().add(Duration(days: 365)));
onDatePicker(picked);
}
: null,
child: Text(
date == null ? "Pick Date" : date.toString().split(" ").first,
textScaleFactor: AppStyle.getScaleFactor(context),
),
onPressed: () async {
DateTime picked = await showDatePicker(context: context, initialDate: DateTime.now(), firstDate: from ?? DateTime.now(), lastDate: to ?? DateTime.now().add(Duration(days: 365)));
onDatePicker(picked);
},
);
}
}

@ -12,6 +12,7 @@ class FromToDateBar extends StatefulWidget {
final Function(DateTime) onPickTo;
const FromToDateBar({Key key, this.from, this.to, this.onPickFrom, this.onPickTo}) : super(key: key);
@override
_FromToDateBarState createState() => _FromToDateBarState();
}

@ -6,8 +6,10 @@ class ADateTimePicker extends StatelessWidget {
final DateTime from;
final DateTime to;
final Function(DateTime) onDateTimePicker;
final bool enable;
const ADateTimePicker({Key key, this.date, this.onDateTimePicker, this.from, this.to}) : super(key: key);
const ADateTimePicker({Key key, this.date, this.onDateTimePicker, this.from, this.to, this.enable}) : super(key: key);
@override
Widget build(BuildContext context) {
@ -23,10 +25,10 @@ class ADateTimePicker extends StatelessWidget {
date == null ? "Pick Time" : date.toString().substring(0, date.toString().lastIndexOf(":")),
textScaleFactor: AppStyle.getScaleFactor(context),
),
onPressed: () async {
onPressed: enable? () async {
// TimeOfDay picked = await showTimePicker(context: context, initialTime: TimeOfDay.now());
onDateTimePicker(await showDateTimePicker(context: context, initialDate: date, firstDate: from, lastDate: to));
},
}: null,
);
}
}

@ -1,5 +1,4 @@
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:test_sa/controllers/localization/localization.dart';
import 'package:test_sa/models/department.dart';
import 'package:test_sa/models/subtitle.dart';

@ -8,6 +8,7 @@ class DepartmentItem extends StatelessWidget {
final Function(Department) onPressed;
const DepartmentItem({Key key, this.department, this.onPressed}) : super(key: key);
@override
Widget build(BuildContext context) {
return Padding(

@ -13,6 +13,7 @@ import '../app_text_form_field.dart';
class SingleDepartmentPicker extends StatefulWidget {
static final String id = "/single-Department-Picker";
@override
_SingleDepartmentPickerState createState() => _SingleDepartmentPickerState();
}
@ -22,6 +23,7 @@ class _SingleDepartmentPickerState extends State<SingleDepartmentPicker> {
SettingProvider _settingProvider;
List<Department> _searchableList = [];
bool _firstTime = true;
@override
Widget build(BuildContext context) {
_departmentsProvider = Provider.of<DepartmentsProvider>(context);

@ -8,17 +8,19 @@ import 'package:test_sa/views/widgets/requests/info_row.dart';
import 'package:test_sa/views/widgets/requests/request_status.dart';
import '../../../controllers/providers/api/user_provider.dart';
import '../images/multi_image_picker.dart';
class DeviceTransferInfoSection extends StatelessWidget {
final DeviceTransferInfo info;
final bool isSender;
final VoidCallback onEdit;
const DeviceTransferInfoSection({Key key, this.info, this.onEdit}) : super(key: key);
const DeviceTransferInfoSection({Key key, this.info, this.onEdit, this.isSender}) : super(key: key);
@override
Widget build(BuildContext context) {
info.userName = Provider.of<UserProvider>(context).user.username;
final subtitle = AppLocalization.of(context).subtitle;
print("url:${info.signature}");
info.attachments ??= [];
return Column(
children: [
RequestInfoRow(
@ -29,10 +31,10 @@ class DeviceTransferInfoSection extends StatelessWidget {
title: subtitle.department,
info: info.department.name,
),
RequestInfoRow(
title: subtitle.engineerName,
info: info.userName,
),
// RequestInfoRow(
// title: isSender ? "Sender Name " : "Receiver Name",
// info: info.userName,
// ),
RequestInfoRow(
title: subtitle.workingHours,
info: info.workingHours,
@ -46,17 +48,21 @@ class DeviceTransferInfoSection extends StatelessWidget {
info: info.comment,
),
RequestInfoRow(
title: "Assigned FE",
title: "Assigned Engineer",
info: info.assignedEmployeeName,
),
RequestInfoRow(
title: "Signature",
info: info.signature?.isEmpty != false ? subtitle.noDateFound : null,
contentWidget: info.signature?.isEmpty != false
? null
: ImageLoader(
url: info.signature,
),
info: info.engSignature?.isEmpty != false ? subtitle.noDateFound : null,
contentWidget: info.engSignature?.isEmpty != false ? null : ImageLoader(url: info.engSignature),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 16),
child: MultiFilesPicker(
label: "Attachments",
files: info.attachments,
enabled: false,
),
),
RequestInfoRow(
title: subtitle.status,

@ -16,7 +16,7 @@ class DeviceTransferList extends StatelessWidget {
@override
Widget build(BuildContext context) {
if (items.length == 0) {
if (items.isEmpty) {
Subtitle subtitle = AppLocalization.of(context).subtitle;
return NoItemFound(
message: subtitle.noServiceRequestFound,
@ -33,11 +33,8 @@ class DeviceTransferList extends StatelessWidget {
return DeviceTransferItem(
index: itemIndex,
item: items[itemIndex],
onPressed: (model) {
Navigator.of(context).push(MaterialPageRoute(
builder: (_) => DeviceTransferDetails(
model: model,
)));
onPressed: (model) async {
Navigator.of(context).push(MaterialPageRoute(builder: (_) => DeviceTransferDetails(model: model)));
},
);
}),

@ -56,6 +56,20 @@ class DeviceButton extends StatelessWidget {
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Divider(
color: Theme.of(context).textTheme.subtitle1.color,
),
Text(
"${_subtitle.assetNumber} : ${device.number}",
style: Theme.of(context).textTheme.subtitle2,
),
Divider(
color: Theme.of(context).textTheme.subtitle1.color,
),
Text(
"${_subtitle.assetName} : ${device.modelDefinition.assetName}",
style: Theme.of(context).textTheme.subtitle2,
),
Divider(
color: Theme.of(context).textTheme.subtitle1.color,
),

@ -10,6 +10,7 @@ class DeviceItem extends StatelessWidget {
final Function(Device) onPressed;
const DeviceItem({Key key, this.device, this.onPressed}) : super(key: key);
@override
Widget build(BuildContext context) {
Subtitle _subtitle = AppLocalization.of(context).subtitle;

@ -1,5 +1,4 @@
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/localization/localization.dart';
import 'package:test_sa/controllers/providers/api/devices_provider.dart';
@ -18,6 +17,7 @@ import '../qr/scan_qr.dart';
class SingleDevicePicker extends StatefulWidget {
static final String id = "/single-device-Picker";
final bool sandraChoice = true;
@override
_SingleDevicePickerState createState() => _SingleDevicePickerState();
}
@ -33,12 +33,19 @@ class _SingleDevicePickerState extends State<SingleDevicePicker> {
TextEditingController numberController = TextEditingController();
TextEditingController snController = TextEditingController();
_getDevice(String result) async {
print(result);
_getDevice(String result, {bool isQr = false}) async {
if (result == null) return;
// List<Device> devices = await _devicesProvider.getDevicesListBySN(host: _settingProvider.host, user: _userProvider.user, hospitalId: _userProvider.user.clientId, sn: result);
_devicesProvider.reset();
await _devicesProvider.getEquipment(user: _userProvider.user, host: _settingProvider.host, hospitalId: _userProvider.user.clientId, serialNumber: "", number: result);
await _devicesProvider.getEquipment(
user: _userProvider.user,
host: _settingProvider.host,
hospitalId: _userProvider.user.clientId,
serialNumber: "",
number: result,
isQr: isQr,
);
_searchableList.clear();
_searchableList.addAll(_devicesProvider.devices);
// Navigator.of(context).pop();
@ -163,7 +170,7 @@ class _SingleDevicePickerState extends State<SingleDevicePicker> {
String result = await Navigator.of(context).push(
MaterialPageRoute(builder: (_) => const ScanQr()),
) as String;
_getDevice(result);
_getDevice(result, isQr: true);
},
),
);

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save