2026-09-21 16:33:51 -04:00
|
|
|
import 'package:intl/intl.dart';
|
|
|
|
|
import 'package:mobx/mobx.dart';
|
|
|
|
|
import '../../data/models/patient_model.dart';
|
|
|
|
|
import '../../data/services/patient_service.dart';
|
|
|
|
|
|
|
|
|
|
part 'patient_store.g.dart';
|
|
|
|
|
|
|
|
|
|
// ignore: library_private_types_in_public_api
|
|
|
|
|
class PatientStore = _PatientStoreBase with _$PatientStore;
|
|
|
|
|
|
|
|
|
|
abstract class _PatientStoreBase with Store {
|
|
|
|
|
final PatientService service;
|
|
|
|
|
|
|
|
|
|
_PatientStoreBase({PatientService? patientService})
|
|
|
|
|
: service = patientService ?? PatientService();
|
|
|
|
|
|
|
|
|
|
@observable
|
|
|
|
|
int? id;
|
|
|
|
|
|
|
|
|
|
@observable
|
|
|
|
|
bool isLoading = false;
|
|
|
|
|
|
|
|
|
|
@observable
|
|
|
|
|
bool isSaving = false;
|
|
|
|
|
|
2026-09-22 13:41:14 -04:00
|
|
|
@observable
|
|
|
|
|
bool isDeleting = false;
|
|
|
|
|
|
2026-09-21 16:33:51 -04:00
|
|
|
@observable
|
|
|
|
|
String? errorMessage;
|
|
|
|
|
|
|
|
|
|
@observable
|
|
|
|
|
String? successMessage;
|
|
|
|
|
|
|
|
|
|
// Campos Demográficos Superiores
|
|
|
|
|
@observable
|
|
|
|
|
String fecReg = '';
|
|
|
|
|
|
|
|
|
|
@observable
|
|
|
|
|
String cedula = '';
|
|
|
|
|
|
|
|
|
|
@observable
|
|
|
|
|
String nombre = '';
|
|
|
|
|
|
|
|
|
|
@observable
|
|
|
|
|
String apellido = '';
|
|
|
|
|
|
|
|
|
|
@observable
|
|
|
|
|
String direccion = '';
|
|
|
|
|
|
|
|
|
|
@observable
|
|
|
|
|
String telefono = '';
|
|
|
|
|
|
|
|
|
|
@observable
|
|
|
|
|
String ocupacion = '';
|
|
|
|
|
|
|
|
|
|
@observable
|
|
|
|
|
String edad = '';
|
|
|
|
|
|
|
|
|
|
@observable
|
|
|
|
|
String sexo = 'Masculino';
|
|
|
|
|
|
|
|
|
|
@observable
|
|
|
|
|
String seguro = 'Sí';
|
|
|
|
|
|
|
|
|
|
@observable
|
|
|
|
|
String estCivil = 'Soltero';
|
|
|
|
|
|
|
|
|
|
// Pestañas Clínicas
|
|
|
|
|
@observable
|
|
|
|
|
String motCons = '';
|
|
|
|
|
|
|
|
|
|
@observable
|
|
|
|
|
String fecUltcon = '';
|
|
|
|
|
|
|
|
|
|
@observable
|
|
|
|
|
String hisEnfAct = '';
|
|
|
|
|
|
|
|
|
|
// Antecedentes Personales Patológicos
|
|
|
|
|
@observable
|
|
|
|
|
String datNi = 'Ninguna';
|
|
|
|
|
|
|
|
|
|
@observable
|
|
|
|
|
String datAdo = 'Ninguna';
|
|
|
|
|
|
|
|
|
|
@observable
|
|
|
|
|
String datAdu = 'Ninguna';
|
|
|
|
|
|
|
|
|
|
@observable
|
|
|
|
|
String datAlerg = 'Ninguna';
|
|
|
|
|
|
|
|
|
|
@observable
|
|
|
|
|
String datTran = 'ninguna';
|
|
|
|
|
|
|
|
|
|
@observable
|
|
|
|
|
String datCir = 'ninguna';
|
|
|
|
|
|
|
|
|
|
@observable
|
|
|
|
|
String datAc = 'ninguno';
|
|
|
|
|
|
|
|
|
|
@observable
|
|
|
|
|
String datOtrosp = 'ninguno';
|
|
|
|
|
|
|
|
|
|
// Antecedentes No Patológicos
|
|
|
|
|
@observable
|
|
|
|
|
String datMad = 'Viva y sana';
|
|
|
|
|
|
|
|
|
|
@observable
|
|
|
|
|
String datEsp = 'Viva y sana';
|
|
|
|
|
|
|
|
|
|
@observable
|
|
|
|
|
String datPadre = 'Vivo y sano';
|
|
|
|
|
|
|
|
|
|
@observable
|
|
|
|
|
String datHijos = 'Vivos y sanos';
|
|
|
|
|
|
|
|
|
|
@observable
|
|
|
|
|
String datHer = 'Vivos y sanos';
|
|
|
|
|
|
|
|
|
|
@observable
|
|
|
|
|
String datOtrosnp = 'Ningunos';
|
|
|
|
|
|
|
|
|
|
// Diagnósticos
|
|
|
|
|
@observable
|
|
|
|
|
String metDiagnRad = '';
|
|
|
|
|
|
|
|
|
|
@observable
|
|
|
|
|
String diagnDesc = '';
|
|
|
|
|
|
|
|
|
|
@observable
|
|
|
|
|
String diagnDef = '';
|
|
|
|
|
|
|
|
|
|
// Laboratorios y Tratamiento
|
|
|
|
|
@observable
|
|
|
|
|
String datLab = '';
|
|
|
|
|
|
|
|
|
|
@observable
|
|
|
|
|
String tratamiento = '';
|
|
|
|
|
|
|
|
|
|
// Próxima Cita
|
|
|
|
|
@observable
|
|
|
|
|
String fecProxcita = '';
|
|
|
|
|
|
|
|
|
|
// Estado de Sala de Espera
|
|
|
|
|
@observable
|
|
|
|
|
String estadoEspera = 'no_presente';
|
|
|
|
|
|
|
|
|
|
@computed
|
|
|
|
|
bool get isEditing => id != null;
|
|
|
|
|
|
|
|
|
|
@computed
|
|
|
|
|
bool get isValid =>
|
|
|
|
|
nombre.trim().isNotEmpty &&
|
|
|
|
|
apellido.trim().isNotEmpty &&
|
|
|
|
|
sexo.trim().isNotEmpty &&
|
|
|
|
|
seguro.trim().isNotEmpty;
|
|
|
|
|
|
|
|
|
|
@computed
|
|
|
|
|
int? get diasParaProximaCita {
|
|
|
|
|
if (fecProxcita.isEmpty) return null;
|
|
|
|
|
try {
|
|
|
|
|
DateTime? target;
|
|
|
|
|
if (fecProxcita.contains('-')) {
|
|
|
|
|
target = DateTime.tryParse(fecProxcita);
|
|
|
|
|
} else if (fecProxcita.contains('/')) {
|
|
|
|
|
final parts = fecProxcita.split('/');
|
|
|
|
|
if (parts.length == 3) {
|
|
|
|
|
final day = int.parse(parts[0]);
|
|
|
|
|
final month = int.parse(parts[1]);
|
|
|
|
|
final year = int.parse(parts[2]);
|
|
|
|
|
target = DateTime(year, month, day);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (target == null) return null;
|
|
|
|
|
final now = DateTime.now();
|
|
|
|
|
final today = DateTime(now.year, now.month, now.day);
|
|
|
|
|
final cleanTarget = DateTime(target.year, target.month, target.day);
|
|
|
|
|
return cleanTarget.difference(today).inDays;
|
|
|
|
|
} catch (_) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@action
|
|
|
|
|
void initForCreate() {
|
|
|
|
|
id = null;
|
|
|
|
|
errorMessage = null;
|
|
|
|
|
successMessage = null;
|
|
|
|
|
isLoading = false;
|
|
|
|
|
isSaving = false;
|
2026-09-22 13:41:14 -04:00
|
|
|
isDeleting = false;
|
2026-09-21 16:33:51 -04:00
|
|
|
|
|
|
|
|
final now = DateTime.now();
|
|
|
|
|
fecReg = DateFormat('dd/MM/yyyy').format(now);
|
|
|
|
|
fecUltcon = DateFormat('dd/MM/yyyy').format(now);
|
|
|
|
|
cedula = '';
|
|
|
|
|
nombre = '';
|
|
|
|
|
apellido = '';
|
|
|
|
|
direccion = '';
|
|
|
|
|
telefono = '';
|
|
|
|
|
ocupacion = '';
|
|
|
|
|
edad = '';
|
|
|
|
|
sexo = 'Masculino';
|
|
|
|
|
seguro = 'Sí';
|
|
|
|
|
estCivil = 'Soltero';
|
|
|
|
|
|
|
|
|
|
motCons = '';
|
|
|
|
|
hisEnfAct = '';
|
|
|
|
|
datNi = 'Ninguna';
|
|
|
|
|
datAdo = 'Ninguna';
|
|
|
|
|
datAdu = 'Ninguna';
|
|
|
|
|
datAlerg = 'Ninguna';
|
|
|
|
|
datTran = 'ninguna';
|
|
|
|
|
datCir = 'ninguna';
|
|
|
|
|
datAc = 'ninguno';
|
|
|
|
|
datOtrosp = 'ninguno';
|
|
|
|
|
|
|
|
|
|
datMad = 'Viva y sana';
|
|
|
|
|
datEsp = 'Viva y sana';
|
|
|
|
|
datPadre = 'Vivo y sano';
|
|
|
|
|
datHijos = 'Vivos y sanos';
|
|
|
|
|
datHer = 'Vivos y sanos';
|
|
|
|
|
datOtrosnp = 'Ningunos';
|
|
|
|
|
|
|
|
|
|
metDiagnRad = '';
|
|
|
|
|
diagnDesc = '';
|
|
|
|
|
diagnDef = '';
|
|
|
|
|
datLab = '';
|
|
|
|
|
tratamiento = '';
|
|
|
|
|
fecProxcita = '';
|
|
|
|
|
estadoEspera = 'no_presente';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@action
|
|
|
|
|
void populateFromModel(PatientModel p) {
|
|
|
|
|
id = p.id;
|
|
|
|
|
fecReg = p.fecReg;
|
|
|
|
|
fecUltcon = p.fecUltcon;
|
|
|
|
|
cedula = p.cedula;
|
|
|
|
|
nombre = p.nombre;
|
|
|
|
|
apellido = p.apellido;
|
|
|
|
|
direccion = p.direccion;
|
|
|
|
|
telefono = p.telefono;
|
|
|
|
|
ocupacion = p.ocupacion;
|
|
|
|
|
edad = p.edad;
|
|
|
|
|
sexo = p.sexo.isNotEmpty ? p.sexo : 'Masculino';
|
|
|
|
|
seguro = p.seguro.isNotEmpty ? p.seguro : 'Sí';
|
|
|
|
|
estCivil = p.estCivil.isNotEmpty ? p.estCivil : 'Soltero';
|
|
|
|
|
|
|
|
|
|
motCons = p.motCons;
|
|
|
|
|
hisEnfAct = p.hisEnfAct;
|
|
|
|
|
datNi = p.datNi.isNotEmpty ? p.datNi : 'Ninguna';
|
|
|
|
|
datAdo = p.datAdo.isNotEmpty ? p.datAdo : 'Ninguna';
|
|
|
|
|
datAdu = p.datAdu.isNotEmpty ? p.datAdu : 'Ninguna';
|
|
|
|
|
datAlerg = p.datAlerg.isNotEmpty ? p.datAlerg : 'Ninguna';
|
|
|
|
|
datTran = p.datTran.isNotEmpty ? p.datTran : 'ninguna';
|
|
|
|
|
datCir = p.datCir.isNotEmpty ? p.datCir : 'ninguna';
|
|
|
|
|
datAc = p.datAc.isNotEmpty ? p.datAc : 'ninguno';
|
|
|
|
|
datOtrosp = p.datOtrosp.isNotEmpty ? p.datOtrosp : 'ninguno';
|
|
|
|
|
|
|
|
|
|
datMad = p.datMad.isNotEmpty ? p.datMad : 'Viva y sana';
|
|
|
|
|
datEsp = p.datEsp.isNotEmpty ? p.datEsp : 'Viva y sana';
|
|
|
|
|
datPadre = p.datPadre.isNotEmpty ? p.datPadre : 'Vivo y sano';
|
|
|
|
|
datHijos = p.datHijos.isNotEmpty ? p.datHijos : 'Vivos y sanos';
|
|
|
|
|
datHer = p.datHer.isNotEmpty ? p.datHer : 'Vivos y sanos';
|
|
|
|
|
datOtrosnp = p.datOtrosnp.isNotEmpty ? p.datOtrosnp : 'Ningunos';
|
|
|
|
|
|
|
|
|
|
metDiagnRad = p.metDiagnRad;
|
|
|
|
|
diagnDesc = p.diagnDesc;
|
|
|
|
|
diagnDef = p.diagnDef;
|
|
|
|
|
datLab = p.datLab;
|
|
|
|
|
tratamiento = p.tratamiento;
|
|
|
|
|
fecProxcita = p.fecProxcita;
|
|
|
|
|
estadoEspera = p.estadoEspera.isNotEmpty ? p.estadoEspera : 'no_presente';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@action
|
|
|
|
|
Future<void> loadPatient(int patientId) async {
|
|
|
|
|
isLoading = true;
|
|
|
|
|
errorMessage = null;
|
|
|
|
|
try {
|
|
|
|
|
final p = await service.getPatientById(patientId);
|
|
|
|
|
runInAction(() {
|
|
|
|
|
populateFromModel(p);
|
|
|
|
|
isLoading = false;
|
|
|
|
|
});
|
|
|
|
|
} catch (e) {
|
|
|
|
|
runInAction(() {
|
|
|
|
|
errorMessage = e.toString().replaceAll('Exception: ', '');
|
|
|
|
|
isLoading = false;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@action
|
|
|
|
|
void appendCurrentDateToConsultas() {
|
|
|
|
|
final dateStr = DateFormat('dd/MM/yyyy').format(DateTime.now());
|
|
|
|
|
if (motCons.isEmpty) {
|
|
|
|
|
motCons = '$dateStr: ';
|
|
|
|
|
} else {
|
|
|
|
|
motCons = '$motCons\n$dateStr: ';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@action
|
|
|
|
|
void appendCurrentDateToHistorial() {
|
|
|
|
|
final dateStr = DateFormat('dd/MM/yyyy').format(DateTime.now());
|
|
|
|
|
if (hisEnfAct.isEmpty) {
|
|
|
|
|
hisEnfAct = '$dateStr: ';
|
|
|
|
|
} else {
|
|
|
|
|
hisEnfAct = '$hisEnfAct\n$dateStr: ';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PatientModel toModel() {
|
|
|
|
|
return PatientModel(
|
|
|
|
|
id: id,
|
|
|
|
|
nombre: nombre.trim(),
|
|
|
|
|
apellido: apellido.trim(),
|
|
|
|
|
telefono: telefono.trim(),
|
|
|
|
|
direccion: direccion.trim(),
|
|
|
|
|
cedula: cedula.trim(),
|
|
|
|
|
ocupacion: ocupacion.trim(),
|
|
|
|
|
edad: edad.trim(),
|
|
|
|
|
fecUltcon: fecUltcon.trim(),
|
|
|
|
|
fecReg: fecReg.trim(),
|
|
|
|
|
sexo: sexo.trim(),
|
|
|
|
|
seguro: seguro.trim(),
|
|
|
|
|
estCivil: estCivil.trim(),
|
|
|
|
|
motCons: motCons,
|
|
|
|
|
hisEnfAct: hisEnfAct,
|
|
|
|
|
datPadre: datPadre,
|
|
|
|
|
datEsp: datEsp,
|
|
|
|
|
datHijos: datHijos,
|
|
|
|
|
datOtrosnp: datOtrosnp,
|
|
|
|
|
datAlerg: datAlerg,
|
|
|
|
|
datTran: datTran,
|
|
|
|
|
datOtrosp: datOtrosp,
|
|
|
|
|
metDiagnRad: metDiagnRad,
|
|
|
|
|
datLab: datLab,
|
|
|
|
|
diagnDesc: diagnDesc,
|
|
|
|
|
diagnDef: diagnDef,
|
|
|
|
|
fecProxcita: fecProxcita.trim(),
|
|
|
|
|
tratamiento: tratamiento,
|
|
|
|
|
datHer: datHer,
|
|
|
|
|
datMad: datMad,
|
|
|
|
|
datNi: datNi,
|
|
|
|
|
datAdo: datAdo,
|
|
|
|
|
datAdu: datAdu,
|
|
|
|
|
datAc: datAc,
|
|
|
|
|
datCir: datCir,
|
|
|
|
|
estadoEspera: estadoEspera,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@action
|
|
|
|
|
Future<bool> savePatient() async {
|
|
|
|
|
if (!isValid) {
|
|
|
|
|
errorMessage = 'Faltan campos obligatorios: Nombre, Apellido, Sexo y Seguro.';
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Si el paciente estaba en consulta o en espera y el médico guarda los cambios de la consulta médica,
|
|
|
|
|
// la atención concluye formalmente y su estado de sala de espera pasa a 'atendido'.
|
|
|
|
|
if (estadoEspera == 'en_consulta' || estadoEspera == 'en_espera') {
|
|
|
|
|
estadoEspera = 'atendido';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
isSaving = true;
|
|
|
|
|
errorMessage = null;
|
|
|
|
|
successMessage = null;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
final model = toModel();
|
|
|
|
|
if (isEditing) {
|
|
|
|
|
await service.updatePatient(id!, model.toJson(includeId: false));
|
|
|
|
|
runInAction(() {
|
|
|
|
|
successMessage = 'Paciente ${model.fullName} actualizado correctamente';
|
|
|
|
|
isSaving = false;
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
final created = await service.createPatient(model);
|
|
|
|
|
runInAction(() {
|
|
|
|
|
id = created.id;
|
|
|
|
|
successMessage = 'Paciente ${model.fullName} guardado correctamente';
|
|
|
|
|
isSaving = false;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
} catch (e) {
|
|
|
|
|
runInAction(() {
|
|
|
|
|
errorMessage = e.toString().replaceAll('Exception: ', '');
|
|
|
|
|
isSaving = false;
|
|
|
|
|
});
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-09-22 13:41:14 -04:00
|
|
|
|
|
|
|
|
@action
|
|
|
|
|
Future<bool> deletePatient() async {
|
|
|
|
|
if (id == null) {
|
|
|
|
|
errorMessage = 'No se puede eliminar un paciente que no ha sido guardado.';
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
isDeleting = true;
|
|
|
|
|
errorMessage = null;
|
|
|
|
|
successMessage = null;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
await service.deletePatient(id!);
|
|
|
|
|
runInAction(() {
|
|
|
|
|
isDeleting = false;
|
|
|
|
|
successMessage = 'Paciente eliminado exitosamente';
|
|
|
|
|
});
|
|
|
|
|
return true;
|
|
|
|
|
} catch (e) {
|
|
|
|
|
runInAction(() {
|
|
|
|
|
errorMessage = e.toString().replaceAll('Exception: ', '');
|
|
|
|
|
isDeleting = false;
|
|
|
|
|
});
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-09-21 16:33:51 -04:00
|
|
|
}
|