Files
prosappco/lib/src/screens/professional_profile_web.dart
T
2023-09-14 14:16:23 -05:00

706 lines
26 KiB
Dart

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<ProfessionalProfileWebScreen> createState() =>
_ProfessionalProfileWebScreenState();
}
class _ProfessionalProfileWebScreenState
extends State<ProfessionalProfileWebScreen> {
final uid = AuthenticationRepository.instance.getCurrentUserUid();
final FirebaseStorage storage = FirebaseStorage.instance;
// variables imagen
String selectedImage = '';
String selectedCedulaImage = '';
String selectedCertificadoImage = '';
List selectedEspecializacionImages = [];
List<Uint8List> imagesEspecializacionsBytes = [];
XFile? file;
Uint8List? selectedImagInBytes;
XFile? image_cedula;
Uint8List? imageCedulaBytes;
XFile? image_certificado;
Uint8List? imageCertificadoBytes;
XFile? image_especializaciones;
Uint8List? imageEspecializacionesBytes;
// controllers
final _formKey = GlobalKey<FormState>();
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<Uint8List> 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<void> sendInfo() async {
setState(() {
_isLoading = true;
});
final String cedula = _cedulaController.text.trim();
final String especializacion = _especializacionController.text.trim();
final List<String> 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<String> 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<List<String>> uploadEspecializaciones(List<Uint8List> files) async {
List<String> 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<void> 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});
} else {
await userRef.set({'imgCedula': image});
}
} catch (e) {
print('Error al agregar o actualizar la imagen de cédula: $e');
}
}
Future<void> 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});
} else {
await userRef.set({'imgCertificado': image});
}
} catch (e) {
print('Error al agregar o actualizar la imagen de certificado: $e');
}
}
Future<void> updateImage(image) async {
try {
await FirebaseFirestore.instance
.collection('users')
.doc(uid)
.update({'photo': image});
} 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<void> updateFilesEspecializaciones(List<String> filePaths) async {
try {
final userRef = FirebaseFirestore.instance.collection('users').doc(uid);
final userSnapshot = await userRef.get();
if (userSnapshot.exists) {
await userRef.update({'imgEspecializaciones': filePaths});
} else {
await userRef.set({'imgEspecializaciones': filePaths});
}
} 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(
'Si tienes más de una especialidad, por favor, adjunta un archivo con el diploma de respaldo para cada una de ellas y sepáralos por comas. ¡Gracias!',
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,
),
],
),
),
),
],
),
),
),
),
),
),
);
}
}