implement uiux changes on cleaner module

ui_ux_rollout_merge
WaseemAbbasi22 1 week ago
parent 3766c69368
commit 65335dca87

@ -7,8 +7,8 @@ class URLs {
// static const host1 = "https://atomsmdev.hmg.com"; // local DEV url
static const host1 = "https://atomsmuat.hmg.com"; // local UAT url
// static final String _baseUrl = "$_host/mobile"; // host local UAT
static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis
static final String _baseUrl = "$_host/mobile"; // host local UAT
// static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis
// static final String _baseUrl = "$_host/v3/mobile"; // v3 for production CM,PM,TM
// static final String _baseUrl = "$_host/v4/mobile"; // v4 for Demo module
// static final String _baseUrl = "$_host/v5/mobile"; // v5 for data segregation

@ -252,7 +252,7 @@ class _RequestCategoryFragmentState extends State<RequestCategoryFragment> with
snapshot.allRequestsAndCount?.requestsDetails ?? [],
snapshot.isAllLoading,
disableScroll: true,
key: ValueKey('request_list_'), // Key changes on every tab click
key: const ValueKey('request_list_'), // Key changes on every tab click
);
})
: dashboardProvider.listIndex.length == 1 && dashboardProvider.isUnassignedTab(dashboardProvider.listIndex[0])

@ -1,413 +0,0 @@
// UI: Cleaner Search Details View
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:provider/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/ppm/recurrent_wo.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart';
import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart';
import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
import 'package:test_sa/views/widgets/qr/scan_qr.dart';
import 'package:test_sa/views/widgets/requests/request_status.dart';
import '../models/cleaner_task_search_result.dart';
import '../provider/cleaner_provider.dart';
import '../../pm_module/recurrent_wo/recurrent_work_order_view.dart';
import 'package:test_sa/controllers/providers/api/all_requests_provider.dart';
import 'package:test_sa/views/widgets/dialogs/confirm_dialog.dart';
import 'package:test_sa/controllers/api_routes/api_manager.dart';
import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:http/http.dart' as http;
class CleanerSearchDetailsView extends StatefulWidget {
static const String routeName = '/cleaner_search_details';
final int requestId;
final CleanerTaskSearchResult? taskResult;
const CleanerSearchDetailsView({
Key? key,
required this.requestId,
this.taskResult,
}) : super(key: key);
@override
_CleanerSearchDetailsViewState createState() => _CleanerSearchDetailsViewState();
}
class _CleanerSearchDetailsViewState extends State<CleanerSearchDetailsView> {
late CleanerProvider _cleanerProvider;
// bool _isQRScanned = false;
bool _isRequestOpen = false;
CleanerTaskSearchResult? _taskData;
RecurrentWoData? _recurrentWoData;
bool _isLoading = false;
@override
void initState() {
super.initState();
_cleanerProvider = Provider.of<CleanerProvider>(context, listen: false);
_taskData = widget.taskResult;
WidgetsBinding.instance.addPostFrameCallback((_) {
getInitialData();
});
}
Future<void> getInitialData() async {
// If taskResult is null, fetch data from recurrent work order API
if (widget.taskResult == null) {
setState(() {
_isLoading = true;
});
try {
// Use direct API call to get better error messages
final result = await _getRecurrentWoByIdWithMessage(widget.requestId);
if (result["success"] == true && result["data"] != null) {
_recurrentWoData = result["data"];
_isRequestOpen = _recurrentWoData?.status?.value == 4;
_taskData = CleanerTaskSearchResult(
id: _recurrentWoData!.id,
taskNo: _recurrentWoData!.taskNo,
siteName: _recurrentWoData!.site?.siteName,
buildingName: _recurrentWoData!.building?.name,
floorName: _recurrentWoData!.floor?.name,
departmentName: _recurrentWoData!.department?.name,
roomName: _recurrentWoData!.room?.name,
locationDescription: null,
createdDate: _recurrentWoData!.scheduleDate,
);
} else {
// Show exact backend error message
if (mounted) {
_showErrorDialog(context, result["message"] ?? "Failed to load request details. Please try again.");
}
}
} catch (e) {
debugPrint('Error fetching recurrent work order: $e');
if (mounted) {
_showErrorDialog(context, "Failed to load request details. Please check your connection and try again.");
}
} finally {
setState(() {
_isLoading = false;
});
}
} else {
try {
await _cleanerProvider.getCleanerRequestById(id: widget.requestId);
} catch (e) {
debugPrint('Error fetching cleaner request: $e');
if (mounted) {
_showErrorDialog(context, "Failed to load request details. Please check your connection and try again.");
}
}
}
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
appBar: DefaultAppBar(
title: 'Request Details'.addTranslation,
onBackPress: () => Navigator.pop(context),
),
body: _isLoading
? const Center(child: CircularProgressIndicator())
: SafeArea(
child: Selector<CleanerProvider, bool>(
selector: (_, model) => model.isLoading,
builder: (_, isLoading, __) {
if (isLoading) {
return const Center(child: CircularProgressIndicator());
}
return Column(
children: [
SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildCleanerRequestDetailCard(context),
],
),
).expanded,
FooterActionButton.footerContainer(
context: context,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
if (_isRequestOpen) ...[
Row(
children: [
Icon(Icons.info_outline_rounded, size: 16, color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
8.width,
Expanded(
child: Text(
'By scanning the QR code you will accept this task'.addTranslation,
// textAlign: TextAlign.center,
style: AppTextStyles.bodyText2.copyWith(
color: context.isDark ? AppColor.neutral10 : AppColor.neutral120,
),
),
),
],
),
8.height,
],
AppFilledButton(
label: _isRequestOpen ? 'Scan QR Code' : 'Update',
maxWidth: true,
buttonColor: AppColor.primary10,
onPressed: () async {
if (_isRequestOpen) {
final result = await Navigator.push(context, MaterialPageRoute(builder: (context) => const ScanQr()));
if (result != null && result is String && result.isNotEmpty) {
showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
try {
final qrResult = await CleanerProvider().checkQRSameRoomWithMessage(planRecurrentTaskId: widget.requestId, qrCode: result);
if (mounted) Navigator.pop(context);
final isValid = qrResult["success"] ?? false;
final backendMessage = qrResult["message"] ?? "Unknown error occurred";
if (isValid) {
if (mounted) {
Navigator.of(context).pushReplacement(
MaterialPageRoute(builder: (_) => RecurrentWorkOrderView(taskId: widget.requestId)),
);
}
} else {
if (mounted) {
// Show exact backend error message instead of our custom message
_showErrorDialog(context, backendMessage);
}
}
} catch (e) {
if (mounted) Navigator.pop(context);
if (mounted) {
// Extract actual error message from the exception or use generic fallback
String errorMessage = _extractErrorMessage(e) ?? 'Failed to validate QR code. Please try again.';
_showErrorDialog(context, errorMessage);
}
}
}
} else {
Navigator.of(context).push(
MaterialPageRoute(builder: (_) => RecurrentWorkOrderView(taskId: widget.requestId)),
);
}
},
),
],
),
).toShadowContainer(context, padding: 0, showShadow: false, borderRadius: 0),
],
);
},
),
),
);
}
Widget _buildCleanerRequestDetailCard(BuildContext context) {
final taskResult = _taskData;
if (taskResult == null) {
return const SizedBox();
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Task Number and Date Row
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
// Text(
// 'Request Information',
// style: AppTextStyles.heading4.copyWith(
// color: context.isDark ? AppColor.neutral30 : AppColor.neutral50,
// ),
// ),
if (_recurrentWoData?.status?.name != null)
StatusLabel(
label: _recurrentWoData?.status?.name!,
textColor: AppColor.getRequestStatusTextColorByName(context, _recurrentWoData?.status?.name!),
backgroundColor: AppColor.getRequestStatusColorByName(context, _recurrentWoData?.status?.name!),
),
8.width,
// StatusLabel(
// label: taskModel?.taskJobStatus?.name ?? widget.requestDetails?.status!,
// textColor: AppColor.getRequestStatusTextColorByName(context, taskModel?.taskJobStatus?.name ?? widget.requestDetails?.status!),
// backgroundColor: AppColor.getRequestStatusColorByName(context, taskModel?.taskJobStatus?.name ?? widget.requestDetails?.status!),
// ),
if (taskResult.createdDate != null)
Text(
taskResult.createdDate!.toServiceRequestCardFormat,
textAlign: TextAlign.end,
style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
),
],
),
8.height,
if (_recurrentWoData?.title?.isNotEmpty ?? false)
Text(
_recurrentWoData?.title ?? "",
style: AppTextStyles.heading4.copyWith(
color: context.isDark ? AppColor.neutral30 : AppColor.neutral50,
),
),
if (taskResult.taskNo != null && taskResult.taskNo!.isNotEmpty)
Text(
'Task No: ${taskResult.taskNo!}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
if (taskResult.siteName != null && taskResult.siteName!.isNotEmpty)
Text(
'Site: ${taskResult.siteName}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
if (taskResult.buildingName != null && taskResult.buildingName!.isNotEmpty)
Text(
'Building: ${taskResult.buildingName}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
if (taskResult.floorName != null && taskResult.floorName!.isNotEmpty)
Text(
'Floor: ${taskResult.floorName}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
if (taskResult.departmentName != null && taskResult.departmentName!.isNotEmpty)
Text(
'Department: ${taskResult.departmentName}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
if (taskResult.roomName != null && taskResult.roomName!.isNotEmpty)
Text(
'Room: ${taskResult.roomName}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
if (taskResult.locationDescription != null && taskResult.locationDescription!.isNotEmpty)
Text(
'Location: ${taskResult.locationDescription}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
],
).expanded,
],
),
],
).paddingOnly(start: 16, end: 16, top: 16, bottom: 8),
],
).toShadowContainer(context, padding: 0);
}
void _showErrorDialog(BuildContext context, String message) {
showDialog(
context: context,
builder: (context) => ConfirmDialog(
message: message,
title: 'Error',
onTap: () => Navigator.pop(context),
),
);
}
String? _extractErrorMessage(dynamic error) {
// Implement your logic to extract error message from the exception
// For example, if the error is a custom exception with a message property:
if (error is ExceptionWithMessage) {
return error.message;
} else if (error is String) {
// If the error is a string, return it directly
return error;
} else if (error is Map<String, dynamic>) {
// If the error is a Map (e.g., parsed JSON), extract the message field
return error['message'] ?? error.toString();
}
// Fallback to a generic error message
return 'An unexpected error occurred. Please try again.';
}
/// Custom method to get recurrent work order with proper error message extraction
Future<Map<String, dynamic>> _getRecurrentWoByIdWithMessage(int id) async {
try {
final response = await ApiManager.instance.get(
URLs.getRecurrentPlanByIdUrl + "?planRecurrentTaskId=$id",
enableToastMessage: false, // Disable automatic toast
);
final responseData = json.decode(response.body);
if (response.statusCode >= 200 && response.statusCode < 300) {
// Success response
final recurrentWoData = RecurrentWoData.fromJson(responseData["data"]);
// Apply the same processing as in AllRequestsProvider
recurrentWoData.planRecurrentMedicalTaskRooms?.forEach((element) {
element.planRecurrentMedicalTaskRoomTabs?.forEach((tabs) {
tabs.planRecurrentMedicalTaskRoomTabAttributes?.forEach((attribute) {
if (attribute.attribute?.type == "bool" && attribute.attributeValue == null) {
attribute.attributeValue = "true";
}
});
});
});
return {
"success": true,
"data": recurrentWoData,
"message": "Data loaded successfully",
};
} else {
// Error response - extract the exact error message from backend
return {
"success": false,
"data": null,
"message": responseData["message"] ?? "Failed to load request details",
};
}
} catch (error) {
debugPrint('Error in _getRecurrentWoByIdWithMessage: $error');
return {
"success": false,
"data": null,
"message": "Failed to load request details. Please check your connection and try again.",
};
}
}
}
class ExceptionWithMessage implements Exception {
final String message;
ExceptionWithMessage(this.message);
}

@ -16,6 +16,7 @@ import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/providers/loading_list_notifier.dart';
import 'package:test_sa/views/widgets/dialogs/confirm_dialog.dart';
import 'package:test_sa/views/widgets/item_views/info_text_widget.dart';
import 'package:test_sa/views/widgets/qr/scan_qr.dart';
class CleanerSearchFormView extends StatefulWidget {
@ -203,6 +204,7 @@ class _CleanerSearchFormViewState extends State<CleanerSearchFormView> {
),
// Scan QR Code Button
8.height,
GestureDetector(
onTap: selectedTaskType != null ? _onScanQRCode : null,
child: Container(
@ -223,21 +225,17 @@ class _CleanerSearchFormViewState extends State<CleanerSearchFormView> {
"scan_asset".toSvgAsset(
height: 22,
fit: BoxFit.fitHeight,
color: selectedTaskType != null
? (context.isDark ? AppColor.neutral20 : AppColor.neutral120)
: Colors.grey,
color: selectedTaskType != null ? (context.isDark ? AppColor.neutral20 : AppColor.neutral120) : Colors.grey,
),
8.width,
//we can change the implementation when merge with uiux branch
_scannedLocationData==null? "Scan QR Code".bodyText(context).custom(
color: selectedTaskType != null
? (context.isDark ? AppColor.neutral20 : AppColor.black20)
: Colors.grey,
):'Re Scan QR Code'.bodyText(context).custom(
color: selectedTaskType != null
? (context.isDark ? AppColor.neutral20 : AppColor.black20)
: Colors.grey,
),
_scannedLocationData == null
? "Scan QR Code".bodyText(context).custom(
color: selectedTaskType != null ? (context.isDark ? AppColor.neutral20 : AppColor.black20) : Colors.grey,
)
: 'Re Scan QR Code'.bodyText(context).custom(
color: selectedTaskType != null ? (context.isDark ? AppColor.neutral20 : AppColor.black20) : Colors.grey,
),
],
),
),
@ -263,7 +261,7 @@ class _CleanerSearchFormViewState extends State<CleanerSearchFormView> {
FooterActionButton.footerContainer(
context: context,
child: AppFilledButton(
buttonColor:_scannedLocationData != null && !_isProceeding? AppColor.primary10: Colors.grey,
buttonColor: _scannedLocationData != null && !_isProceeding ? AppColor.primary10 : Colors.grey,
label: 'Proceed',
maxWidth: true,
onPressed: (_scannedLocationData != null && !_isProceeding) ? _onProceed : null,
@ -290,49 +288,45 @@ class _CleanerSearchFormViewState extends State<CleanerSearchFormView> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (locationData.siteName != null && locationData.siteName!.isNotEmpty)
Text(
'Site: ${locationData.siteName}',
style: AppTextStyles.bodyText.copyWith(
color: context.isDark ? AppColor.neutral10 : AppColor.neutral120,
),
InfoTextWidget(
label: 'Site', value: locationData.siteName,
// style: AppTextStyles.bodyText.copyWith(
// color: context.isDark ? AppColor.neutral10 : AppColor.neutral120,
// ),
),
if (locationData.buildingName != null && locationData.buildingName!.isNotEmpty)
Text(
'Building: ${locationData.buildingName}',
style: AppTextStyles.bodyText.copyWith(
color: context.isDark ? AppColor.neutral10 : AppColor.neutral120,
),
InfoTextWidget(
label: 'Building',
value: locationData.buildingName,
),
if (locationData.floorName != null && locationData.floorName!.isNotEmpty)
Text(
'Floor: ${locationData.floorName}',
style: AppTextStyles.bodyText.copyWith(
color: context.isDark ? AppColor.neutral10 : AppColor.neutral120,
),
InfoTextWidget(
label: 'Floor',
value: locationData.floorName,
),
if (locationData.departmentName != null && locationData.departmentName!.isNotEmpty)
Text(
'Department: ${locationData.departmentName}',
style: AppTextStyles.bodyText.copyWith(
color: context.isDark ? AppColor.neutral10 : AppColor.neutral120,
),
InfoTextWidget(
label: 'Department',
value: locationData.departmentName,
),
if (locationData.roomName != null && locationData.roomName!.isNotEmpty)
Text(
'Room: ${locationData.roomName}',
style: AppTextStyles.bodyText.copyWith(
color: context.isDark ? AppColor.neutral10 : AppColor.neutral120,
),
InfoTextWidget(
label: 'Room',
value: locationData.roomName,
),
if (locationData.locationDescription != null && locationData.locationDescription!.isNotEmpty)
Text(
'Location Description: ${locationData.locationDescription}',
style: AppTextStyles.bodyText.copyWith(
color: context.isDark ? AppColor.neutral10 : AppColor.neutral120,
),
softWrap: true,
maxLines: null,
InfoTextWidget(
label: 'Location Description',
value: locationData.locationDescription,
),
// Text(
// 'Location Description: ${locationData.locationDescription}',
// style: AppTextStyles.bodyText.copyWith(
// color: context.isDark ? AppColor.neutral10 : AppColor.neutral120,
// ),
// softWrap: true,
// maxLines: null,
// ),
],
).paddingOnly(start: 16, end: 16, top: 16, bottom: 16),
],

@ -2,7 +2,6 @@ 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/widget_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/modules/cleaner_module/models/one_time_task_data.dart';
import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
@ -11,6 +10,8 @@ import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/views/widgets/images/files_list.dart';
import 'package:test_sa/modules/cm_module/cm_request_utils.dart';
import 'package:test_sa/views/widgets/item_views/info_header_widget.dart';
import 'package:test_sa/views/widgets/item_views/info_text_widget.dart';
import 'package:test_sa/views/widgets/timer/app_timer.dart';
import 'package:test_sa/models/timer_model.dart';
import 'dart:convert';
@ -102,24 +103,20 @@ class OneTimeTaskPreviewScreen extends StatelessWidget {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
InfoHeader16Widget(
'Task Information',
style: AppTextStyles.heading5.copyWith(
color: context.isDark ? AppColor.neutral30 : AppColor.neutral50,
fontWeight: FontWeight.w600,
),
),
12.height,
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (taskData.oneTimeSetting?.taskTypeName != null) _buildInfoRow(context, 'Task Type', taskData.oneTimeSetting!.taskTypeName!),
if (taskData.siteName != null) _buildInfoRow(context, 'Site', taskData.siteName!),
if (taskData.buildingName != null) _buildInfoRow(context, 'Building', taskData.buildingName!),
if (taskData.floorName != null) _buildInfoRow(context, 'Floor', taskData.floorName!),
if (taskData.departmentName != null) _buildInfoRow(context, 'Department', taskData.departmentName!),
if (taskData.roomName != null) _buildInfoRow(context, 'Room', taskData.roomName!),
if (taskData.locationDescription != null) _buildInfoRow(context, 'Location', taskData.locationDescription!),
if (taskData.oneTimeSetting?.taskTypeName != null) InfoTextWidget(label: 'Task Type', value: taskData.oneTimeSetting!.taskTypeName!),
if (taskData.siteName != null) InfoTextWidget(label: 'Site', value: taskData.siteName!),
if (taskData.buildingName != null) InfoTextWidget(label: 'Building', value: taskData.buildingName!),
if (taskData.floorName != null) InfoTextWidget(label: 'Floor', value: taskData.floorName!),
if (taskData.departmentName != null) InfoTextWidget(label: 'Department', value: taskData.departmentName!),
if (taskData.roomName != null) InfoTextWidget(label: 'Room', value: taskData.roomName!),
if (taskData.locationDescription != null) InfoTextWidget(label: 'Location', value: taskData.locationDescription!),
],
).paddingAll(16),
],
@ -140,12 +137,8 @@ class OneTimeTaskPreviewScreen extends StatelessWidget {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
InfoHeader16Widget(
'Working Hours',
style: AppTextStyles.heading5.copyWith(
color: context.isDark ? AppColor.neutral30 : AppColor.neutral50,
fontWeight: FontWeight.w600,
),
),
12.height,
if (timerStartTime != null)
@ -156,7 +149,8 @@ class OneTimeTaskPreviewScreen extends StatelessWidget {
endAt: null,
durationInSecond: 0,
),
enabled: false, // Disable controls, just show the timer
enabled: false,
// Disable controls, just show the timer
showTimer: true,
decoration: BoxDecoration(
color: context.isDark ? AppColor.neutral20.withValues(alpha: 0.5) : AppColor.neutral10.withValues(alpha: 0.1),
@ -173,18 +167,11 @@ class OneTimeTaskPreviewScreen extends StatelessWidget {
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Total Working Hours',
style: AppTextStyles.bodyText.copyWith(
color: context.isDark ? AppColor.neutral10 : AppColor.neutral120,
),
InfoTextLabelWidget(
label: 'Total Working Hours',
),
Text(
InfoHeader16Widget(
CMRequestUtils.formatTotalWorkingHours(totalWorkingHours),
style: AppTextStyles.heading6.copyWith(
color: context.isDark ? AppColor.neutral10 : AppColor.neutral120,
fontWeight: FontWeight.w600,
),
),
],
),
@ -203,19 +190,11 @@ class OneTimeTaskPreviewScreen extends StatelessWidget {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
InfoHeader16Widget(
'Checklist',
style: AppTextStyles.heading5.copyWith(
color: context.isDark ? AppColor.neutral30 : AppColor.neutral50,
fontWeight: FontWeight.w600,
),
),
Text(
'${completedInstructions.length}/$totalInstructions',
style: AppTextStyles.bodyText.copyWith(
color: context.isDark ? AppColor.neutral10 : AppColor.neutral120,
fontWeight: FontWeight.w600,
),
InfoTextLabelWidget(
label: '${completedInstructions.length}/$totalInstructions',
),
],
),
@ -234,18 +213,15 @@ class OneTimeTaskPreviewScreen extends StatelessWidget {
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(
const Icon(
Icons.check_circle,
color: AppColor.primary10,
size: 20,
),
8.width,
Expanded(
child: Text(
instruction.instructionText ?? '',
style: AppTextStyles.bodyText.copyWith(
color: context.isDark ? AppColor.neutral10 : AppColor.neutral120,
),
child: InfoTextLabelWidget(
label: instruction.instructionText ?? '',
),
),
],
@ -262,19 +238,12 @@ class OneTimeTaskPreviewScreen extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Comment:',
style: AppTextStyles.tinyFont.copyWith(
color: context.isDark ? AppColor.neutral30 : AppColor.neutral50,
fontWeight: FontWeight.w600,
),
InfoTextLabelWidget(
label: 'Comment:',
),
4.height,
Text(
instruction.comment!,
style: AppTextStyles.bodyText.copyWith(
color: context.isDark ? AppColor.neutral10 : AppColor.neutral120,
),
InfoTextLabelWidget(
label: instruction.comment!,
),
],
),
@ -293,12 +262,8 @@ class OneTimeTaskPreviewScreen extends StatelessWidget {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
InfoHeader16Widget(
'Captured Images',
style: AppTextStyles.heading5.copyWith(
color: context.isDark ? AppColor.neutral30 : AppColor.neutral50,
fontWeight: FontWeight.w600,
),
),
16.height,
Wrap(
@ -350,12 +315,8 @@ class OneTimeTaskPreviewScreen extends StatelessWidget {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
InfoHeader16Widget(
'Attachments',
style: AppTextStyles.heading5.copyWith(
color: context.isDark ? AppColor.neutral30 : AppColor.neutral50,
fontWeight: FontWeight.w600,
),
),
FilesList(
images: taskData.attachments!.map((attachment) => URLs.getFileUrl(attachment.name ?? '') ?? '').toList(),
@ -387,20 +348,13 @@ class OneTimeTaskPreviewScreen extends StatelessWidget {
children: [
SizedBox(
width: 100,
child: Text(
'$label:',
style: AppTextStyles.bodyText.copyWith(
color: context.isDark ? AppColor.neutral30 : AppColor.neutral50,
),
child: InfoTextLabelWidget(
label:'$label:',
),
),
Expanded(
child: Text(
value,
style: AppTextStyles.bodyText.copyWith(
color: context.isDark ? AppColor.neutral10 : AppColor.neutral120,
fontWeight: FontWeight.w500,
),
child: InfoTextLabelWidget(
label: value,
),
),
],

@ -18,6 +18,9 @@ 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/new_views/pages/land_page/land_page.dart';
import 'package:test_sa/views/widgets/item_views/info_date_widget.dart';
import 'package:test_sa/views/widgets/item_views/info_header_widget.dart';
import 'package:test_sa/views/widgets/item_views/info_text_widget.dart';
import 'package:test_sa/views/widgets/loaders/app_loading.dart';
import 'package:test_sa/views/widgets/loaders/no_data_found.dart';
import 'package:test_sa/views/widgets/dialogs/confirm_dialog.dart';
@ -218,40 +221,32 @@ class _OneTimeTaskViewState extends State<OneTimeTaskView> {
textColor: AppColor.getHistoryLogStatusTextColorByName(context, _taskData!.statusName!),
backgroundColor: AppColor.getHistoryLogStatusColorByName(context, _taskData!.statusName!),
),
if (_taskData?.createdDate != null)
Text(
_taskData!.createdDate!.toString().toServiceRequestCardFormat,
textAlign: TextAlign.end,
style: AppTextStyles.tinyFont.copyWith(
color: context.isDark ? AppColor.neutral30 : AppColor.neutral50,
),
),
if (_taskData?.createdDate != null) InfoDateWidget(_taskData!.createdDate!.toString()),
],
),
12.height,
if (_taskData?.oneTimeSetting?.taskTypeName != null)
Text(
_taskData!.oneTimeSetting!.taskTypeName!,
style: AppTextStyles.heading4.copyWith(
color: context.isDark ? AppColor.neutral30 : AppColor.neutral50,
),
InfoTextLabelWidget(
label: _taskData!.oneTimeSetting!.taskTypeName!,
),
8.height,
// Text(
// _taskData!.oneTimeSetting!.taskTypeName!,
// style: AppTextStyles.heading4.copyWith(
// color: context.isDark ? AppColor.neutral30 : AppColor.neutral50,
// ),
// ),
// 8.height,
if (_taskData?.oneTimeSetting?.instructionDescriptionName != null)
Text(
_taskData!.oneTimeSetting!.instructionDescriptionName!,
style: AppTextStyles.bodyText.copyWith(
color: context.isDark ? AppColor.neutral10 : AppColor.neutral120,
),
InfoTextLabelWidget(
label: _taskData!.oneTimeSetting!.instructionDescriptionName!,
),
8.height,
if (_taskData?.siteName != null) _buildInfoRow('Site', _taskData!.siteName!),
if (_taskData?.buildingName != null) _buildInfoRow('Building', _taskData!.buildingName!),
if (_taskData?.floorName != null) _buildInfoRow('Floor', _taskData!.floorName!),
if (_taskData?.departmentName != null) _buildInfoRow('Department', _taskData!.departmentName!),
if (_taskData?.roomName != null) _buildInfoRow('Room', _taskData!.roomName!),
if (_taskData?.locationDescription != null) _buildInfoRow('Location', _taskData!.locationDescription!),
// Timer display using AppTimer widget
if (_taskData?.siteName != null) InfoTextWidget(label: 'Site', value: _taskData!.siteName!),
if (_taskData?.buildingName != null) InfoTextWidget(label: 'Building', value: _taskData!.buildingName!),
if (_taskData?.floorName != null) InfoTextWidget(label: 'Floor', value: _taskData!.floorName!),
if (_taskData?.departmentName != null) InfoTextWidget(label: 'Department', value: _taskData!.departmentName!),
if (_taskData?.roomName != null) InfoTextWidget(label: 'Room', value: _taskData!.roomName!),
if (_taskData?.locationDescription != null) InfoTextWidget(label: 'Location', value: _taskData!.locationDescription!),
if (_timerStart != null && !isClosed) ...[
12.height,
AppTimer(
@ -286,18 +281,6 @@ class _OneTimeTaskViewState extends State<OneTimeTaskView> {
).toShadowContainer(context, padding: 0);
}
Widget _buildInfoRow(String label, String value) {
return Padding(
padding: const EdgeInsets.only(bottom: 4),
child: Text(
'$label: $value',
style: AppTextStyles.bodyText.copyWith(
color: context.isDark ? AppColor.neutral10 : AppColor.neutral120,
),
),
);
}
List<ChecklistItem> _convertInstructionsToChecklist() {
// If checklist items are already created, reuse them
if (_checklistItems != null) {
@ -354,22 +337,15 @@ class _OneTimeTaskViewState extends State<OneTimeTaskView> {
// Validate that at least one image is captured
final capturedImages = _taskData?.imageRooms ?? [];
print('DEBUG: Captured images count: ${capturedImages.length}');
print('DEBUG: Images: $capturedImages');
if (capturedImages.isEmpty) {
_showErrorDialog(context, "Please capture at least one image before completing");
return;
}
// Calculate working hours
double totalWorkingHours = 0;
if (_timerStart != null) {
final duration = DateTime.now().difference(_timerStart!);
totalWorkingHours = duration.inSeconds / 3600.0;
}
// Navigate to preview screen
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => OneTimeTaskPreviewScreen(
@ -401,7 +377,6 @@ class _OneTimeTaskViewState extends State<OneTimeTaskView> {
}).toList() ??
[];
// Convert images to attachments format
final attachmentsPayload = _taskData?.imageRooms?.map((imageString) {
// imageString format: "filename|base64data"
final parts = imageString.split('|');

@ -11,6 +11,8 @@ import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart';
import 'package:test_sa/views/widgets/buttons/app_back_button.dart';
import 'package:test_sa/modules/cleaner_module/widgets/multi_image_picker.dart';
import 'package:test_sa/views/widgets/images/files_list.dart';
import 'package:test_sa/views/widgets/item_views/info_header_widget.dart';
import 'package:test_sa/views/widgets/item_views/info_text_widget.dart';
class CleanerChecklistWidget extends StatefulWidget {
final List<ChecklistItem> checklistItems;
@ -19,14 +21,7 @@ class CleanerChecklistWidget extends StatefulWidget {
final Function(List<String>)? onImagesChanged;
final bool isClosed;
const CleanerChecklistWidget({
Key? key,
required this.checklistItems,
this.onChecklistChanged,
required this.capturedImages,
this.onImagesChanged,
this.isClosed = false
}) : super(key: key);
const CleanerChecklistWidget({Key? key, required this.checklistItems, this.onChecklistChanged, required this.capturedImages, this.onImagesChanged, this.isClosed = false}) : super(key: key);
@override
State<CleanerChecklistWidget> createState() => _CleanerChecklistWidgetState();
@ -43,12 +38,7 @@ class _CleanerChecklistWidgetState extends State<CleanerChecklistWidget> {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Checklist'.addTranslation,
style: AppTextStyles.heading4.copyWith(
color: context.isDark ? AppColor.neutral30 : AppColor.neutral50,
),
),
InfoHeader16Widget('Checklist'),
16.height,
ListView.separated(
shrinkWrap: true,
@ -93,10 +83,7 @@ class _CleanerChecklistWidgetState extends State<CleanerChecklistWidget> {
children: [
TextSpan(
text: item.title,
style: AppTextStyles.bodyText.copyWith(
color: context.isDark ? AppColor.neutral10 : AppColor.neutral120,
fontWeight: FontWeight.w500,
),
style: AppTextStyles.bodyText2.copyWith(color: AppColor.lightTextColor(context)),
),
if (item.isMandatory)
TextSpan(
@ -175,9 +162,7 @@ class _CleanerChecklistWidgetState extends State<CleanerChecklistWidget> {
labelText: context.translation.comment,
backgroundColor: AppColor.fieldBgColor(context),
showShadow: false,
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(
color: context.isDark ? AppColor.white10 : AppColor.black10,
),
labelStyle: AppTextStyles.textFieldLabelStyle,
alignLabelWithHint: true,
textInputType: TextInputType.multiline,
onChange: (value) {
@ -199,19 +184,7 @@ class _CleanerChecklistWidgetState extends State<CleanerChecklistWidget> {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Captured Image'.addTranslation,
style: AppTextStyles.heading6.copyWith(
color: context.isDark ? AppColor.neutral30 : AppColor.neutral50,
),
),
// Text(
// '(${widget.capturedImages.length}/$maxImages)',
// style: AppTextStyles.bodyText.copyWith(
// color: context.isDark ? AppColor.neutral30 : AppColor.neutral50,
// fontWeight: FontWeight.w600,
// ),
// ),
InfoHeader16Widget('Captured Image'),
],
),
8.height,
@ -227,28 +200,30 @@ class _CleanerChecklistWidgetState extends State<CleanerChecklistWidget> {
if (widget.capturedImages.isEmpty) {
// Show add image button when no image
return GestureDetector(
onTap: widget.isClosed ? null : () async {
// Only allow camera - pick one image at a time
final pickedFile = await ImagePicker().pickImage(
source: ImageSource.camera,
imageQuality: 70,
maxWidth: 800,
maxHeight: 800,
);
onTap: widget.isClosed
? null
: () async {
// Only allow camera - pick one image at a time
final pickedFile = await ImagePicker().pickImage(
source: ImageSource.camera,
imageQuality: 70,
maxWidth: 800,
maxHeight: 800,
);
if (pickedFile != null) {
final bytes = await pickedFile.readAsBytes();
final base64Image = base64Encode(bytes);
final fileName = pickedFile.path.split("/").last;
final formattedImage = "$fileName|$base64Image";
if (pickedFile != null) {
final bytes = await pickedFile.readAsBytes();
final base64Image = base64Encode(bytes);
final fileName = pickedFile.path.split("/").last;
final formattedImage = "$fileName|$base64Image";
// Add to existing images (max 2)
final updatedImages = List<String>.from(widget.capturedImages);
updatedImages.add(formattedImage);
// Add to existing images (max 2)
final updatedImages = List<String>.from(widget.capturedImages);
updatedImages.add(formattedImage);
widget.onImagesChanged?.call(updatedImages);
}
},
widget.onImagesChanged?.call(updatedImages);
}
},
child: Container(
height: 120,
width: 120,
@ -270,12 +245,14 @@ class _CleanerChecklistWidgetState extends State<CleanerChecklistWidget> {
color: context.isDark ? AppColor.white10 : AppColor.black10,
),
4.height,
Text(
'Add Image',
style: AppTextStyles.tinyFont.copyWith(
color: context.isDark ? AppColor.white10 : AppColor.black10,
),
),
InfoTextLabelWidget(label: 'Add Image'),
// Text(
// 'Add Image',
// style: AppTextStyles.tinyFont.copyWith(
// color: context.isDark ? AppColor.white10 : AppColor.black10,
// ),
// ),
],
),
),
@ -283,8 +260,7 @@ class _CleanerChecklistWidgetState extends State<CleanerChecklistWidget> {
}
// Check if images are URLs from API (like ServiceRequestDetailView does)
final bool hasApiImages = widget.capturedImages.any((img) =>
img.startsWith('http://') || img.startsWith('https://'));
final bool hasApiImages = widget.capturedImages.any((img) => img.startsWith('http://') || img.startsWith('https://'));
// If images are from API (URLs), use FilesList widget like ServiceRequestDetailView
if (hasApiImages && widget.isClosed) {
@ -298,7 +274,8 @@ class _CleanerChecklistWidgetState extends State<CleanerChecklistWidget> {
return MultiImagePicker(
imageUrls: widget.capturedImages,
enabled: !widget.isClosed,
maxImages: 2, // Enforce max 2 images
maxImages: 2,
// Enforce max 2 images
onImageTap: (index, imageUrl) {
// Handle image tap - show in full screen
Navigator.of(context).push(

@ -10,6 +10,9 @@ import 'package:test_sa/models/all_requests_and_count_model.dart';
import 'package:test_sa/models/new_models/dashboard_detail.dart';
import 'package:test_sa/modules/cleaner_module/pages/one_time_task_view.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/views/widgets/item_views/info_date_widget.dart';
import 'package:test_sa/views/widgets/item_views/info_header_widget.dart';
import 'package:test_sa/views/widgets/item_views/info_text_widget.dart';
import 'package:test_sa/views/widgets/requests/request_status.dart';
class OneTimeTaskItemView extends StatelessWidget {
@ -34,33 +37,20 @@ class OneTimeTaskItemView extends StatelessWidget {
backgroundColor: AppColor.getRequestStatusColorByName(context, requestData!.statusName ?? ''),
),
1.width.expanded,
Text(
requestData!.transactionDate?.toServiceRequestCardFormat ?? "",
textAlign: TextAlign.end,
style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50),
),
InfoDateWidget(requestData!.transactionDate ?? ""),
],
),
8.height,
(requestData?.typeTransaction ?? context.translation.recurrentWo).heading5(context),
8.height,
'${context.translation.taskNo}: ${requestData!.requestNo}'.bodyText(context),
if (requestData?.siteName != null) '${context.translation.site}: ${requestData!.siteName}'.bodyText(context),
if (requestData!.buildingName != null) '${context.translation.building}: ${requestData!.buildingName}'.bodyText(context),
if (requestData!.departmentName != null) '${context.translation.department}: ${requestData!.departmentName}'.bodyText(context),
if (requestData!.floorName != null) '${context.translation.floor}: ${requestData!.floorName}'.bodyText(context),
if (requestData!.roomName != null) '${context.translation.room}: ${requestData!.roomName}'.bodyText(context),
8.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)
],
InfoHeaderWidget(requestData?.typeTransaction ?? 'One Time Task'.addTranslation),
InfoTextWidget(label: context.translation.taskNo, value: requestData!.requestNo),
if (requestData?.siteName != null) InfoTextWidget(label: context.translation.site, value: requestData!.siteName),
if (requestData!.buildingName != null) InfoTextWidget(label: context.translation.building, value: requestData!.buildingName),
if (requestData!.departmentName != null) InfoTextWidget(label: context.translation.department, value: requestData!.departmentName),
if (requestData!.floorName != null) InfoTextWidget(label: context.translation.floor, value: requestData!.floorName),
InfoTextWidget(
label: context.translation.room,
value: requestData!.roomName,
showArrow: true,
),
],
).toShadowContainer(context, withShadow: showShadow).onPress(() {
@ -89,38 +79,23 @@ class OneTimeTaskItemView extends StatelessWidget {
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),
),
InfoDateWidget(requestDetails!.date ?? ""),
],
),
8.height,
(requestDetails?.nameOfType ?? context.translation.recurrentWo).heading5(context),
8.height,
'${context.translation.site}: ${requestDetails!.site}'.bodyText(context),
'${context.translation.taskNo}: ${requestDetails!.requestNo}'.bodyText(context),
if (requestDetails!.siteName != null) '${context.translation.site}: ${requestDetails!.siteName}'.bodyText(context),
if (requestDetails!.buildingName != null) '${context.translation.building}: ${requestDetails!.buildingName}'.bodyText(context),
if (requestDetails!.departmentName != null) '${context.translation.department}: ${requestDetails!.departmentName}'.bodyText(context),
if (requestDetails!.floorName != null) '${context.translation.floor}: ${requestDetails!.floorName}'.bodyText(context),
if (requestDetails!.roomName != null) '${context.translation.room}: ${requestDetails!.roomName}'.bodyText(context),
8.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)
],
InfoHeaderWidget(requestDetails?.nameOfType ?? 'One Time Task'.addTranslation),
InfoTextWidget(label: context.translation.taskNo, value: requestDetails!.requestNo),
if (requestDetails!.siteName != null) InfoTextWidget(label: context.translation.site, value: requestDetails!.siteName),
if (requestDetails!.buildingName != null) InfoTextWidget(label: context.translation.building, value: requestDetails!.buildingName),
if (requestDetails!.departmentName != null) InfoTextWidget(label: context.translation.department, value: requestDetails!.departmentName),
if (requestDetails!.floorName != null) InfoTextWidget(label: context.translation.floor, value: requestDetails!.floorName),
InfoTextWidget(
label: context.translation.room,
value: requestDetails!.roomName,
showArrow: true,
),
],
).toShadowContainer(context, withShadow: showShadow).onPress(() async {
// Navigate to editable view for in-progress tasks
Navigator.push(
context,
MaterialPageRoute(

@ -1,14 +1,9 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart';
import 'package:test_sa/controllers/providers/settings/setting_provider.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/all_requests_and_count_model.dart';
import 'package:test_sa/models/enums/user_types.dart';
import 'package:test_sa/models/new_models/dashboard_detail.dart';
import 'package:test_sa/modules/cleaner_module/pages/cleaner_search_details_view.dart';
import 'package:test_sa/modules/pm_module/recurrent_wo/recurrent_work_order_view.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/views/widgets/item_views/info_date_widget.dart';
@ -25,7 +20,6 @@ class RecurrentWoItemView extends StatelessWidget {
@override
Widget build(BuildContext context) {
final user = Provider.of<UserProvider>(context, listen: false).user;
if (requestData != null) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
@ -49,15 +43,14 @@ class RecurrentWoItemView extends StatelessWidget {
],
),
8.height,
InfoHeaderWidget(requestData?.typeTransaction ?? context.translation.recurrentWo),
InfoTextWidget(label: context.translation.taskNo, value: requestData!.requestNo, showArrow: true),
// todo @waseem replace below code to infotextwidget
// if (requestData?.siteName != null) '${context.translation.site}: ${requestData!.siteName}'.bodyText(context),
// if (requestData!.buildingName != null) '${context.translation.building}: ${requestData!.buildingName}'.bodyText(context),
// if (requestData!.departmentName != null) '${context.translation.department}: ${requestData!.departmentName}'.bodyText(context),
// if (requestData!.floorName != null) '${context.translation.floor}: ${requestData!.floorName}'.bodyText(context),
// if (requestData!.roomName != null) '${context.translation.room}: ${requestData!.roomName}'.bodyText(context),
InfoTextWidget(label: context.translation.taskNo, value: requestData!.requestNo),
InfoTextWidget(label: context.translation.taskNo, value: requestData!.requestNo),
if (requestData?.siteName != null) InfoTextWidget(label: context.translation.site, value: requestData!.siteName),
if (requestData!.buildingName != null) InfoTextWidget(label: context.translation.building, value: requestData!.buildingName),
if (requestData!.departmentName != null) InfoTextWidget(label: context.translation.department, value: requestData!.departmentName),
if (requestData!.floorName != null) InfoTextWidget(label: context.translation.floor, value: requestData!.floorName),
if (requestData!.roomName != null) InfoTextWidget(label: context.translation.room, value: requestData!.roomName, showArrow: true),
],
).toShadowContainer(context, withShadow: showShadow).onPress(() {
Navigator.of(context).push(MaterialPageRoute(builder: (_) => RecurrentWorkOrderView(taskId: requestData!.id)));
@ -88,15 +81,15 @@ class RecurrentWoItemView extends StatelessWidget {
),
8.height,
InfoHeaderWidget(requestDetails?.nameOfType ?? context.translation.recurrentWo),
InfoTextWidget(label: context.translation.site, value: requestDetails!.site),
InfoTextWidget(label: context.translation.taskNo, value: requestDetails!.requestNo, showArrow: true),
// todo @waseem replace below code to infotextwidget
// if (requestDetails!.siteName != null) '${context.translation.site}: ${requestDetails!.siteName}'.bodyText(context),
// if (requestDetails!.buildingName != null) '${context.translation.building}: ${requestDetails!.buildingName}'.bodyText(context),
// if (requestDetails!.departmentName != null) '${context.translation.department}: ${requestDetails!.departmentName}'.bodyText(context),
// if (requestDetails!.floorName != null) '${context.translation.floor}: ${requestDetails!.floorName}'.bodyText(context),
// if (requestDetails!.roomName != null) '${context.translation.room}: ${requestDetails!.roomName}'.bodyText(context),
InfoTextWidget(
label: context.translation.taskNo,
value: requestDetails!.requestNo,
),
if (requestDetails!.siteName != null) InfoTextWidget(label: context.translation.site, value: requestDetails!.siteName),
if (requestDetails!.buildingName != null) InfoTextWidget(label: context.translation.building, value: requestDetails!.buildingName),
if (requestDetails!.departmentName != null) InfoTextWidget(label: context.translation.department, value: requestDetails!.departmentName),
if (requestDetails!.floorName != null) InfoTextWidget(label: context.translation.floor, value: requestDetails!.floorName),
if (requestDetails!.roomName != null) InfoTextWidget(label: context.translation.room, value: requestDetails!.roomName, showArrow: true),
],
).toShadowContainer(context, withShadow: showShadow).onPress(() async {
Navigator.of(context).push(MaterialPageRoute(builder: (_) => RecurrentWorkOrderView(taskId: requestDetails!.id)));

Loading…
Cancel
Save