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.dartdesign_3.0_internal_audit_module
commit
84dd801ed1
@ -0,0 +1,4 @@
|
|||||||
|
enum RecurrentTaskInspectionDataTypeEnum {
|
||||||
|
bool, //bool
|
||||||
|
number, // number
|
||||||
|
}
|
||||||
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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);
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue