import 'dart:typed_data'; import 'package:file_picker/file_picker.dart'; import 'package:prosapp_web_app/models/location_preferences.dart'; import 'package:prosapp_web_app/models/schedules_entity.dart'; import 'package:prosapp_web_app/models/usuario.dart'; import 'package:prosapp_web_app/providers/auth_provider.dart'; import 'package:prosapp_web_app/providers/professional_form_provider.dart'; import 'package:prosapp_web_app/providers/professional_provider.dart'; import 'package:prosapp_web_app/providers/profile_form_provider.dart'; import 'package:prosapp_web_app/providers/settings_provider.dart'; import 'package:prosapp_web_app/router/router.dart'; import 'package:prosapp_web_app/services/navigation_service.dart'; import 'package:prosapp_web_app/services/notifications_service.dart'; import 'package:prosapp_web_app/ui/cards/white_card.dart'; import 'package:prosapp_web_app/ui/inputs/custom_inputs.dart'; import 'package:prosapp_web_app/ui/labels/custom_labels.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; class ProfessionalProfileView extends StatefulWidget { const ProfessionalProfileView({super.key}); @override State createState() => _ProfessionalProfileViewState(); } class _ProfessionalProfileViewState extends State { Usuario? user; late ProfessionalFormProvider professionalFormProvider; @override void initState() { super.initState(); final authProvider = Provider.of(context, listen: false); final profileFormProvider = Provider.of(context, listen: false); professionalFormProvider = Provider.of(context, listen: false); final proProvider = Provider.of(context, listen: false); proProvider.getProfessional(authProvider.user!.id).then((value) { professionalFormProvider.setProfesional(value); }); profileFormProvider.user = authProvider.user; setState(() { user = authProvider.user; }); } @override Widget build(BuildContext context) { return LayoutBuilder(builder: (context, constraints) { if (constraints.maxWidth < 700) { return ListView( physics: const ClampingScrollPhysics(), children: const [SizedBox(height: 10), _ProfileViewBody()], ); } else { return Container( padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10), child: ListView( physics: const ClampingScrollPhysics(), children: const [SizedBox(height: 10), _ProfileViewBody()], ), ); } }); } } class _ProfileViewBody extends StatelessWidget { const _ProfileViewBody(); @override Widget build(BuildContext context) { return Center( child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 900), child: const Column( children: [ _AvatarContainer(containerFull: true), _ProfileViewForm(), ], ), ), ); } } class _ProfileViewForm extends StatefulWidget { const _ProfileViewForm(); @override State<_ProfileViewForm> createState() => _ProfileViewFormState(); } class _ProfileViewFormState extends State<_ProfileViewForm> { bool _serviceDeliverySwitchValue = false; bool _serviceSiteSwitchValue = false; bool _serviceRateSwitchValue = false; bool first = true; @override Widget build(BuildContext context) { final profileFormProvider = Provider.of(context); final settingsProvider = Provider.of(context); final user = profileFormProvider.user!; return Consumer( builder: (context, professionalFormProvider, child) { if (professionalFormProvider.profesional == null) { return const Center( child: CircularProgressIndicator(), ); } if (settingsProvider.settings == null) { return const Center( child: CircularProgressIndicator(), ); } final settings = settingsProvider.settings!; final profesional = professionalFormProvider.profesional!; if (first) { first = false; if (settings.tarifas) { _serviceRateSwitchValue = profesional.ratePreferences; } else { _serviceRateSwitchValue = false; } if (profesional.locationPreferences == LocationPreferences.both) { _serviceSiteSwitchValue = true; _serviceDeliverySwitchValue = true; } else if (profesional.locationPreferences == LocationPreferences.office) { _serviceSiteSwitchValue = true; _serviceDeliverySwitchValue = false; } else if (profesional.locationPreferences == LocationPreferences.delivery) { _serviceSiteSwitchValue = false; _serviceDeliverySwitchValue = true; } } return LayoutBuilder(builder: (context, constraints) { double columnWidth = constraints.maxWidth < 600 ? 95 : 150; return WhiteCard( title: 'Información profesional', child: Form( key: professionalFormProvider.profileFormKey, autovalidateMode: AutovalidateMode.always, child: Column( children: [ const SizedBox(height: 10), SwitchListTile( title: const Text('Servicio a domicilio'), value: _serviceDeliverySwitchValue, onChanged: (value) { setState(() { _serviceDeliverySwitchValue = value; if (settings.domicilios == true) { _serviceDeliverySwitchValue = value; if (!_serviceDeliverySwitchValue) { _serviceSiteSwitchValue = true; } } else { _serviceDeliverySwitchValue = false; } }); }, ), const SizedBox(height: 10), SwitchListTile( title: const Text('Servicio en sitio / consultorio'), value: _serviceSiteSwitchValue, onChanged: (value) { setState(() { if (settings.domicilios == true) { _serviceSiteSwitchValue = value; if (!_serviceSiteSwitchValue) { _serviceDeliverySwitchValue = true; } } else { _serviceSiteSwitchValue = true; _serviceDeliverySwitchValue = false; } }); }, ), if (_serviceSiteSwitchValue) Column( children: [ TextFormField( initialValue: profesional.address, // validator: (value) { // if (value == null || value.isEmpty) { // return 'La dirección es obligatoria'; // } // return null; // }, onChanged: (value) {}, decoration: CustomInputs.formInputDecoration( hint: 'Ingresa tu dirección', label: 'Dirección', icon: Icons.location_on_outlined, ), ), const SizedBox(height: 12), TextFormField( initialValue: profesional.aditionalAddress, decoration: CustomInputs.formInputDecoration( hint: 'Ingresa tu piso / apartamento / conjunto', label: 'Piso / Apartamento / Conjunto', icon: Icons.email_outlined, ), onChanged: (value) { professionalFormProvider.copyProfesionalWith( aditionalAddress: value); }, ), ], ), if (settings.tarifas == true) ...[ const SizedBox(height: 20), SwitchListTile( title: const Text('Tarifa'), value: _serviceRateSwitchValue, onChanged: (value) { setState(() { _serviceRateSwitchValue = value; }); }, ), if (_serviceRateSwitchValue) Column( children: [ TextFormField( keyboardType: TextInputType.number, initialValue: profesional.rate, validator: (value) { if (value == null || value.isEmpty) { return 'La tarifa es obligatoria'; } final numericRegex = RegExp(r'^[0-9]+$'); if (!numericRegex.hasMatch(value)) { return 'Por favor, ingresa solo números'; } return null; }, onChanged: (value) { professionalFormProvider.copyProfesionalWith( rate: value); }, decoration: CustomInputs.formInputDecoration( hint: 'Ingresa la tarifa del servicio', label: 'Tarifa', icon: Icons.attach_money, ), ), ], ), ], const SizedBox(height: 20), Text('Metodos de pago', style: CustomLabels.h3), CheckboxListTile( title: const Text('Datafono'), value: profesional.paymentMethods.datafono, onChanged: (value) { professionalFormProvider.copyProfesionalWith( paymentMethods: profesional.paymentMethods .copyWith(datafono: value)); }), const SizedBox(height: 10), CheckboxListTile( title: const Text('Nequi'), value: profesional.paymentMethods.nequi, onChanged: (value) { professionalFormProvider.copyProfesionalWith( paymentMethods: profesional.paymentMethods .copyWith(nequi: value)); }), const SizedBox(height: 10), CheckboxListTile( title: const Text('Transferencia bancaria'), value: profesional.paymentMethods.transferencia, onChanged: (value) { professionalFormProvider.copyProfesionalWith( paymentMethods: profesional.paymentMethods .copyWith(transferencia: value)); }), const SizedBox(height: 20), Text('Horarios de atenciòn', style: CustomLabels.h3), const SizedBox(height: 10), GestureDetector( onTap: () { NavigationService.replaceTo( Flurorouter.professionalScheduleRoute); }, child: MouseRegion( cursor: SystemMouseCursors.click, child: Table( columnWidths: { 0: FixedColumnWidth(columnWidth), }, border: TableBorder.all(color: Colors.grey.withOpacity(0.3)), children: [ _buildTableRow( 'Lunes', profesional.schedules.monday, context), _buildTableRow( 'Martes', profesional.schedules.tuesday, context), _buildTableRow('Miercoles', profesional.schedules.wednesday, context), _buildTableRow( 'Jueves', profesional.schedules.thursday, context), _buildTableRow( 'Viernes', profesional.schedules.friday, context), _buildTableRow( 'Sabado', profesional.schedules.saturday, context), _buildTableRow( 'Domingo', profesional.schedules.sunday, context), ], ), ), ), const SizedBox(height: 20), ConstrainedBox( constraints: const BoxConstraints(maxWidth: 130), child: ElevatedButton( onPressed: () async { LocationPreferences locationPreferences; if (_serviceDeliverySwitchValue && _serviceSiteSwitchValue) { locationPreferences = LocationPreferences.both; } else if (_serviceDeliverySwitchValue) { locationPreferences = LocationPreferences.delivery; } else if (_serviceSiteSwitchValue) { locationPreferences = LocationPreferences.office; } else { locationPreferences = LocationPreferences.office; } professionalFormProvider.copyProfesionalWith( locationPreferences: locationPreferences, ratePreferences: _serviceRateSwitchValue, ); await professionalFormProvider .updateProfesionalProfileInfo(user.id); }, style: ButtonStyle( backgroundColor: WidgetStateProperty.all( Colors.blue.shade400, ), shape: WidgetStateProperty.all(const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(5)), )), shadowColor: WidgetStateProperty.all(Colors.transparent), ), child: const Text( 'Guardar', style: TextStyle(color: Colors.white), ), ), ), const SizedBox(height: 10), ], ), ), ); }); }); } TableRow _buildTableRow( String day, ScheduleEntity schedules, BuildContext context) { return TableRow( children: [ TableCell( child: Container( padding: const EdgeInsets.all(8.0), decoration: const BoxDecoration( color: Colors.blueAccent, ), child: Text( day, style: const TextStyle( fontWeight: FontWeight.bold, color: Colors.white, ), ), ), ), TableCell( child: Container( padding: const EdgeInsets.all(8.0), child: Text( timeList(schedules, context), style: const TextStyle( color: Colors.black87, ), ), ), ), ], ); } String timeList(ScheduleEntity? schedule, BuildContext context) { if (schedule == null) { return 'No hay horarios'; } if (!schedule.enabled) { return 'No hay horarios'; } if (schedule.range1Hour1 == null || schedule.range2Hour2 == null) { return 'No hay horarios'; } if (schedule.continuousDay) { return '${ScheduleEntity.getFormatTime(schedule.range1Hour1)} a ${ScheduleEntity.getFormatTime(schedule.range2Hour2)}'; } else { if (schedule.range1Hour2 == null || schedule.range2Hour1 == null) { return 'No hay horarios'; } return '${ScheduleEntity.getFormatTime(schedule.range1Hour1)} a ${ScheduleEntity.getFormatTime(schedule.range1Hour2)} - ${ScheduleEntity.getFormatTime(schedule.range2Hour1)} a ${ScheduleEntity.getFormatTime(schedule.range2Hour2)}'; } } } class _AvatarContainer extends StatelessWidget { final bool containerFull; const _AvatarContainer({required this.containerFull}); @override Widget build(BuildContext context) { final user = Provider.of(context).user!; final profileFormProvider = Provider.of(context); final image = (profileFormProvider.user!.picture == '' || profileFormProvider.user!.picture == null) ? const Image(image: AssetImage('no-image.jpg')) : FadeInImage.assetNetwork( placeholder: 'loader.gif', fit: BoxFit.cover, image: profileFormProvider.user!.picture!, ); return WhiteCard( width: containerFull ? null : 250, child: SizedBox( width: double.infinity, child: Column( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [ Text(user.name, style: CustomLabels.h2), const SizedBox(height: 10), SizedBox( width: 160, height: 160, child: Stack( children: [ SizedBox( width: 200, height: 200, child: ClipOval(child: image), ), Positioned( bottom: 5, right: 5, child: Container( width: 45, height: 45, decoration: BoxDecoration( borderRadius: BorderRadius.circular(100), border: Border.all(color: Colors.white, width: 5), ), child: FloatingActionButton( onPressed: () async { FilePickerResult? result = await FilePicker.platform.pickFiles( withData: true, ); if (result != null) { PlatformFile file = result.files.first; Uint8List? fileBytes = file.bytes; if (fileBytes != null) { NotificationsService.showBusyIndicator(context); await profileFormProvider .uploadPicture(fileBytes); Provider.of(context, listen: false) .refreshUser(); Navigator.pop(context); } } else {} }, backgroundColor: Colors.indigo, elevation: 0, child: const Icon( Icons.camera_alt_outlined, size: 20, color: Colors.white, ), ), ), ) ], ), ), const SizedBox(height: 20), ], ), ), ); } }