Merge remote-tracking branch 'origin/design_3.0_ppm_new_flow' into design_3.0_ppm_new_flow

# Conflicts:
#	lib/views/pages/user/ppm/ppm_details_page.dart
#	lib/views/pages/user/ppm/ppm_work_order/recurrent_wo/recurrent_work_order_view.dart
design_3.0_latest
Sikander Saleem 12 months ago
commit 84dd801ed1

@ -82,6 +82,10 @@ class URLs {
static get swipeUrl=> '$_baseUrl/Swipe/Swipe';
static get getSwipeLastTransactionUrl=> '$_baseUrl/Swipe/GetLastTransaction';
static get getSwipeTransactionHistoryUrl=> '$_baseUrl/Swipe/GetTransactions';
//Recurrent plan Api...
static get getRecurrentPlanByIdUrl=> '$_baseUrl/PlanRecurrentTasks/GetPlanRecurrentTaskById';
static get updateRecurrentPlanUrl=> '$_baseUrl/PlanRecurrentTasks/UpdateTaskByEngineer';
//service request.....
static get getServiceRequests => "$_baseUrl/CallRequest/GetCallRequests"; // get

@ -4,8 +4,11 @@ import 'package:flutter/widgets.dart';
import 'package:http/http.dart';
import 'package:test_sa/controllers/api_routes/api_manager.dart';
import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/models/all_requests_and_count_model.dart';
import 'package:test_sa/models/enums/user_types.dart';
import 'package:test_sa/models/ppm/recurrent_wo.dart';
import 'package:test_sa/models/timer_model.dart';
import '../../../models/search_all_requests_model.dart';
@ -17,6 +20,8 @@ class AllRequestsProvider extends ChangeNotifier {
bool isOverdueLoading = false;
bool isHighPriorityLoading = false;
bool isCalendarLoading = false;
bool isLoading = false;
bool _isFilterRequestLoading = false;
bool _isRequestCategoryLoading = false;
@ -48,12 +53,24 @@ class AllRequestsProvider extends ChangeNotifier {
AllRequestsAndCount? _requestDetailList;
AllRequestsAndCount? get allRequestsAndCount => _allRequestsAndCount;
AllRequestsAndCount? get highPriorityRequests => _highPriorityRequests;
AllRequestsAndCount? get overdueRequests => _overdueRequests;
// AllRequestsAndCount? get openRequests => _openRequests;
// AllRequestsAndCount? get completedRequests => _completedRequests;
AllRequestsAndCount? get requestDetailList => _requestDetailList;
RecurrentWoData? _recurrentWoData=RecurrentWoData();
RecurrentWoData? get recurrentWoData => _recurrentWoData;
set recurrentWoData(RecurrentWoData? value) {
_recurrentWoData = value;
notifyListeners();
}
set requestDetailList(AllRequestsAndCount? value) {
_requestDetailList = value;
notifyListeners();
@ -115,10 +132,9 @@ class AllRequestsProvider extends ChangeNotifier {
SearchAllRequestsModel? searchedModel;
Future<int> getAllRequests(BuildContext context, {int? typeTransaction, SearchAllRequestsModel? search}) async {
print('loading value is $isAllLoading');
if (isAllLoading == true) return -2;
isAllLoading = true;
if (_allRequestsAndCount == null) notifyListeners();
if (_allRequestsAndCount == null) notifyListeners();
Response response;
try {
if (search != null) {
@ -128,7 +144,7 @@ class AllRequestsProvider extends ChangeNotifier {
}
final type = typeTransaction == null
? search?.typeTransaction == null || (search?.typeTransaction?.isEmpty ?? false)
? [1, 2, 3, 4]
? [1, 2, 3, 4, 5] //added 5 to get recurrent wo ...
: search!.typeTransaction
: [typeTransaction];
List<int> status = (search?.statuses == null || (search?.statuses?.isEmpty ?? false)) ? (((search?.isArchived ?? false) ? [3] : [1, 2, 4])) : search!.statuses!;
@ -177,6 +193,49 @@ class AllRequestsProvider extends ChangeNotifier {
}
}
Future<int> getRecurrentWoById({required int id}) async {
isLoading = true;
Response response;
try {
response = await ApiManager.instance.get(URLs.getRecurrentPlanByIdUrl + "?planRecurrentTaskId=$id");
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
recurrentWoData = RecurrentWoData.fromJson(json.decode(response.body)["data"]);
notifyListeners();
}
isLoading = false;
notifyListeners();
return response.statusCode;
} catch (error) {
isLoading = false;
stateCode = -1;
notifyListeners();
return -1;
}
}
Future<int> updateRecurrentWo({required int status}) async {
isLoading = true;
Response response;
try {
response = await ApiManager.instance.post(URLs.updateRecurrentPlanUrl, body: recurrentWoData!.toJson(status: status));
stateCode = response.statusCode;
isLoading = false;
notifyListeners();
return response.statusCode;
} catch (error) {
isLoading = false;
stateCode = -1;
notifyListeners();
return -1;
}
}
void updateRecurrentWoTimer({TimerModel? timer}) {
recurrentWoData?.recurrentWoTimerModel = timer;
notifyListeners();
}
Future<int> getCalendarRequests({required DateTime from, DateTime? to}) async {
if (isCalendarLoading == true) return -2;
isCalendarLoading = true;

@ -47,6 +47,7 @@ class GasRefillProvider extends ChangeNotifier {
Future<GasRefillModel?> getGasRefillObjectById(num id) async {
try {
Response response = await ApiManager.instance.get(URLs.getGasRefillById + "?gazRefillId=$id");
if (response.statusCode >= 200 && response.statusCode < 300) {
return GasRefillModel.fromJson(json.decode(response.body)["data"]);
} else {

@ -1,4 +1,5 @@
import 'package:test_sa/app_strings/app_asset.dart';
import 'package:test_sa/models/enums/recurrent_task_inspection_data_type.dart';
import 'package:test_sa/models/enums/swipe_type.dart';
import 'package:test_sa/models/enums/work_order_next_step.dart';
@ -94,6 +95,8 @@ extension IntExtensionsWorkOrder on int {
}
}
extension EnumExtensionsSwipeType on SwipeTypeEnum {
int getIntFromSwipeTypeEnum() {
switch (this) {
@ -106,3 +109,15 @@ extension EnumExtensionsSwipeType on SwipeTypeEnum {
}
}
}
extension StringExtensionsRecurrentTaskInpesctionDataType on String {
RecurrentTaskInspectionDataTypeEnum toRecurrentTaskInspectionDataTypeEnum() {
switch (this) {
case 'bool':
return RecurrentTaskInspectionDataTypeEnum.bool;
case 'number':
return RecurrentTaskInspectionDataTypeEnum.number;
default:
return RecurrentTaskInspectionDataTypeEnum.bool;
}
}
}

@ -38,6 +38,15 @@ extension StringExtensions on String {
return "";
}
}
String get toMonthYearFormat {
try {
DateTime dateTime = DateTime.parse(this);
String formattedDate = DateFormat('MMMM d, y').format(dateTime);
return formattedDate;
} catch (e) {
return "";
}
}
String get toAssetDetailsFormat {
try {

@ -526,10 +526,17 @@
"userName": "اسم المستخدم",
"siteName": "اسم الموقع",
"pointName": "اسم النقطة",
"checkIn": "تسجيل الدخول",
"createdDate": "تاريخ الإنشاء",
"employeeId": "رقم الموظف",
"extensionNo": "رقم التمديد",
"checkIn": "تسجيل الدخول",
"pmWo": "أمر العمل الوقائي",
"recurrentWo": "أمر العمل المتكرر",
"taskNo": "رقم المهمة",
"assignEngineer": "تعيين مهندس",
"scheduledDate": "التاريخ المجدول"
"scheduledDate": "التاريخ المجدول",
"complete": "اكتمل",
"recurrentWo": "أمر العمل المتكرر"
}

@ -535,5 +535,9 @@
"recurrentWo": "Recurrent WO",
"taskNo": "Task No",
"assignEngineer": "Assign Engineer",
"scheduledDate": "Scheduled Date"
"scheduledDate": "Scheduled Date",
"complete": "Complete",
"createdDate": "Created Date",
"employeeId": "Employee ID",
"extensionNo": "Extension No"
}

@ -52,6 +52,10 @@ class AssetTransfer {
this.destDepartmentName,
this.destBuildingName,
this.applied,
this.extensionNo,
this.name,
this.employeeId,
this.createdDate,
this.createdOn,
this.destFloorName,
this.destSiteName,
@ -155,6 +159,10 @@ class AssetTransfer {
destDepartmentName = json['destDepartmentName'];
destBuildingName = json['destBuildingName'];
applied = json['applied'];
extensionNo = json['extensionNo'];
employeeId = json['employeeId'];
name = json['name'];
createdDate = json['createdDate'];
createdOn = json['createdOn'];
destFloorName = json['destFloorName'];
destSiteName = json['destSiteName'];
@ -234,6 +242,10 @@ class AssetTransfer {
String? receiverMachineStatusName;
String? receiverEngSignatureUrl;
bool? applied;
dynamic extensionNo;
String? employeeId;
String? name;
String? createdDate;
String? createdOn;
String? modifiedOn;
List<VisitTimers>? senderVisitTimers;
@ -293,6 +305,10 @@ class AssetTransfer {
String? receiverMachineStatusName,
String? receiverEngSignatureUrl,
bool? applied,
dynamic extensionNo,
String? employeeId,
String? name,
String? createdDate,
String? createdOn,
String? modifiedOn,
String? assetSerialNo,
@ -359,6 +375,10 @@ class AssetTransfer {
receiverMachineStatusName: receiverMachineStatusName ?? this.receiverMachineStatusName,
receiverEngSignatureUrl: receiverEngSignatureUrl ?? this.receiverEngSignatureUrl,
applied: applied ?? this.applied,
extensionNo: extensionNo??this.extensionNo,
employeeId: employeeId??this.employeeId,
name: name??this.name,
createdDate: createdDate??this.createdDate,
createdOn: createdOn ?? this.createdOn,
modifiedOn: modifiedOn ?? this.modifiedOn,
assetSerialNo: assetSerialNo ?? this.assetSerialNo,
@ -436,6 +456,10 @@ class AssetTransfer {
map["receiverMachineStatusName"] = receiverMachineStatusName;
map["receiverEngSignatureUrl"] = receiverEngSignatureUrl;
map["applied"] = applied;
map["extensionNo"] = extensionNo;
map["employeeId"] = employeeId;
map["name"] = name;
map["createdDate"] = createdDate;
map["createdOn"] = createdOn;
map["modifiedOn"] = modifiedOn;
map["assetSerialNo"] = assetSerialNo;
@ -552,6 +576,10 @@ class AssetTransfer {
receiverMachineStatusName = assetTransfer.receiverMachineStatusName;
receiverEngSignatureUrl = assetTransfer.receiverEngSignatureUrl;
applied = assetTransfer.applied;
extensionNo = assetTransfer.extensionNo;
employeeId = assetTransfer.employeeId;
name = assetTransfer.name;
createdDate = assetTransfer.createdDate;
createdOn = assetTransfer.createdOn;
modifiedOn = assetTransfer.modifiedOn;
assetSerialNo = assetTransfer.assetSerialNo;

@ -0,0 +1,4 @@
enum RecurrentTaskInspectionDataTypeEnum {
bool, //bool
number, // number
}

@ -24,6 +24,10 @@ class GasRefillModel {
this.engSignature,
this.nurseSignature,
this.workingHours,
this.extensionNo,
this.employeeId,
this.name,
this.createdDate,
this.site,
this.building,
this.floor,
@ -47,6 +51,10 @@ class GasRefillModel {
endTime = json['endTime'];
comment = json['comment'];
workingHours = json['workingHours'];
extensionNo = json['extensionNo'];
employeeId = json['employeeId'];
name = json['name'];
createdDate = json['createdDate'];
try {
final DateTime? sd = DateTime.tryParse(startDate ?? "");
final DateTime? st = DateTime.tryParse(startTime ?? "");
@ -90,7 +98,11 @@ class GasRefillModel {
String? endTime; // Now nullable
String? engSignature; // Now nullable
String? nurseSignature; // Now nullable
num? workingHours; // Now nullable
num? workingHours;
dynamic extensionNo;
String? employeeId;
String? name;
String? createdDate;
Site? site; // Now nullable
Building? building; // Now nullable
Floor? floor; // Now nullable
@ -115,6 +127,10 @@ class GasRefillModel {
String? engSignature,
String? nurseSignature,
num? workingHours,
num? extensionNo,
num? employeeId,
String? name,
String? createdDate,
Site? site,
Building? building,
Floor? floor,
@ -161,6 +177,10 @@ class GasRefillModel {
map['engSignature'] = engSignature;
map['nurseSignature'] = nurseSignature;
map['workingHours'] = workingHours;
map['extensionNo'] = extensionNo;
map['employeeId'] = employeeId;
map['name'] = name;
map['createdDate'] = createdDate;
map['comment'] = comment;
if (site != null) {
map['site'] = site?.toJson(addBuildings: false); // Use '?.' for null safety
@ -223,6 +243,10 @@ class GasRefillModel {
engSignature = model.engSignature;
nurseSignature = model.nurseSignature;
workingHours = model.workingHours;
extensionNo = model.extensionNo;
employeeId = model.employeeId;
name = model.name;
createdDate = model.createdDate;
}
}

@ -0,0 +1,342 @@
import 'package:test_sa/extensions/enum_extensions.dart';
import 'package:test_sa/models/enums/recurrent_task_inspection_data_type.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/models/timer_model.dart';
class RecurrentWo {
RecurrentWoData? recurrentWoData;
String? message;
String? title;
String? innerMessage;
int? responseCode;
bool? isSuccess;
RecurrentWo({this.recurrentWoData, this.message, this.title, this.innerMessage, this.responseCode, this.isSuccess});
RecurrentWo.fromJson(Map<String, dynamic> json) {
recurrentWoData = json['data'] != null ? RecurrentWoData.fromJson(json['data']) : null;
message = json['message'];
title = json['title'];
innerMessage = json['innerMessage'];
responseCode = json['responseCode'];
isSuccess = json['isSuccess'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
if (recurrentWoData != null) {
data['data'] = recurrentWoData!.toJson();
}
data['message'] = message;
data['title'] = title;
data['innerMessage'] = innerMessage;
data['responseCode'] = responseCode;
data['isSuccess'] = isSuccess;
return data;
}
}
class RecurrentWoData {
int? id;
Engineer? engineer;
String? scheduleDate;
Status? status;
Site? site;
Lookup? building;
Lookup? floor;
Lookup? department;
Lookup? room;
List<PlanRecurrentMedicalTaskRooms>? planRecurrentMedicalTaskRooms;
List<PlanRecurrentTaskTimers>? planRecurrentTaskTimers;
TimerModel? recurrentWoTimerModel = TimerModel();
double? totalWorkingHours = 0.0;
RecurrentWoData(
{this.id,
this.engineer,
this.scheduleDate,
this.status,
this.site,
this.building,
this.recurrentWoTimerModel,
this.floor,
this.department,
this.room,
this.planRecurrentMedicalTaskRooms,
this.planRecurrentTaskTimers,
this.totalWorkingHours});
RecurrentWoData.fromJson(Map<String, dynamic> json) {
id = json['id'];
engineer = json['engineer'] != null ? new Engineer.fromJson(json['engineer']) : null;
scheduleDate = json['scheduleDate'];
status = json['status'] != null ? Status.fromJson(json['status']) : null;
site = json['site'] != null ? Site.fromJson(json['site']) : null;
building = json["building"] == null ? null : Lookup.fromJson(json["building"]);
floor = json["floor"] == null ? null : Lookup.fromJson(json["floor"]);
department = json["department"] == null ? null : Lookup.fromJson(json["department"]);
room = json["room"] == null ? null : Lookup.fromJson(json["room"]);
if (json['planRecurrentMedicalTaskRooms'] != null) {
planRecurrentMedicalTaskRooms = <PlanRecurrentMedicalTaskRooms>[];
json['planRecurrentMedicalTaskRooms'].forEach((v) {
planRecurrentMedicalTaskRooms!.add(PlanRecurrentMedicalTaskRooms.fromJson(v));
});
}
if (json['planRecurrentTaskTimers'] != null) {
planRecurrentTaskTimers = <PlanRecurrentTaskTimers>[];
json['planRecurrentTaskTimers'].forEach((v) {
planRecurrentTaskTimers?.add(PlanRecurrentTaskTimers.fromJson(v));
});
//TODO need to test this @waseem..
totalWorkingHours = json['planRecurrentTaskTimers'].fold(0.0, (sum, item) => (sum ?? 0) + DateTime.parse(item['endDateTime']).difference(DateTime.parse(item['startDateTime'])).inSeconds) ?? 0;
}
}
Map<String, dynamic> toJson({int? status = 0}) {
final Map<String, dynamic> data = <String, dynamic>{};
List taskRoomTabAttributesJson = [];
if (planRecurrentMedicalTaskRooms != null) {
taskRoomTabAttributesJson = planRecurrentMedicalTaskRooms
?.expand((room) => room.planRecurrentMedicalTaskRoomTabs ?? [])
.expand((tab) => tab.planRecurrentMedicalTaskRoomTabAttributes ?? [])
.map((attribute) => attribute.toJson())
.toList() ??
[];
}
data['id'] = id;
data['statusValue'] = status;
if (planRecurrentTaskTimers != null) {
data['planRecurrentTaskTimers'] = planRecurrentTaskTimers!.map((v) => v.toJson()).toList();
}
if (taskRoomTabAttributesJson.isNotEmpty) {
data['attributes'] = taskRoomTabAttributesJson;
} else {
data['attributes'] = [];
}
return data;
}
}
class Engineer {
String? userId;
String? userName;
String? email;
String? employeeId;
int? languageId;
Engineer({this.userId, this.userName, this.email, this.employeeId, this.languageId});
Engineer.fromJson(Map<String, dynamic> json) {
userId = json['userId'];
userName = json['userName'];
email = json['email'];
employeeId = json['employeeId'];
languageId = json['languageId'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['userId'] = userId;
data['userName'] = userName;
data['email'] = email;
data['employeeId'] = employeeId;
data['languageId'] = languageId;
return data;
}
}
class Status {
int? id;
String? name;
int? value;
Status({this.id, this.name, this.value});
Status.fromJson(Map<String, dynamic> json) {
id = json['id'];
name = json['name'];
value = json['value'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['name'] = name;
data['value'] = value;
return data;
}
}
class Site {
int? id;
String? siteName;
Site({this.id, this.siteName});
Site.fromJson(Map<String, dynamic> json) {
id = json['id'];
siteName = json['siteName'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = {};
data['id'] = id;
data['siteName'] = siteName;
return data;
}
}
class PlanRecurrentMedicalTaskRooms {
int? id;
Room? room;
List<PlanRecurrentMedicalTaskRoomTabs>? planRecurrentMedicalTaskRoomTabs;
PlanRecurrentMedicalTaskRooms({this.id, this.room, this.planRecurrentMedicalTaskRoomTabs});
PlanRecurrentMedicalTaskRooms.fromJson(Map<String, dynamic> json) {
id = json['id'];
room = json['room'] != null ? Room.fromJson(json['room']) : null;
if (json['planRecurrentMedicalTaskRoomTabs'] != null) {
planRecurrentMedicalTaskRoomTabs = <PlanRecurrentMedicalTaskRoomTabs>[];
json['planRecurrentMedicalTaskRoomTabs'].forEach((v) {
planRecurrentMedicalTaskRoomTabs!.add(PlanRecurrentMedicalTaskRoomTabs.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = {};
data['id'] = id;
if (room != null) {
data['room'] = room!.toJson();
}
if (planRecurrentMedicalTaskRoomTabs != null) {
data['planRecurrentMedicalTaskRoomTabs'] = planRecurrentMedicalTaskRoomTabs!.map((v) => v.toJson()).toList();
}
return data;
}
}
class Room {
int? id;
String? roomId;
Room({this.id, this.roomId});
Room.fromJson(Map<String, dynamic> json) {
id = json['id'];
roomId = json['roomId'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = {};
data['id'] = id;
data['roomId'] = roomId;
return data;
}
}
class PlanRecurrentMedicalTaskRoomTabs {
int? id;
String? tabName;
int? tabMedicalRoomId;
List<PlanRecurrentMedicalTaskRoomTabAttributes>? planRecurrentMedicalTaskRoomTabAttributes;
PlanRecurrentMedicalTaskRoomTabs({this.id, this.tabName, this.tabMedicalRoomId, this.planRecurrentMedicalTaskRoomTabAttributes});
PlanRecurrentMedicalTaskRoomTabs.fromJson(Map<String, dynamic> json) {
id = json['id'];
tabName = json['tabName'];
tabMedicalRoomId = json['tabMedicalRoomId'];
if (json['planRecurrentMedicalTaskRoomTabAttributes'] != null) {
planRecurrentMedicalTaskRoomTabAttributes = <PlanRecurrentMedicalTaskRoomTabAttributes>[];
json['planRecurrentMedicalTaskRoomTabAttributes'].forEach((v) {
planRecurrentMedicalTaskRoomTabAttributes!.add(PlanRecurrentMedicalTaskRoomTabAttributes.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = {};
data['id'] = id;
data['tabName'] = tabName;
data['tabMedicalRoomId'] = tabMedicalRoomId;
if (planRecurrentMedicalTaskRoomTabAttributes != null) {
data['planRecurrentMedicalTaskRoomTabAttributes'] = planRecurrentMedicalTaskRoomTabAttributes!.map((v) => v.toJson()).toList();
}
return data;
}
}
class PlanRecurrentMedicalTaskRoomTabAttributes {
int? id;
Attribute? attribute;
dynamic attributeValue;
PlanRecurrentMedicalTaskRoomTabAttributes({this.id, this.attribute, this.attributeValue});
PlanRecurrentMedicalTaskRoomTabAttributes.fromJson(Map<String, dynamic> json) {
id = json['id'];
attribute = json['attribute'] != null ? Attribute.fromJson(json['attribute']) : null;
attributeValue = json['attributeValue'] ?? (json['attribute']['type'] == 'bool' ? (json['attributeValue']?.toString() == 'true') : json['attributeValue']);
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['attributeValue'] = attributeValue != null ? attributeValue.toString() : attributeValue;
return data;
}
}
class Attribute {
String? name;
String? type;
String? key;
RecurrentTaskInspectionDataTypeEnum? dataTypeEnum;
Attribute({this.name, this.type, this.key, this.dataTypeEnum});
Attribute.fromJson(Map<String, dynamic> json) {
name = json['name'];
type = json['type'];
dataTypeEnum = json['type'] == null ? null : (json['type'] as String).toRecurrentTaskInspectionDataTypeEnum();
key = json['key'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['name'] = name;
data['type'] = type;
data['key'] = key;
return data;
}
}
class PlanRecurrentTaskTimers {
int? id;
String? startTime;
String? endTime;
dynamic workingHours;
PlanRecurrentTaskTimers({this.id, this.startTime, this.endTime, this.workingHours});
PlanRecurrentTaskTimers.fromJson(Map<String, dynamic> json) {
id = json['id'];
startTime = json['startDateTime'];
endTime = json['endDateTime'];
workingHours = json['workingHour'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['startDateTime'] = startTime;
data['endDateTime'] = endTime;
data['workingHour'] = workingHours;
return data;
}
}

@ -60,10 +60,12 @@ class AppColor {
static const Color red50 = Color(0xffD02127);
static const Color red60 = Color(0xff8C050A);
static const Color red70 = Color(0xffF63939);
static const Color red80 = Color(0xfffdcdcd);
//green
static const Color green40 = Color(0xffBAFFE1);
static const Color green50 = Color(0xff62BE96);
static const Color green30 = Color(0xffd8efe5);
static const Color green60 = Color(0xff065E38);
static const Color green70 = Color(0xff54C166);
static const Color green15 = Color(0xff157D14);

@ -37,6 +37,7 @@ class _MyRequestsPageState extends State<MyRequestsPage> {
context.translation.gasRefillRequest,
context.translation.deviceTransferRequest,
context.translation.preventiveMaintenance,
context.translation.recurrentWo,
];
_provider = Provider.of<AllRequestsProvider>(context, listen: false);
_provider!.reset();

@ -0,0 +1,75 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/all_requests_provider.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/all_requests_and_count_model.dart';
import 'package:test_sa/models/ppm/recurrent_wo.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/views/pages/user/ppm/ppm_work_order/recurrent_wo/recurrent_work_order_view.dart';
import '../../../../views/widgets/requests/request_status.dart';
class RecurrentWoItemView extends StatelessWidget {
final RequestsDetails? requestDetails;
final bool showShadow;
const RecurrentWoItemView({Key? key, this.requestDetails, this.showShadow = true}) : super(key: key);
@override
Widget build(BuildContext context) {
if (requestDetails != null) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
StatusLabel(
label: requestDetails!.priority!,
textColor: AppColor.getRequestStatusTextColorByName(context, requestDetails!.priority!),
backgroundColor: AppColor.getRequestStatusColorByName(context, requestDetails!.priority!),
),
8.width,
StatusLabel(
label: requestDetails!.status!,
textColor: AppColor.getRequestStatusTextColorByName(context, requestDetails!.status!),
backgroundColor: AppColor.getRequestStatusColorByName(context, requestDetails!.status!),
),
1.width.expanded,
Text(
requestDetails!.date?.toServiceRequestCardFormat ?? "",
textAlign: TextAlign.end,
style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50),
),
],
),
8.height,
(requestDetails?.nameOfType ?? context.translation.ppmRequest).heading5(context),
8.height,
'${context.translation.taskNo}: ${requestDetails!.id}'.bodyText(context),
'${context.translation.site}: ${requestDetails!.site}'.bodyText(context),
// '${context.translation.code}: ${request.code}'.bodyText(context),
'${context.translation.requestNo}: ${requestDetails!.requestNo}'.bodyText(context),
16.height,
Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
context.translation.viewDetails,
style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context)),
),
4.width,
Icon(Icons.arrow_forward, color: AppColor.blueStatus(context), size: 14)
],
),
],
).toShadowContainer(context, withShadow: showShadow).onPress(() async {
Navigator.of(context).push(MaterialPageRoute(builder: (_) => RecurrentWorkOrderView(taskId: requestDetails!.id)));
});
}
return const SizedBox();
}
}

@ -7,6 +7,7 @@ import 'package:test_sa/models/all_requests_and_count_model.dart';
import 'package:test_sa/new_views/pages/land_page/requests/asset_item_view.dart';
import 'package:test_sa/new_views/pages/land_page/requests/gas_refill_item_view.dart';
import 'package:test_sa/new_views/pages/land_page/requests/ppm_item_view.dart';
import 'package:test_sa/new_views/pages/land_page/requests/recurrent_wo_item_view.dart';
import 'package:test_sa/new_views/pages/land_page/requests/service_request_item_view.dart';
import 'package:test_sa/views/widgets/loaders/no_data_found.dart';
@ -25,24 +26,43 @@ class RequestItemViewList extends StatelessWidget {
shrinkWrap: true,
itemBuilder: (cxt, index) {
if (isLoading) return const SizedBox().toRequestShimmer(cxt, isLoading);
bool isServiceRequest = list[index].transactionType == 1;
bool isGasRefill = list[index].transactionType == 2;
bool isAssetTransfer = list[index].transactionType == 3;
bool isPPMs = list[index].transactionType == 4;
switch(list[index].transactionType){
case 1:
return ServiceRequestItemView(requestDetails: list[index]);
case 2:
return GasRefillItemView(requestDetails: list[index]);
case 3:
return AssetItemView(requestDetails: list[index]);
case 4:
return PpmItemView(requestDetails: list[index]);
case 5:
return RecurrentWoItemView(requestDetails: list[index]);
default:
Container(
height: 100,
width: double.infinity,
color: Colors.grey,
);
return isServiceRequest
? ServiceRequestItemView(requestDetails: list[index])
: isGasRefill
? GasRefillItemView(requestDetails: list[index])
: isPPMs
? PpmItemView(requestDetails: list[index])
: isAssetTransfer
? AssetItemView(requestDetails: list[index])
: Container(
height: 100,
width: double.infinity,
color: Colors.grey,
);
}
// bool isServiceRequest = list[index].transactionType == 1;
// bool isGasRefill = list[index].transactionType == 2;
// bool isAssetTransfer = list[index].transactionType == 3;
// bool isPPMs = list[index].transactionType == 4;
//
// return isServiceRequest
// ? ServiceRequestItemView(requestDetails: list[index])
// : isGasRefill
// ? GasRefillItemView(requestDetails: list[index])
// : isPPMs
// ? PpmItemView(requestDetails: list[index])
// : isAssetTransfer
// ? AssetItemView(requestDetails: list[index])
// : Container(
// height: 100,
// width: double.infinity,
// color: Colors.grey,
// );
},
separatorBuilder: (cxt, index) => 8.height,
itemCount: isLoading ? 6 : list.length);

@ -101,6 +101,7 @@ class _InternalMaintenanceRequestState extends State<InternalMaintenanceRequest>
print("timerProgress:$isRunning");
},
onChange: (timer) async {
requestDetailProvider.activityMaintenanceHelperModel?.activityMaintenanceTimerModel = timer;
return true;
},

@ -101,12 +101,6 @@ class _MaintenanceRequestFormState extends State<MaintenanceRequestForm> with Si
if (validate(model: requestDetailProvider.activityMaintenanceHelperModel!)) {
ActivityMaintenanceTimers model = ActivityMaintenanceTimers(
id: 0,
startTime: requestDetailProvider.activityMaintenanceHelperModel?.activityMaintenanceTimerModel?.startAt!.toIso8601String(), // Handle potential null
endTime: requestDetailProvider.activityMaintenanceHelperModel?.activityMaintenanceTimerModel?.endAt?.toIso8601String(), // Handle potential null
workingHours: ((requestDetailProvider.activityMaintenanceHelperModel?.activityMaintenanceTimerModel?.durationInSecond ?? 0) / 60 / 60),
);
requestDetailProvider.activityMaintenanceHelperModel?.activityMaintenanceTimers =requestDetailProvider.activityMaintenanceHelperModel?.activityMaintenanceTimers??[];
requestDetailProvider.activityMaintenanceHelperModel?.activityMaintenanceTimers?.add(
ActivityMaintenanceTimers(

@ -329,8 +329,6 @@ class _CreateNewRequestState extends State<CreateNewRequest> with TickerProvider
_serviceRequest.requestedThrough = Provider.of<RequestedThroughProvider>(context, listen: false).items.firstWhere((element) => element.value == 3, orElse: null);
_serviceRequest.type = Provider.of<TypeOfRequestProvider>(context, listen: false).items.firstWhere((element) => element.value == 1, orElse: null);
print('comments value is ${_serviceRequest.callComments}');
if (_formKey.currentState!.validate() && await _serviceRequest.validateNewRequest(context)) {
_formKey.currentState!.save();

@ -79,6 +79,11 @@ class _DeviceTransferDetailsState extends State<DeviceTransferDetails> {
_buildTextWidget('${context.translation.sn} : ${_model?.assetSerialNo ?? ""}'),
if (_model?.receiverEndUserName != null) _buildTextWidget('${context.translation.receiverName} : ${_model?.receiverEndUserName ?? ""}'),
_buildTextWidget('${context.translation.requestNo} : ${_model?.transferCode ?? ""}'),
//TODO need to confirm where to display this new data...
infoText(label:context.translation.gasRequest ,value:_model?.extensionNo ),
infoText(label:context.translation.employeeId ,value:_model?.employeeId ),
infoText(label:context.translation.name ,value:_model?.name ),
infoText(label:context.translation.createdDate ,value:_model?.createdDate?.toInitialVisitCardFormat),
if ((_model?.comment ?? "").isNotEmpty) ...[
8.height,
const Divider().defaultStyle(context),
@ -223,4 +228,13 @@ class _DeviceTransferDetailsState extends State<DeviceTransferDetails> {
],
).toShadowContainer(context);
}
Widget infoText({String ?label,String ?value,}){
if(value==null||value.isEmpty){
return const SizedBox();
}
else {
return '$label: $value'.bodyText(context);
}
}
}

@ -108,12 +108,19 @@ class _GasRefillDetailsPageState extends State<GasRefillDetailsPage> {
8.height,
context.translation.gasRefillRequest.heading5(context),
8.height,
'${context.translation.gasRequest}: ${gasRefillModel.gazRefillDetails![0].gasType?.name}'.bodyText(context),
'${context.translation.cylinderType}: ${gasRefillModel.gazRefillDetails![0].cylinderType?.name}'.bodyText(context),
'${context.translation.cylinderSize}: ${gasRefillModel.gazRefillDetails![0].cylinderSize?.name}'.bodyText(context),
'${context.translation.site}: ${gasRefillModel.site?.name?.cleanupWhitespace.capitalizeFirstOfEach}'.bodyText(context),
'${context.translation.department}: ${gasRefillModel.department?.name?.cleanupWhitespace.capitalizeFirstOfEach}'.bodyText(context),
'${context.translation.requestNo}: ${gasRefillModel.gazRefillNo}'.bodyText(context),
//TODO need to confirm where to display this new data...
infoText(label:context.translation.gasRequest ,value:gasRefillModel.extensionNo ),
infoText(label:context.translation.employeeId ,value:gasRefillModel.employeeId ),
infoText(label:context.translation.name ,value:gasRefillModel.name ),
infoText(label:context.translation.createdDate ,value:gasRefillModel.createdDate?.toInitialVisitCardFormat),
const Divider().defaultStyle(context),
'${context.translation.requestedQuantity}: ${gasRefillModel.gazRefillDetails![0].requestedQty ?? 0}'.bodyText(context),
'${context.translation.deliveredQuantity}: ${gasRefillModel.gazRefillDetails![0].deliverdQty ?? 0}'.bodyText(context),
@ -221,4 +228,14 @@ class _GasRefillDetailsPageState extends State<GasRefillDetailsPage> {
],
).toShadowContainer(context, padding: 0);
}
Widget infoText({String ?label,String ?value,}){
if(value==null||value.isEmpty){
return const SizedBox();
}
else {
return '$label: $value'.bodyText(context);
}
}
}

@ -176,6 +176,7 @@ class _RequestGasRefillState extends State<RequestGasRefill> {
@override
Widget build(BuildContext context) {
_userProvider = Provider.of<UserProvider>(context);
_settingProvider = Provider.of<SettingProvider>(context);
_gasRefillProvider ??= Provider.of<GasRefillProvider>(context, listen: false);

@ -1,116 +0,0 @@
import 'package:flutter/material.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/all_requests_and_count_model.dart';
import 'package:test_sa/models/ppm/ppm.dart';
import 'package:test_sa/models/timer_model.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/service_request_latest/utilities/service_request_utils.dart';
import 'package:test_sa/views/widgets/requests/request_status.dart';
import 'package:test_sa/views/widgets/timer/app_timer.dart';
class AssetInfoWidget extends StatelessWidget {
DummyModel ?model;
AssetInfoWidget({super.key,DummyModel ?model});
@override
Widget build(BuildContext context) {
return Column(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (model?.request?.priority != null)
StatusLabel(
label: model?.request?.priority,
textColor: AppColor.getRequestStatusTextColorByName(context,model?.request?.priority),
backgroundColor: AppColor.getRequestStatusColorByName(context,model?.request?.priority),
),
8.height,
model!.ppm!.assetName!.heading5(context),
8.height,
'${context.translation.taskNo}: ${model!.ppm!.assetName}'.bodyText(context),
'${context.translation.site}: ${model!.ppm!.siteName!.cleanupWhitespace.capitalizeFirstOfEach}'.bodyText(context),
'${context.translation.assignEngineer}: ${model!.ppm!.assignedEmployeeName ?? ""}'.bodyText(context),
'${context.translation.scheduledDate}: ${'July 7, 2024' ?? ""}'.bodyText(context),
],
).toShadowContainer(context),
12.height,
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
buildingInfoWidget(label: context.translation.department, value: model!.ppm!.departmentName!.cleanupWhitespace.capitalizeFirstOfEach,context: context),
8.height,
buildingInfoWidget(label: context.translation.floor, value: model!.ppm!.floorName!.cleanupWhitespace.capitalizeFirstOfEach,context: context),
8.height,
buildingInfoWidget(label: context.translation.room, value: model!.ppm!.roomName!.cleanupWhitespace.capitalizeFirstOfEach,context: context),
8.height,
AppTimer(
label: context.translation.timer,
timer: model!.timerModel,
width:double.infinity,
enabled: model!.timerModel?.endAt == null,
decoration: BoxDecoration(
color: AppColor.neutral100,
borderRadius: BorderRadius.circular(10),
),
timerProgress: (isRunning) {},
onChange: (timer) async {
timer = timer;
return true;
},
),
// if (totalWorkingHours > 0.0) ...[
11.height,
Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
"Total Working Time: ",
style: Theme.of(context).textTheme.bodySmall?.copyWith(color: context.isDark ? null : AppColor.neutral20, fontWeight: FontWeight.w500),
),
Text(
" ${ServiceRequestUtils.formatTimerDuration(model!.totalWorkingHours.round())}",
style: Theme.of(context).textTheme.bodyMedium,
),
],
),
8.height,
],
// ],
).toShadowContainer(context,padding: 12),
],
);
}
Widget buildingInfoWidget({required String label, required String value, required BuildContext context}) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.neutral120),
),
3.height,
Text(
value,
style: AppTextStyles.bodyText2.copyWith(color: AppColor.black10),
)
],
).toShadowContainer(context, backgroundColor: AppColor.neutral100, borderRadius: 10, paddingObject: EdgeInsets.all(12.toScreenHeight), showShadow: false);
}
}
class DummyModel{
RequestsDetails? request;
Ppm? ppm;
TimerModel? timerModel = TimerModel();
double totalWorkingHours = 2;
DummyModel(this.request,this.ppm,this.timerModel,this.totalWorkingHours);
}

@ -0,0 +1,146 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:test_sa/dashboard_latest/dashboard_view.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/enums/recurrent_task_inspection_data_type.dart';
import 'package:test_sa/models/ppm/recurrent_wo.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart';
class RoomInspectionCard extends StatefulWidget {
final PlanRecurrentMedicalTaskRoomTabs? inspectionModel;
RoomInspectionCard({super.key, required this.inspectionModel});
@override
State<RoomInspectionCard> createState() => _RoomInspectionCardState();
}
class _RoomInspectionCardState extends State<RoomInspectionCard> {
late List<bool> inspectionValues;
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
widget.inspectionModel!.tabName!.bodyText(context).custom(color: AppColor.neutral50, fontWeight: FontWeight.w600),
8.height,
Column(
children: widget.inspectionModel!.planRecurrentMedicalTaskRoomTabAttributes?.asMap().entries.map<Widget>((entry) {
final model = entry.value;
final attribute = model.attribute;
switch (attribute?.dataTypeEnum) {
case RecurrentTaskInspectionDataTypeEnum.bool:
return inspectionStatusRadioWidget(
index: entry.key,
model: model,
context: context,
);
case RecurrentTaskInspectionDataTypeEnum.number:
return inspectionStatusNumberWidget(
index: entry.key,
model: model,
context: context,
);
default:
return const SizedBox.shrink(); // Handles any unexpected cases gracefully
}
}).toList() ??
[],
)
],
).toShadowContainer(context).paddingOnly(top: 12);
}
Widget inspectionStatusRadioWidget({
required int index,
required PlanRecurrentMedicalTaskRoomTabAttributes model,
required BuildContext context,
}) {
bool status = model.attribute != null
? model.attributeValue == 'true'
? true
: false
: false;
String statusString = status ? 'Pass' : 'Fail';
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
model.attribute!.name!.bodyText2(context).custom(color: AppColor.white936, fontWeight: FontWeight.w500),
statusString.bodyText2(context).custom(color: AppColor.neutral120, fontWeight: FontWeight.w500),
],
),
SizedBox(
height: 24.toScreenHeight,
width: 41.toScreenWidth,
child: CupertinoSwitch(
thumbColor: status ? AppColor.green50 : AppColor.red30,
activeColor: AppColor.green30,
trackColor: AppColor.red80,
value: status,
onChanged: (state) {
setState(() {
model.attributeValue = state;
status = state;
});
},
),
)
],
).paddingOnly(bottom: 12);
}
Widget inspectionStatusNumberWidget({
required int index,
required PlanRecurrentMedicalTaskRoomTabAttributes model,
required BuildContext context,
}) {
final border = OutlineInputBorder(
borderRadius: BorderRadius.circular(4), // Optional: Slight rounding
borderSide: const BorderSide(
color: AppColor.white70, // Border color
width: 1, // 1px border
),
);
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
model.attribute!.name!.bodyText2(context).custom(color: AppColor.white936, fontWeight: FontWeight.w500),
TextFormField(
keyboardType: TextInputType.number,
initialValue: model.attributeValue ?? '',
decoration: InputDecoration(
contentPadding: EdgeInsets.symmetric(horizontal: 5.toScreenWidth),
filled: true,
fillColor: AppColor.neutral100,
constraints: const BoxConstraints(
maxHeight: 30,
maxWidth: 50,
),
border: border,
enabledBorder: border,
focusedBorder: border,
),
onChanged: (value) {
model.attributeValue = value;
},
),
],
).paddingOnly(bottom: 12);
}
}

@ -0,0 +1,87 @@
import 'package:flutter/material.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/ppm/recurrent_wo.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/views/pages/user/ppm/ppm_work_order/recurrent_wo/components/room_inspection_card.dart';
import 'package:test_sa/views/widgets/loaders/app_loading.dart';
class RoomTabsWidget extends StatefulWidget {
final RecurrentWoData? model;
const RoomTabsWidget({Key? key,required this.model}) : super(key: key);
@override
State<RoomTabsWidget> createState() => _RoomTabsWidgetState();
}
class _RoomTabsWidgetState extends State<RoomTabsWidget> {
int selectedIndex = 0;
bool isLoading = false;
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: EdgeInsets.all(8.toScreenHeight),
height: 57.toScreenHeight,
width: double.infinity,
decoration: BoxDecoration(
color: context.isDark ? AppColor.neutral50 : AppColor.white10,
borderRadius: BorderRadius.circular(10),
),
child: ListView(
scrollDirection: Axis.horizontal,
// mainAxisAlignment: MainAxisAlignment.spaceAround,
children: widget.model!.planRecurrentMedicalTaskRooms!.asMap().entries.map((entry) {
final int index = entry.key;
final String label = entry.value.room!.roomId!;
return GestureDetector(
onTap: () {
setState(() {
isLoading = true;
selectedIndex = index;
//TODO replace with api response delay...
Future.delayed(const Duration(seconds: 1)).whenComplete(() {
setState(() {
isLoading = false;
});
});
});
},
child: Container(
// margin: EdgeInsets.only(right: 8.toScreenWidth),
height: 49.toScreenHeight,
padding: EdgeInsets.symmetric(
// vertical: 20.toScreenHeight,
horizontal: 30.toScreenWidth,
),
alignment: Alignment.center,
decoration: BoxDecoration(
color: selectedIndex == index ? (context.isDark ? AppColor.neutral60 : AppColor.neutral110) : Colors.transparent,
borderRadius: BorderRadius.circular(7),
),
child: label.bodyText(context).custom(
color:AppColor.white936,
),
),
);
}).toList(),
),
),
isLoading
? SizedBox(height: 120.toScreenHeight, child: const ALoading().center)
: ListView(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
children: widget.model!.planRecurrentMedicalTaskRooms![selectedIndex].planRecurrentMedicalTaskRoomTabs!.map<Widget>((card) {
return RoomInspectionCard(inspectionModel: card);
}).toList(),
),
],
);
}
}

@ -0,0 +1,144 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/all_requests_provider.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/all_requests_and_count_model.dart';
import 'package:test_sa/models/ppm/ppm.dart';
import 'package:test_sa/models/ppm/recurrent_wo.dart';
import 'package:test_sa/models/timer_model.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/service_request_latest/utilities/service_request_utils.dart';
import 'package:test_sa/views/widgets/requests/request_status.dart';
import 'package:test_sa/views/widgets/timer/app_timer.dart';
class RecurrentTaskInfoWidget extends StatelessWidget {
final RecurrentWoData? model;
RecurrentTaskInfoWidget({super.key, required this.model});
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (model?.status != null)
StatusLabel(
label: model?.status?.name,
textColor: AppColor.getRequestStatusTextColorByName(context, model?.status?.name),
backgroundColor: AppColor.getRequestStatusColorByName(context, model?.status?.name),
),
8.height,
model!.site!.siteName!.bodyText(context).custom(color: AppColor.black10),
2.height,
'${context.translation.taskNo}: ${model!.id!}'.bodyText2(context).custom(color: AppColor.neutral120),
'${context.translation.site}: ${model!.site!.siteName!}'.bodyText2(context).custom(color: AppColor.neutral120),
'${context.translation.assignEngineer}: ${model!.engineer!.userName ?? ""}'.bodyText2(context).custom(color: AppColor.neutral120),
'${context.translation.scheduledDate}: ${model!.scheduleDate!.toMonthYearFormat}'.bodyText2(context).custom(color: AppColor.neutral120),
],
).toShadowContainer(context),
12.height,
model!.planRecurrentMedicalTaskRooms!.isEmpty
? Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
buildingInfoWidget(label: context.translation.department, value: model!.department!.name!.cleanupWhitespace.capitalizeFirstOfEach, context: context),
8.height,
buildingInfoWidget(label: context.translation.floor, value: model!.floor!.name!.cleanupWhitespace.capitalizeFirstOfEach, context: context),
8.height,
buildingInfoWidget(label: context.translation.room, value: model!.room!.name!.cleanupWhitespace.capitalizeFirstOfEach, context: context),
8.height,
_timerWidget(context, model!.totalWorkingHours!)
],
// ],
).toShadowContainer(context, padding: 12)
: _timerWidget(context, model!.totalWorkingHours!).toShadowContainer(context, padding: 12),
],
);
}
Widget _timerWidget(BuildContext context, double totalWorkingHours) {
return Consumer<AllRequestsProvider>(
builder: (context, snapshot,child) {
return Column(
children: [
AppTimer(
label: context.translation.timer,
timer: snapshot.recurrentWoData?.recurrentWoTimerModel,
width: double.infinity,
enabled: snapshot.recurrentWoData?.recurrentWoTimerModel?.endAt == null,
decoration: BoxDecoration(
color: AppColor.neutral100,
borderRadius: BorderRadius.circular(10),
),
timerProgress: (isRunning) {},
onChange: (timer) async {
snapshot.updateRecurrentWoTimer(timer: timer);
return true;
},
),
11.height,
if (totalWorkingHours > 0.0) ...[
Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
"Total Working Time: ",
style: Theme.of(context).textTheme.bodySmall?.copyWith(
color: context.isDark ? null : AppColor.neutral20,
fontWeight: FontWeight.w500,
),
),
Text(
" ${ServiceRequestUtils.formatTimerDuration(totalWorkingHours.round())}",
style: Theme.of(context).textTheme.bodyMedium,
),
],
),
],
8.height,
],
);
}
);
}
}
Widget buildingInfoWidget({required String label, required String value, required BuildContext context}) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
label,
style: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.neutral120),
),
3.height,
Text(
value,
style: AppTextStyles.bodyText2.copyWith(color: AppColor.black10),
)
],
).toShadowContainer(context, backgroundColor: AppColor.neutral100, borderRadius: 10, paddingObject: EdgeInsets.all(12.toScreenHeight), showShadow: false);
}
class DummyModel {
RequestsDetails? request;
Ppm? ppm;
TimerModel? timerModel = TimerModel();
double totalWorkingHours = 2;
DummyModel(this.request, this.ppm, this.timerModel, this.totalWorkingHours);
}

@ -1,23 +1,26 @@
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/ppm_provider.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/all_requests_and_count_model.dart';
import 'package:test_sa/models/enums/user_types.dart';
import 'package:test_sa/models/ppm/ppm.dart';
import 'package:test_sa/models/timer_model.dart';
import 'package:test_sa/models/ppm/recurrent_wo.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart';
import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
import 'package:test_sa/views/pages/user/ppm/ppm_work_order/recurrent_wo/components/asset_info_widget.dart';
import 'package:test_sa/service_request_latest/views/components/action_button/footer_action_button.dart';
import 'package:test_sa/views/pages/user/ppm/ppm_work_order/recurrent_wo/components/task_info_widget.dart';
import 'package:test_sa/views/widgets/loaders/app_loading.dart';
import 'package:test_sa/views/widgets/loaders/no_data_found.dart';
import '../../../../../../controllers/providers/api/all_requests_provider.dart';
import 'components/room_tabs_widget.dart';
class RecurrentWorkOrderView extends StatefulWidget {
static const String id = "/visit-details";
final RequestsDetails request;
static const String id = "/recurrent_wo";
final int? taskId;
const RecurrentWorkOrderView({Key? key, required this.request}) : super(key: key);
RecurrentWorkOrderView({Key? key, required this.taskId}) : super(key: key);
@override
_RecurrentWorkOrderViewState createState() {
@ -26,15 +29,12 @@ class RecurrentWorkOrderView extends StatefulWidget {
}
class _RecurrentWorkOrderViewState extends State<RecurrentWorkOrderView> {
UserProvider? userProvider;
TimerModel? timerModel = TimerModel();
PpmProvider? ppmProvider;
// double totalWorkingHours = _requestDetailProvider?.activityMaintenanceHelperModel?.activityMaintenanceTimers?.fold(0.0, (sum, item) => (sum ?? 0) + DateTime.parse(item.endTime!).difference(DateTime.parse(item.startTime!)).inSeconds) ?? 0;
double totalWorkingHours = 2.0;
AllRequestsProvider? allRequestsProvider;
@override
void initState() {
allRequestsProvider = Provider.of<AllRequestsProvider>(context, listen: false);
Provider.of<AllRequestsProvider>(context, listen: false).getRecurrentWoById(id: widget.taskId!);
super.initState();
}
@ -45,50 +45,109 @@ class _RecurrentWorkOrderViewState extends State<RecurrentWorkOrderView> {
@override
Widget build(BuildContext context) {
userProvider ??= Provider.of<UserProvider>(context, listen: false);
ppmProvider ??= Provider.of<PpmProvider>(context, listen: false);
return Consumer<AllRequestsProvider>(builder: (context, requestProvider, child) {
return Scaffold(
appBar: DefaultAppBar(title: context.translation.recurrentWo),
body: allRequestsProvider!.isLoading
? const ALoading()
: requestProvider.recurrentWoData != null
? Stack(
children: [
SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
RecurrentTaskInfoWidget(model: requestProvider.recurrentWoData),
// 8.height,
requestProvider.recurrentWoData!.planRecurrentMedicalTaskRooms!.isNotEmpty
? Column(
children: [
8.height,
RoomTabsWidget(
model: requestProvider.recurrentWoData,
),
],
)
: const SizedBox(),
],
).paddingAll(12),
).paddingOnly(bottom: 85),
FooterActionButton.footerContainer(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
AppFilledButton(
label: context.translation.save,
buttonColor: AppColor.white60,
textColor: AppColor.black10,
onPressed: () => _updateTask(
context: context,
status: 0,
),
).expanded,
12.width,
AppFilledButton(
label: context.translation.complete,
buttonColor: AppColor.primary10,
onPressed: () => _updateTask(
context: context,
status: 1,
),
).expanded,
],
),
),
],
)
: NoDataFound(message: context.translation.noDataFound).center,
);
});
}
}
void _updateTask({required BuildContext context, required int status}) async {
AllRequestsProvider allRequestsProvider = Provider.of<AllRequestsProvider>(context, listen: false);
return Scaffold(
appBar: DefaultAppBar(title: context.translation.recurrentWo),
body: SafeArea(
child: FutureBuilder(
future: ppmProvider!.getPlanPreventiveVisitById(widget.request.id!),
builder: (context, snap) {
if (snap.connectionState == ConnectionState.waiting) {
return const ALoading();
} else if (snap.hasData) {
Ppm ppm = snap.data as Ppm;
return Column(children: [
AssetInfoWidget(model: DummyModel(widget.request, ppm, timerModel, totalWorkingHours)),
]).paddingAll(12);
}
return NoDataFound(message: context.translation.noDataFound);
}),
if(validate(model: allRequestsProvider.recurrentWoData!)){
allRequestsProvider.recurrentWoData?.planRecurrentTaskTimers = allRequestsProvider.recurrentWoData?.planRecurrentTaskTimers ?? [];
DateTime ?startTime = allRequestsProvider.recurrentWoData?.recurrentWoTimerModel?.startAt;
DateTime ?endTime = allRequestsProvider.recurrentWoData?.recurrentWoTimerModel?.endAt;
final duration = (endTime?.difference(startTime!));
showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
allRequestsProvider.recurrentWoData?.planRecurrentTaskTimers?.add(
PlanRecurrentTaskTimers(
id: 0,
startTime: startTime?.toIso8601String(),
endTime: endTime?.toIso8601String(),
workingHours: (duration?.inSeconds ?? 0) / 60 / 60,
),
);
await allRequestsProvider.updateRecurrentWo(
status: status,
).whenComplete((){
if(status==1){// when click complete then this request remove from the list and status changes to closed..
//TODO some issues data not properly refreshed need to check waseem
allRequestsProvider.getAllRequests(context,typeTransaction: 5);
}
allRequestsProvider.recurrentWoData?.recurrentWoTimerModel=null;
Navigator.pop(context);
Navigator.pop(context);
});
}
}
class RoomTabs {
String label;
int tag;
int id;
//
RoomTabs({
required this.label,
required this.tag,
required this.id,
});
static List<RoomTabs> getTabs({required UsersTypes userType, required BuildContext context}) {
List<RoomTabs> tabs = [];
}
tabs.add(RoomTabs(label: 'Upcoming', tag: 0, id: 0));
tabs.add(RoomTabs(label: 'UnAssigned Open', tag: 1, id: 1));
tabs.add(RoomTabs(label: 'Assigned Open', tag: 1, id: 2));
tabs.add(RoomTabs(label: 'In Progress', tag: 2, id: 3));
tabs.add(RoomTabs(label: 'Completed', tag: 3, id: 4));
return tabs;
bool validate({required RecurrentWoData model}) {
if (model.recurrentWoTimerModel?.startAt == null) {
Fluttertoast.showToast(msg: "Working Hours Required");
return false;
}
if (model.recurrentWoTimerModel?.endAt == null) {
Fluttertoast.showToast(msg: "Please Stop The Timer");
return false;
}
return true;
}

Loading…
Cancel
Save