import 'dart:io'; import 'package:flutter/material.dart'; import 'package:image_cropper/image_cropper.dart'; import 'package:image_picker/image_picker.dart'; import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; import 'package:table_calendar/table_calendar.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/text_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/user.dart'; import 'package:test_sa/models/user_rota_model.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_dashed_button.dart'; import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; import 'package:test_sa/views/pages/user/update_user_contact_info_bottomsheet.dart'; import '../../../new_views/app_style/app_color.dart'; class ProfilePage extends StatefulWidget { static const String id = "/user/profile"; const ProfilePage({Key? key}) : super(key: key); @override _ProfilePageState createState() => _ProfilePageState(); } class _ProfilePageState extends State { late UserProvider _userProvider; late DateTime _initialDate, _firstDate, _lastDate; User _user = User(); bool _firstTime = true; final GlobalKey _formKey = GlobalKey(); final GlobalKey _scaffoldKey = GlobalKey(); bool isTodayRota = true; @override void initState() { super.initState(); _initialDate = DateTime.now(); _firstDate = DateTime.utc(2010, 10, 16); _lastDate = DateTime.utc(2030, 3, 14); } @override Widget build(BuildContext context) { _userProvider = Provider.of(context); // _settingProvider = Provider.of(context); // _width = MediaQuery.of(context).size.width; // _height = MediaQuery.of(context).size.height; if (_firstTime) { _user = User.fromJsonCons(_userProvider.user!.toJson()); _firstTime = false; } Color color = context.isDark ? AppColor.neutral10 : AppColor.neutral50; return Scaffold( key: _scaffoldKey, appBar: DefaultAppBar(title: context.translation.myProfile), body: Column( children: [ ListView( padding: const EdgeInsets.all(16), children: [ Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( width: double.infinity, child: Column( mainAxisSize: MainAxisSize.min, children: [ Consumer(builder: (context, snapshot, _) { return Stack( alignment: Alignment.bottomRight, children: [ CircleAvatar( radius: 45, backgroundColor: const Color(0xFFE4E5E6), child: Padding( padding: const EdgeInsets.all(1), // Border radius child: ClipOval( child: snapshot.profileImage != null ? Image.file(snapshot.profileImage!) : (snapshot.user!.profilePhotoName?.isNotEmpty ?? false) ? Image.network(snapshot.user!.profilePhotoName!) : const Icon( Icons.person, size: 50, color: Colors.white, ), ), ), ), // CircleAvatar( // radius: 14, // backgroundColor: AppColor.primary70, // child: Padding( // padding: const EdgeInsets.all(1), // Border radius // child: snapshot.isLoading // ? const SizedBox(height: 16, width: 16, child: CircularProgressIndicator(color: Colors.white, strokeWidth: 2)) // : const Icon(Icons.upload, size: 16, color: Colors.white), // ), // ).onPress(snapshot.isLoading // ? null // : () async { // final pickedFile = await ImagePicker().pickImage(source: ImageSource.gallery, imageQuality: 70, maxWidth: 800, maxHeight: 800); // // if (pickedFile != null) { // CroppedFile? croppedFile = await ImageCropper().cropImage( // sourcePath: pickedFile.path, // aspectRatio: CropAspectRatio(ratioX: 1, ratioY: 1), // uiSettings: [ // AndroidUiSettings( // toolbarTitle: 'ATOMS', // toolbarColor: Colors.white, // toolbarWidgetColor: color, // initAspectRatio: CropAspectRatioPreset.square, // lockAspectRatio: false, // ), // IOSUiSettings(title: 'ATOMS'), // ], // ); // if (croppedFile != null) { // await snapshot.uploadProfileImage(_user.userID!, File(croppedFile.path)); // Provider.of(context, listen: false).setUser(_userProvider.user!); // } // } // }), ], ); }), 8.height, (_user.username ?? "").heading3(context).custom(fontWeight: FontWeight.w600, color: context.isDark ? AppColor.neutral10 : AppColor.neutral50), ], ), ), 16.height, Text( '${context.translation.email}: ${_user.email ?? "-"}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), Text( '${context.translation.phoneNumber}: ${_user.phoneNumber ?? "-"}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), Text( '${context.translation.extensionNo}: ${_user.extensionNo ?? "-"}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), // if ((_user.phoneNumber ?? "").isNotEmpty) ...[ // const Divider().defaultStyle(context), // 8.height, // (_user.phoneNumber??"").heading5(context), // 8.height, // ], // if ((_user.extensionNo ?? "").isNotEmpty) ...[ // const Divider().defaultStyle(context), // 8.height, // _user.extensionNo!.heading5(context), // 8.height, // ], if ((_user.departmentName?.length ?? 0) > 0) const Divider().defaultStyle(context), ListView.builder( physics: const NeverScrollableScrollPhysics(), itemCount: _user.departmentName?.length ?? 0, shrinkWrap: true, padding: EdgeInsets.zero, itemBuilder: (context, index) { return Text( _user.departmentName![index] ?? "N/A", style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ).paddingOnly(top: 2, bottom: 2); }, ), if ((_user.clientName ?? "").isNotEmpty) ...[ const Divider().defaultStyle(context), 8.height, _user.clientName!.heading5(context).custom(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50), 8.height, ], Selector( selector: (_, myModel) => myModel.isLoading, // Selects only the userName builder: (_, isLoading, __) { return AppDashedButton( title: isLoading ? "Uploading..." : "Update Image", height: 50, width: MediaQuery.sizeOf(context).width / 2, padding: EdgeInsets.all(4), icon: isLoading ? const SizedBox(height: 16, width: 16, child: CircularProgressIndicator(color: AppColor.primary10, strokeWidth: 2)) : 'attachment_icon'.toSvgAsset(height: 24, width: 24), buttonColor: AppColor.primary10, onPressed: () async { if (isLoading) return; final pickedFile = await ImagePicker().pickImage(source: ImageSource.gallery, imageQuality: 70, maxWidth: 800, maxHeight: 800); if (pickedFile != null) { CroppedFile? croppedFile = await ImageCropper().cropImage( sourcePath: pickedFile.path, aspectRatio: CropAspectRatio(ratioX: 1, ratioY: 1), uiSettings: [ AndroidUiSettings( toolbarTitle: 'ATOMS', toolbarColor: Colors.white, toolbarWidgetColor: color, initAspectRatio: CropAspectRatioPreset.square, lockAspectRatio: false, ), IOSUiSettings(title: 'ATOMS'), ], ); if (croppedFile != null) { await context.userProvider.uploadProfileImage(_user.userID!, File(croppedFile.path)); Provider.of(context, listen: false).setUser(_userProvider.user!); } } }, ).center; }) ], ).toShadowContainer(context), if (context.settingProvider.isUserFlowMedical) Container( margin: const EdgeInsets.only(top: 16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( "Rota Details", style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), ), 8.width, Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( borderRadius: BorderRadius.circular(8), color: AppColor.primary10, ), child: Text( isTodayRota ? "Monthly " : "Today", style: AppTextStyles.bodyText2.copyWith(color: Colors.white), ), ).onPress(() => setState(() { _initialDate = DateTime.now(); isTodayRota = !isTodayRota; })), ], ), (isTodayRota ? todayRotaWidget() : monthRotaWidget()) ], ).toShadowContainer(context), ), ], ).expanded, FooterActionButton.footerContainer( context: context, child: AppFilledButton( label: "Update Information", buttonColor: context.isDark ? AppColor.primary10 : AppColor.neutral50, onPressed: () { context.showBottomSheet( UpdateUserContactInfoBottomSheet( _userProvider.user!.userID!, uEmail: _user.email, uPhoneNo: _user.phoneNumber, uExtensionNo: _user.extensionNo, onUpdate: (email, phoneNo, extensionNo) { _userProvider.user!.email = email; _userProvider.user!.phoneNumber = phoneNo; _userProvider.user!.extensionNo = extensionNo; _firstTime = true; Provider.of(context, listen: false).setUser(_userProvider.user!); }, ), title: "Update Information"); }, ), ) ], ), ); } Widget todayRotaWidget() { final DateFormat fmt = DateFormat('MM-dd-yyyy'); final String startStr = fmt.format(_initialDate); return FutureBuilder( future: _userProvider.getUserTodayRota(startStr, startStr), builder: (context, snapshot) { bool isLoading = snapshot.connectionState == ConnectionState.waiting; if ((!isLoading && (snapshot.hasError || !snapshot.hasData))) { return const SizedBox(); } return rotaDetailsWidget(isLoading, snapshot.data); }, ); } Widget monthRotaWidget() { final DateTime startOfMonth = DateTime(_initialDate.year, _initialDate.month, 1); final DateTime endOfMonth = DateTime(_initialDate.year, _initialDate.month + 1, 0); final DateFormat fmt = DateFormat('MM-dd-yyyy'); final String startStr = fmt.format(startOfMonth); final String endStr = fmt.format(endOfMonth); return FutureBuilder>( future: _userProvider.getUserMonthlyRota(startStr, endStr), builder: (context, snapshot) { bool isLoading = snapshot.connectionState == ConnectionState.waiting; if ((!isLoading && (snapshot.hasError || !snapshot.hasData))) { return const SizedBox(); } return TableCalendar( firstDay: _firstDate, lastDay: _lastDate, focusedDay: _initialDate, calendarFormat: CalendarFormat.month, weekendDays: const [], rowHeight: 45, pageJumpingEnabled: true, pageAnimationEnabled: true, availableGestures: AvailableGestures.none, onPageChanged: (dateTime) { _initialDate = dateTime; setState(() {}); }, onDaySelected: (selectedDate, focusDate) { final List matches = snapshot.data?.where((e) { final dt = DateTime.tryParse(e.scheduleDate ?? ''); return dt != null && isSameDay(dt, selectedDate); }).toList() ?? []; final UserRotaModel? rota = matches.isNotEmpty ? matches.first : null; if (rota == null) { "No details found".showToast; return; } context.showBottomSheet(rotaDetailsWidget(isLoading, rota), title: "Rota Details".addTranslation); }, calendarBuilders: CalendarBuilders( markerBuilder: (context, date, eventsOnDay) { if (isLoading) return null; final List matches = snapshot.data?.where((e) { final dt = DateTime.tryParse(e.scheduleDate ?? ''); return dt != null && isSameDay(dt, date); }).toList() ?? []; final UserRotaModel? rota = matches.isNotEmpty ? matches.first : null; if (rota == null) return null; return Container( width: 6, height: 6, margin: const EdgeInsets.symmetric(horizontal: 1, vertical: 4), decoration: BoxDecoration( color: rota.leaveTypeCode == "ANNUAL" ? AppColor.red30 : rota.leaveTypeCode == "HOLIDAY" ? AppColor.green15 : AppColor.primary10, shape: BoxShape.circle), ); }, dowBuilder: (context, dateTime) { final day = DateFormat("EE", context.isAr ? "ar" : "en").format(dateTime).toUpperCase(); return Align(alignment: Alignment.center, child: day.bodyText(context).custom(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50)); }, defaultBuilder: (_cxt, dateTime, _) { final day = DateFormat("d").format(dateTime); if (isLoading) { return const SizedBox(height: 36, width: 36).toShimmer(isShow: isLoading, context: _cxt); } else { null; } }, ), // eventLoader: (day) { // print("eventLoader:$day"); // return []; // }, daysOfWeekHeight: 35.toScreenHeight, headerStyle: HeaderStyle( leftChevronVisible: true, rightChevronVisible: true, formatButtonVisible: false, titleCentered: true, titleTextStyle: AppTextStyles.bodyText, headerPadding: const EdgeInsets.all(0), ), calendarStyle: CalendarStyle( isTodayHighlighted: false, todayDecoration: const BoxDecoration(color: AppColor.primary10, shape: BoxShape.circle), defaultTextStyle: AppTextStyles.bodyText, defaultDecoration: BoxDecoration(shape: BoxShape.circle, color: context.isDark ? AppColor.neutral50 : AppColor.neutral30), ), ).paddingOnly(top: 16); }, ); } Widget rotaDetailsWidget(bool isLoading, UserRotaModel? userRota) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 16.height, if (isLoading) ...[ Text( 'Shift Start Time Time', style: AppTextStyles.bodyText.copyWith(color: context.isDarkNotListen ? AppColor.neutral10 : AppColor.neutral120), ).toShimmer(context: context, isShow: isLoading), 4.height, Text( 'Shift Actual Actual Start Time', style: AppTextStyles.bodyText.copyWith(color: context.isDarkNotListen ? AppColor.neutral10 : AppColor.neutral120), ).toShimmer(context: context, isShow: isLoading) ] else Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ // Text( // 'Site: ${_user.clientName ?? "-"}', // style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), // ), Text( 'Shift Name: ${userRota!.shiftName ?? "-"}', style: AppTextStyles.bodyText.copyWith(color: context.isDarkNotListen ? AppColor.neutral10 : AppColor.neutral120), ), Text( 'Break: ${userRota.breakTime ?? "-"}', style: AppTextStyles.bodyText.copyWith(color: context.isDarkNotListen ? AppColor.neutral10 : AppColor.neutral120), ), if (userRota.leaveTypeCode?.isNotEmpty ?? false) SizedBox( width: double.infinity, child: Column(children: [ 8.height, Text( userRota.leaveTypeCode ?? "", style: AppTextStyles.heading6.copyWith(color: context.isDarkNotListen ? AppColor.neutral10 : AppColor.neutral120, fontWeight: FontWeight.w600), ), Text( userRota.leaveDescription ?? "", style: AppTextStyles.bodyText.copyWith(color: context.isDarkNotListen ? AppColor.neutral10 : AppColor.neutral120), ), ]), ) else ...[ Text( 'Shift Start Time: ${userRota.shiftName?.split('-').first.trim() ?? "-"}', style: AppTextStyles.bodyText.copyWith(color: context.isDarkNotListen ? AppColor.neutral10 : AppColor.neutral120), ), Text( 'Shift End Time: ${userRota.shiftName?.split('-').last.trim() ?? "-"}', style: AppTextStyles.bodyText.copyWith(color: context.isDarkNotListen ? AppColor.neutral10 : AppColor.neutral120), ), const Divider().defaultStyle(context), Text( 'Swipe In: ${userRota.shTActualStartTime?.toTime ?? "-"}', style: AppTextStyles.bodyText.copyWith(color: context.isDarkNotListen ? AppColor.neutral10 : AppColor.neutral120), ), Text( 'Swipe Out: ${userRota.shTActualEndTime?.toTime ?? "-"}', style: AppTextStyles.bodyText.copyWith(color: context.isDarkNotListen ? AppColor.neutral10 : AppColor.neutral120), ), ], ], ), ], ); } }