import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:file_picker/file_picker.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:firebase_storage/firebase_storage.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:get/get.dart'; import 'package:image_picker/image_picker.dart'; import 'package:prosappco/src/authentication/authentication_repository.dart'; import 'package:prosappco/src/components/photo_view_web.dart'; import 'package:prosappco/src/components/pop_appbar.dart'; import 'package:intl/intl.dart'; import 'dart:io'; class ProfessionalProfileWebScreen extends StatefulWidget { const ProfessionalProfileWebScreen({super.key}); @override State createState() => _ProfessionalProfileWebScreenState(); } class _ProfessionalProfileWebScreenState extends State { final uid = AuthenticationRepository.instance.getCurrentUserUid(); final FirebaseStorage storage = FirebaseStorage.instance; // variables imagen String selectedImage = ''; String selectedCedulaImage = ''; String selectedCertificadoImage = ''; List selectedEspecializacionImages = []; List imagesEspecializacionsBytes = []; XFile? file; Uint8List? selectedImagInBytes; XFile? image_cedula; Uint8List? imageCedulaBytes; XFile? image_certificado; Uint8List? imageCertificadoBytes; XFile? image_especializaciones; Uint8List? imageEspecializacionesBytes; // controllers final _formKey = GlobalKey(); final TextEditingController _cedulaController = TextEditingController(); final TextEditingController _especializacionController = TextEditingController(); // variables bool _isLoading = false; String _profession = '...'; String photoTemp = ''; String photoCedulaTemp = ''; String photoCertificadoTemp = ''; String _photo = '...'; @override void initState() { super.initState(); if (_photo == '...') { AuthenticationRepository.instance.getPhoto(uid.toString()).then( (String s) => setState(() { _photo = s; }), ); } if (_profession == '...') { AuthenticationRepository.instance.getProfession(uid.toString()).then( (String s) => setState(() { _profession = s; }), ); } } _selectFile(bool imageFrom) async { FilePickerResult? fileResult = await FilePicker.platform.pickFiles(); if (fileResult != null) { setState(() { selectedImage = fileResult.files.first.name; selectedImagInBytes = fileResult.files.first.bytes; }); } } _selectFileCedula(bool imageFrom) async { FilePickerResult? fileResult = await FilePicker.platform.pickFiles(); if (fileResult != null) { setState(() { selectedCedulaImage = fileResult.files.first.name; imageCedulaBytes = fileResult.files.first.bytes; }); } } _selectFileCertificado(bool imageFrom) async { FilePickerResult? fileResult = await FilePicker.platform.pickFiles(); if (fileResult != null) { setState(() { selectedCertificadoImage = fileResult.files.first.name; imageCertificadoBytes = fileResult.files.first.bytes; }); } } _selectFilesEspecializaciones(bool imageFrom) async { FilePickerResult? fileResult = await FilePicker.platform.pickFiles(allowMultiple: true); try { if (fileResult != null) { List selectedFileBytes = []; for (var file in fileResult.files) { Uint8List? bytes = file.bytes; if (bytes != null) { selectedFileBytes.add(bytes); } } setState(() { imagesEspecializacionsBytes = selectedFileBytes; }); } } catch (e) { print('$e'); } } Future sendInfo() async { setState(() { _isLoading = true; }); final String cedula = _cedulaController.text.trim(); final String especializacion = _especializacionController.text.trim(); final List especializaciones = especializacion.split(',').map((e) => e.trim()).toList(); if (cedula.isEmpty) { showSnackBar('Cedula invalida', 'Ingrese una cedula válida'); return; } if (imageCedulaBytes == null) { showSnackBar('Cedula', 'Ingrese una imagen de su cedula'); return; } if (imageCertificadoBytes == null) { showSnackBar('Certificado', 'Ingrese una imagen de su certificado'); return; } // Actualiza los datos del usuario en Firestore await FirebaseFirestore.instance.collection('users').doc(uid).update({ 'cedula': cedula, 'estado': 'revision', 'especializaciones': especializaciones }); // Sube las imágenes al storage de Firebase await uploadCedula(); await uploadCertificado(); List uploadedPhotoPaths = await uploadEspecializaciones(imagesEspecializacionsBytes); if (uploadedPhotoPaths.isNotEmpty) { // Las imágenes se cargaron correctamente // Actualiza las imágenes en Firestore await updateFilesEspecializaciones(uploadedPhotoPaths); // Navega a la siguiente pantalla Navigator.pushReplacementNamed(context, '/solicitudEnviada'); } else { showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: const Text('Error'), content: const Text('Ocurrió un error al cargar las imágenes.'), actions: [ TextButton( onPressed: () { Navigator.pop(context); }, child: const Text('Aceptar'), ), ], ); }, ); } // Actualiza la imagen de perfil si hay cambios if (selectedImagInBytes != null) { await uploadFile(); await updateImage(photoTemp); } setState(() { _isLoading = false; }); // Navega a la siguiente pantalla Navigator.pushReplacementNamed(context, '/solicitudEnviada'); } uploadFile() async { try { final now = DateTime.now(); final formattedDate = DateFormat('HHmmssddMMyyyy').format(now); final milliseconds = (now.microsecondsSinceEpoch / 1000).round(); final random = '$formattedDate$milliseconds'; final Reference ref = FirebaseStorage.instance .ref() .child('users') .child(uid!) .child('profile') .child(random); final metaData = SettableMetadata(contentType: 'image/jpeg'); final UploadTask uploadTask = ref.putData(selectedImagInBytes!, metaData); final TaskSnapshot snapshot = await uploadTask.whenComplete(() => true); photoTemp = ref.fullPath; if (snapshot.state == TaskState.success) { return true; } else { return false; } } catch (e) { print('web image error - $e'); } } uploadCedula() async { try { final now = DateTime.now(); final formattedDate = DateFormat('HHmmssddMMyyyy').format(now); final milliseconds = (now.microsecondsSinceEpoch / 1000).round(); final random = 'c$formattedDate$milliseconds'; final Reference ref = FirebaseStorage.instance .ref() .child('users') .child(uid!) .child('cedula') .child(random); final metaData = SettableMetadata(contentType: 'application/pdf'); final UploadTask uploadTask = ref.putData(imageCedulaBytes!, metaData); final TaskSnapshot snapshot = await uploadTask.whenComplete(() => true); photoCedulaTemp = ref.fullPath; if (snapshot.state == TaskState.success) { updateImageCedula(photoCedulaTemp); return true; } else { return false; } } catch (e) { print('web image cedula error - $e'); } } uploadCertificado() async { try { final now = DateTime.now(); final formattedDate = DateFormat('HHmmssddMMyyyy').format(now); final milliseconds = (now.microsecondsSinceEpoch / 1000).round(); final random = 'f$formattedDate$milliseconds'; final Reference ref = FirebaseStorage.instance .ref() .child('users') .child(uid!) .child('certificado_profesional') .child(random); final metaData = SettableMetadata(contentType: 'application/pdf'); final UploadTask uploadTask = ref.putData(imageCertificadoBytes!, metaData); final TaskSnapshot snapshot = await uploadTask.whenComplete(() => true); photoCertificadoTemp = ref.fullPath; if (snapshot.state == TaskState.success) { updateImageCertificado(photoCertificadoTemp); return true; } else { return false; } } catch (e) { print('web image certificado error - $e'); } } // Future> uploadEspecializaciones(List images) async { // List photoPaths = []; // for (Uint8List imageBytes in images) { // Reference ref = storage // .ref() // .child('users') // .child(uid!) // .child('especializaciones') // .child('e${DateTime.now().millisecondsSinceEpoch}.jpg'); // final UploadTask uploadTask = ref.putData(imageBytes); // final TaskSnapshot snapshot = await uploadTask.whenComplete(() => true); // if (snapshot.state == TaskState.success) { // photoPaths.add(ref.fullPath); // } else { // await updateImagesEspecializaciones(photoPaths); // return []; // } // } // await updateImagesEspecializaciones(photoPaths); // return photoPaths; // } Future> uploadEspecializaciones(List files) async { List filePaths = []; for (Uint8List fileBytes in files) { final Reference ref = FirebaseStorage.instance .ref() .child('users') .child(uid!) .child('especializaciones') .child('e${DateTime.now().millisecondsSinceEpoch}.pdf'); final SettableMetadata metaData = SettableMetadata(contentType: 'application/pdf'); final UploadTask uploadTask = ref.putData(fileBytes, metaData); final TaskSnapshot snapshot = await uploadTask.whenComplete(() => true); if (snapshot.state == TaskState.success) { filePaths.add(ref.fullPath); } else { await updateFilesEspecializaciones(filePaths); return []; } } await updateFilesEspecializaciones(filePaths); return filePaths; } Future updateImageCedula(image) async { try { final userRef = FirebaseFirestore.instance.collection('users').doc(uid); final userSnapshot = await userRef.get(); if (userSnapshot.exists) { await userRef.update({'imgCedula': image}); print('¡Imagen de cédula actualizada correctamente!'); } else { await userRef.set({'imgCedula': image}); print('¡Imagen de cédula agregada correctamente!'); } } catch (e) { print('Error al agregar o actualizar la imagen de cédula: $e'); } } Future updateImageCertificado(image) async { try { final userRef = FirebaseFirestore.instance.collection('users').doc(uid); final userSnapshot = await userRef.get(); if (userSnapshot.exists) { await userRef.update({'imgCertificado': image}); print('¡Imagen de certificado actualizada correctamente!'); } else { await userRef.set({'imgCertificado': image}); print('¡Imagen de certificado agregada correctamente!'); } } catch (e) { print('Error al agregar o actualizar la imagen de certificado: $e'); } } Future updateImage(image) async { try { await FirebaseFirestore.instance .collection('users') .doc(uid) .update({'photo': image}); print('imagen actualizada correctamente'); } catch (e) { try { await FirebaseFirestore.instance .collection('users') .doc(uid) .set({'photo': image}); } catch (e) { print('Error al agregar la imagen de perfil: $e'); } print('Error al actualizar la imagen de perfil: $e'); } } // Future updateImagesEspecializaciones(List photoPaths) async { // try { // final userRef = FirebaseFirestore.instance.collection('users').doc(uid); // final userSnapshot = await userRef.get(); // if (userSnapshot.exists) { // await userRef.update({'imgEspecializaciones': photoPaths}); // print('¡Imágenes de especializaciones actualizadas correctamente!'); // } else { // await userRef.set({'imgEspecializaciones': photoPaths}); // print('¡Imágenes de especializaciones agregadas correctamente!'); // } // } catch (e) { // print( // 'Error al agregar o actualizar las imágenes de especializaciones: $e'); // } // } Future updateFilesEspecializaciones(List filePaths) async { try { final userRef = FirebaseFirestore.instance.collection('users').doc(uid); final userSnapshot = await userRef.get(); if (userSnapshot.exists) { await userRef.update({'imgEspecializaciones': filePaths}); print('¡Imágenes de especializaciones actualizadas correctamente!'); } else { await userRef.set({'imgEspecializaciones': filePaths}); print('¡Imágenes de especializaciones agregadas correctamente!'); } print('Archivos de especializaciones actualizados correctamente'); } catch (e) { print('Error al actualizar los archivos de especializaciones: $e'); } } void showSnackBar(String title, String message) { Get.snackbar( title, message, snackPosition: SnackPosition.TOP, ); } @override Widget build(BuildContext context) { String profession = _profession.toString(); double _space = 10; return Scaffold( backgroundColor: const Color(0xFFD6F4FF), appBar: PopAppbar( onPressed: () { Navigator.pop(context); }, label: 'Perfil profesional'), body: SingleChildScrollView( child: Center( child: SizedBox( width: 350, child: Card( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), ), color: Colors.white, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 20.0), child: _isLoading ? const Padding( padding: EdgeInsets.symmetric(vertical: 30), child: CircularProgressIndicator(), ) : Column( children: [ Container( padding: const EdgeInsets.only(top: 20), child: (selectedImagInBytes != null) ? LocalPhotoWeb(file: selectedImagInBytes) : ReferencePhotoWeb( ref: storage.ref().child(_photo)), ), SizedBox( width: 300, child: Form( key: _formKey, child: Column( children: [ TextFormField( keyboardType: TextInputType.number, controller: _cedulaController, inputFormatters: [ FilteringTextInputFormatter .digitsOnly // Solo permite caracteres numéricos ], validator: (String? value) { if (value == null || value.isEmpty) { return 'Ingrese una cedula válida'; } return null; }, decoration: const InputDecoration( prefixIcon: Icon(Icons.person_outline), hintText: 'Cedula (Obligatorio)', ), ), SizedBox(height: _space), ElevatedButton( onPressed: () { _selectFileCedula(true); }, style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFFD6F4FF), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(50), ), elevation: 0, minimumSize: const Size(250, 50), ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ const Text( 'Cedula', style: TextStyle( color: Color(0xFF2BA4EC), fontSize: 17, ), ), const SizedBox(width: 15), Icon( imageCedulaBytes != null ? Icons.check : Icons.file_upload_outlined, color: const Color(0xFF2BA4EC), size: 30, ), ], ), ), SizedBox(height: _space), TextFormField( readOnly: true, onTap: () async { final String? profesion = (await Navigator.pushNamed( context, '/profession')) as String?; if (profesion != null) { setState(() { _profession = profesion; }); } }, decoration: InputDecoration( prefixIcon: const Icon( Icons.assignment_ind_rounded), suffixIcon: const Icon(Icons.arrow_drop_down), hintStyle: profession == '' ? const TextStyle() : const TextStyle( color: Colors.black87), hintText: profession == '' ? 'Profesión (Obligatorio)' : profession), ), SizedBox(height: _space), ElevatedButton( onPressed: () { _selectFileCertificado(true); }, style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFFD6F4FF), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(50), ), elevation: 0, minimumSize: const Size(250, 50), ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ const Text( 'Certificado profesional', style: TextStyle( color: Color(0xFF2BA4EC), fontSize: 17, ), ), const SizedBox(width: 15), Icon( imageCertificadoBytes != null ? Icons.check : Icons.file_upload_outlined, color: const Color(0xFF2BA4EC), size: 30, ), ], ), ), SizedBox(height: _space), TextFormField( controller: _especializacionController, decoration: const InputDecoration( prefixIcon: Icon(Icons.assignment_ind_rounded), hintText: 'Especialización'), ), SizedBox(height: _space), ElevatedButton( onPressed: () async { _selectFilesEspecializaciones(true); }, style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFFD6F4FF), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(50), ), elevation: 0, minimumSize: const Size(250, 50), ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ const Text( 'Especialización', style: TextStyle( color: Color(0xFF2BA4EC), fontSize: 17, ), ), const SizedBox(width: 15), Icon( imagesEspecializacionsBytes.isEmpty ? Icons.file_upload_outlined : Icons.check, color: const Color(0xFF2BA4EC), size: 30, ), ], ), ), ], ), ), ), Container( margin: const EdgeInsets.only(top: 40), padding: const EdgeInsets.symmetric( horizontal: 20, vertical: 15), decoration: BoxDecoration( color: const Color(0xFFD6F4FF), borderRadius: BorderRadius.circular(20), boxShadow: [ BoxShadow( color: Colors.grey.withOpacity(0.5), spreadRadius: 1, blurRadius: 5, offset: const Offset(1, 3), ), ], ), child: const Row( children: [ Icon( Icons.error_outline, size: 27, color: Colors.black54, ), SizedBox(width: 15), Expanded( child: Text( 'Para añadir mas de una especialidad, envie mas fotos y separe por comas (,).', style: TextStyle( color: Colors.black, fontSize: 14), ), ), ], ), ), Container( alignment: Alignment.bottomCenter, margin: const EdgeInsets.only( top: 30, right: 20, left: 20, bottom: 30), child: ElevatedButton( onPressed: () { if (_formKey.currentState!.validate()) { sendInfo(); } }, style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF2BA4EC), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(50), ), elevation: 0, minimumSize: const Size(250, 50), maximumSize: const Size(350, 50), ), child: const Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( 'Enviar información', style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 17, ), ), SizedBox(width: 15), Icon( Icons.send, color: Colors.white, size: 20, ), ], ), ), ), ], ), ), ), ), ), ), ); } }