fist commit ftc staff app clone
This commit is contained in:
@@ -0,0 +1,241 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/models/clients/HealthIssuesDetailsModel.dart';
|
||||
import 'package:ftc_mobile_app/models/profileData/user_data.dart';
|
||||
import 'package:ftc_mobile_app/utilities/enums/body_parts.dart';
|
||||
import 'package:ftc_mobile_app/view/custom_widgets/custom_app_bar_with_action.dart';
|
||||
import 'package:ftc_mobile_app/view/custom_widgets/human_body_mapper_widget.dart';
|
||||
import 'package:ftc_mobile_app/view/custom_widgets/my_circle_image.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import '../add_details_to_new_body_point_screen.dart';
|
||||
import 'widget/IssueDetailPopupWidget.dart';
|
||||
|
||||
class CurrentHealthIssuesScreen extends StatefulWidget {
|
||||
final UserData userData;
|
||||
|
||||
const CurrentHealthIssuesScreen({Key? key, required this.userData})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
State<CurrentHealthIssuesScreen> createState() =>
|
||||
_CurrentHealthIssuesScreenState();
|
||||
}
|
||||
|
||||
class _CurrentHealthIssuesScreenState extends State<CurrentHealthIssuesScreen> {
|
||||
final CurrentHealthIssuesScreenController controller =
|
||||
Get.put(CurrentHealthIssuesScreenController());
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
controller.serviceUserId = widget.userData.id!;
|
||||
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DefaultTabController(
|
||||
length: controller.tabs.length,
|
||||
child: CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
onBackButton: () => controller.onBackPress(context),
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
sideDrawer: const CustomDrawer(),
|
||||
showAppBar: true,
|
||||
appBar: _appBar(context),
|
||||
body: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
//User details
|
||||
serviceUserDetailWidget(),
|
||||
|
||||
Divider(
|
||||
height: 1,
|
||||
color: CustomAppColors.kLightGreyColor,
|
||||
),
|
||||
TabBar(
|
||||
onTap: (i) {
|
||||
controller.onTabChange(controller.tabs[i]);
|
||||
},
|
||||
tabs: controller.tabs
|
||||
.map((e) => Tab(
|
||||
text: e,
|
||||
))
|
||||
.toList()),
|
||||
Divider(
|
||||
height: 1,
|
||||
color: CustomAppColors.kLightGreyColor,
|
||||
),
|
||||
8.verticalSpace,
|
||||
Obx(() {
|
||||
final entries = controller.issueBodyParts.entries;
|
||||
|
||||
if (entries.isEmpty) {
|
||||
return FrequentFunctions.noWidget;
|
||||
}
|
||||
|
||||
final map = <BodyPart, Color?>{};
|
||||
for (var e in entries) {
|
||||
map[e.key] = e.value.color;
|
||||
}
|
||||
|
||||
return HumanBodyWidget(
|
||||
visibleBodyPoints: map,
|
||||
width: Get.width * 0.9,
|
||||
onPointTap: (b, p) {
|
||||
RenderBox? overlay = Overlay.of(context)
|
||||
.context
|
||||
.findRenderObject() as RenderBox?;
|
||||
|
||||
showMenu(
|
||||
context: context,
|
||||
surfaceTintColor: Colors.white,
|
||||
position: RelativeRect.fromRect(
|
||||
p & const Size(40, 40),
|
||||
// Smaller rect, the touch area
|
||||
Offset.zero &
|
||||
(overlay?.size ??
|
||||
Get.mediaQuery
|
||||
.size), // Bigger rect, the entire screen
|
||||
),
|
||||
items: [
|
||||
PopupMenuItem(
|
||||
padding: EdgeInsets.zero,
|
||||
child: IssueDetailPopupWidget(
|
||||
userData: widget.userData,
|
||||
data: controller.issueBodyParts[b]!.data,
|
||||
onActionChange: (status, data) {
|
||||
if (data.status != status) {
|
||||
controller.updateHealthIssueStatus(
|
||||
bodyPoint: b, data: data, status: status);
|
||||
}
|
||||
},
|
||||
onUpdateButtonTap: (data) async {
|
||||
Get.back();
|
||||
onAddOrUpdateButtonTap(context, data);
|
||||
},
|
||||
),
|
||||
),
|
||||
]);
|
||||
},
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
AppBar _appBar(BuildContext context) {
|
||||
return CustomAppBarWithAction(
|
||||
context,
|
||||
titleText: "Current Health Issues",
|
||||
actionText: '+ Add New',
|
||||
onActionTap: () => onAddOrUpdateButtonTap(context),
|
||||
);
|
||||
}
|
||||
|
||||
Widget serviceUserDetailWidget() {
|
||||
return Padding(
|
||||
padding: REdgeInsets.symmetric(horizontal: 20),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Align(
|
||||
alignment: Alignment.center,
|
||||
child: MyCircleImage(
|
||||
imageSize: 80.r,
|
||||
url:
|
||||
"${WebUrls.baseUrl}${widget.userData.profilePictureUrl ?? ""}",
|
||||
errorWidget: CustomImageWidget(
|
||||
imagePath: AssetsManager.kPersonMainIcon,
|
||||
height: 53.r,
|
||||
width: 53.r,
|
||||
),
|
||||
),
|
||||
),
|
||||
10.verticalSpace,
|
||||
CustomTextWidget(
|
||||
text: widget.userData.displayName,
|
||||
fontSize: 14.sp,
|
||||
fontWeight: FontWeight.w600),
|
||||
32.verticalSpace,
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: _labelValueWidgets(
|
||||
'Email:',
|
||||
widget.userData.email ?? "",
|
||||
),
|
||||
)),
|
||||
8.horizontalSpace,
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: _labelValueWidgets(
|
||||
'Contact Number:',
|
||||
widget.userData.modelId?.phoneNo ?? "",
|
||||
),
|
||||
)),
|
||||
],
|
||||
),
|
||||
16.verticalSpace,
|
||||
..._labelValueWidgets(
|
||||
'Address 1:',
|
||||
widget.userData.modelId?.suAddress1 ?? "",
|
||||
),
|
||||
16.verticalSpace,
|
||||
..._labelValueWidgets(
|
||||
'Address 2:',
|
||||
widget.userData.modelId?.suAddress2 ?? "",
|
||||
),
|
||||
16.verticalSpace,
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> _labelValueWidgets(String label, String value) {
|
||||
return [
|
||||
CustomTextWidget(
|
||||
textAlign: TextAlign.left,
|
||||
isExpanded: false,
|
||||
text: label,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontColor: CustomAppColors.kLightTextColor,
|
||||
fontSize: 12.sp),
|
||||
4.verticalSpace,
|
||||
CustomTextWidget(
|
||||
textAlign: TextAlign.left,
|
||||
text: value,
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontColor: CustomAppColors.kBlackColor,
|
||||
fontSize: 13.sp),
|
||||
];
|
||||
}
|
||||
|
||||
Future<void> onAddOrUpdateButtonTap(BuildContext context,
|
||||
[HealthIssueDetailsModel? data]) async {
|
||||
dynamic result = await Navigator.of(context)
|
||||
.pushNamed(CustomRouteNames.kAddDetailsToNewPointScreenRoute,
|
||||
arguments: AddDetailsToNewBodyPointScreenArgs(
|
||||
userData: widget.userData,
|
||||
issueData: data,
|
||||
));
|
||||
if (result == true) {
|
||||
controller.getPointsDataFromService();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,260 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import 'package:ftc_mobile_app/models/clients/HealthIssuesDetailsModel.dart';
|
||||
import 'package:ftc_mobile_app/models/profileData/user_data.dart';
|
||||
import 'package:ftc_mobile_app/utilities/extensions/custom_extensions.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
class IssueDetailPopupWidget extends StatefulWidget {
|
||||
const IssueDetailPopupWidget({
|
||||
super.key,
|
||||
required this.userData,
|
||||
required this.data,
|
||||
required this.onActionChange,
|
||||
required this.onUpdateButtonTap,
|
||||
});
|
||||
|
||||
final UserData userData;
|
||||
final HealthIssueDetailsModel data;
|
||||
final Function(bool status, HealthIssueDetailsModel data) onActionChange;
|
||||
final Function(HealthIssueDetailsModel data) onUpdateButtonTap;
|
||||
|
||||
static const actionActive = "Active";
|
||||
static const actionResolved = "Resolved";
|
||||
|
||||
@override
|
||||
State<IssueDetailPopupWidget> createState() => _IssueDetailPopupWidgetState();
|
||||
}
|
||||
|
||||
class _IssueDetailPopupWidgetState extends State<IssueDetailPopupWidget> {
|
||||
final Map<String, bool> actionsMap = {
|
||||
IssueDetailPopupWidget.actionActive: true,
|
||||
IssueDetailPopupWidget.actionResolved: false
|
||||
};
|
||||
|
||||
String selectedValue = IssueDetailPopupWidget.actionActive;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
selectedValue = widget.data.status
|
||||
? IssueDetailPopupWidget.actionActive
|
||||
: IssueDetailPopupWidget.actionResolved;
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: Get.width,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
width: double.maxFinite,
|
||||
padding: REdgeInsets.symmetric(horizontal: 12),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Health Note',
|
||||
style: TextStyle(
|
||||
fontSize: 12.sp,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
CustomTextWidget(
|
||||
text: widget.data.healthNote,
|
||||
fontSize: 14.sp,
|
||||
fontWeight: FontWeight.bold,
|
||||
textAlign: TextAlign.left,
|
||||
isExpanded: false),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
width: 90.r,
|
||||
height: 32.r,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: 24.toRadius(),
|
||||
color: (selectedValue ==
|
||||
IssueDetailPopupWidget.actionActive)
|
||||
? Colors.red.withOpacity(0.3)
|
||||
: Colors.green.withOpacity(0.3),
|
||||
),
|
||||
child: DropdownButtonHideUnderline(
|
||||
child: DropdownButtonFormField(
|
||||
onTap: () {
|
||||
FocusScopeNode().unfocus();
|
||||
},
|
||||
value: selectedValue,
|
||||
dropdownColor: Colors.white,
|
||||
borderRadius: 4.toRadius(),
|
||||
decoration: InputDecoration(
|
||||
isDense: true,
|
||||
border: InputBorder.none,
|
||||
suffixIcon: Icon(Icons.arrow_drop_down_sharp,
|
||||
size: 18,
|
||||
color: (selectedValue ==
|
||||
IssueDetailPopupWidget.actionActive)
|
||||
? Colors.red
|
||||
: Colors.green)
|
||||
.paddingOnly(right: 12.r),
|
||||
suffixIconConstraints: BoxConstraints.tightFor(
|
||||
width: 24.r, height: 32.r),
|
||||
// contentPadding: REdgeInsets.only(left: 0),
|
||||
),
|
||||
elevation: 4,
|
||||
icon: FrequentFunctions.noWidget,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 10.sp,
|
||||
color: Colors.black),
|
||||
hint: Text(
|
||||
"Select...",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 12.sp,
|
||||
color: CustomAppColors.kLightTextColor,
|
||||
),
|
||||
),
|
||||
selectedItemBuilder: (_) {
|
||||
return actionsMap.keys.map(
|
||||
(e) {
|
||||
return DropdownMenuItem<String>(
|
||||
value: e,
|
||||
child: Container(
|
||||
// color: (selectedValue == e)
|
||||
// ? (selectedValue ==
|
||||
// IssueDetailPopupWidget
|
||||
// .actionActive)
|
||||
// ? Colors.red.withOpacity(0.3)
|
||||
// : Colors.green.withOpacity(0.3)
|
||||
// : Colors.white,
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
e,
|
||||
style: TextStyle(
|
||||
color: (selectedValue == e)
|
||||
? (selectedValue ==
|
||||
IssueDetailPopupWidget
|
||||
.actionActive)
|
||||
? Colors.red
|
||||
: Colors.green
|
||||
: Colors.black),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
).toList();
|
||||
},
|
||||
items: actionsMap.keys
|
||||
.map(
|
||||
(e) => DropdownMenuItem<String>(
|
||||
value: e,
|
||||
child: Text(e),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
// padding: EdgeInsets.zero,
|
||||
isExpanded: true,
|
||||
// iconSize: 20.h,
|
||||
// icon: Padding(
|
||||
// padding: REdgeInsets.only(right: 0.0),
|
||||
// child: Icon(Icons.arrow_drop_down_sharp,
|
||||
// size: 18,
|
||||
// color: Colors.black),
|
||||
// ),
|
||||
onChanged: (v) {
|
||||
if (v != null) {
|
||||
setState(() {
|
||||
selectedValue = v;
|
||||
widget.onActionChange(
|
||||
actionsMap[v]!, widget.data);
|
||||
});
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
8.verticalSpace,
|
||||
Divider(
|
||||
height: 1,
|
||||
color: Colors.grey.withOpacity(0.3),
|
||||
),
|
||||
Container(
|
||||
width: double.maxFinite,
|
||||
padding: REdgeInsets.symmetric(horizontal: 12, vertical: 12),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text.rich(
|
||||
textAlign: TextAlign.left,
|
||||
TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: "Complaint: ",
|
||||
style: TextStyle(
|
||||
fontSize: 12.sp, fontWeight: FontWeight.w600),
|
||||
),
|
||||
TextSpan(
|
||||
text: widget.data.complaint,
|
||||
style: TextStyle(
|
||||
fontSize: 12.sp, fontWeight: FontWeight.w400),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
4.verticalSpace,
|
||||
Text.rich(
|
||||
textAlign: TextAlign.left,
|
||||
TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: "Last Update: ",
|
||||
style: TextStyle(
|
||||
fontSize: 12.sp, fontWeight: FontWeight.w600),
|
||||
),
|
||||
TextSpan(
|
||||
text: DateFormat("MMM/dd/yyyy").format(
|
||||
DateTime.parse(widget.data.updatedAt)
|
||||
.toLocal()),
|
||||
style: TextStyle(
|
||||
fontSize: 12.sp, fontWeight: FontWeight.w400),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
16.verticalSpace,
|
||||
Center(
|
||||
child: SizedBox(
|
||||
width: 120.r,
|
||||
height: 32.r,
|
||||
child: CustomAppButton(
|
||||
onTap: () => widget.onUpdateButtonTap(widget.data),
|
||||
buttonText: "Update",
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user