first commit
This commit is contained in:
@@ -0,0 +1,164 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import '../../../../core/theme/app_colors.dart';
|
||||
import '../../../../core/widgets/medical_modal.dart';
|
||||
import '../../../patient/presentation/views/patient_modal_view.dart';
|
||||
import '../../data/models/patient_search_item_model.dart';
|
||||
import '../store/patient_search_store.dart';
|
||||
import '../widgets/search_empty_state.dart';
|
||||
import '../widgets/search_input_bar.dart';
|
||||
import '../widgets/search_results_list.dart';
|
||||
|
||||
class PatientSearchModalView extends StatefulWidget {
|
||||
final ValueChanged<PatientSearchItemModel>? onPatientSelected;
|
||||
final bool isSecretary;
|
||||
|
||||
const PatientSearchModalView({
|
||||
super.key,
|
||||
this.onPatientSelected,
|
||||
this.isSecretary = false,
|
||||
});
|
||||
|
||||
@override
|
||||
State<PatientSearchModalView> createState() => _PatientSearchModalViewState();
|
||||
}
|
||||
|
||||
class _PatientSearchModalViewState extends State<PatientSearchModalView> {
|
||||
late final PatientSearchStore _store;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_store = PatientSearchStore();
|
||||
}
|
||||
|
||||
void _onSelectPatient(PatientSearchItemModel patient) {
|
||||
if (widget.onPatientSelected != null) {
|
||||
widget.onPatientSelected!(patient);
|
||||
} else {
|
||||
Navigator.of(context).pop(patient);
|
||||
showMedicalModal(
|
||||
context: context,
|
||||
builder: (_) => PatientModalView(
|
||||
patientId: patient.id,
|
||||
isSecretary: widget.isSecretary,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MedicalModalDialog(
|
||||
title: 'Búsqueda de Pacientes',
|
||||
titleIcon: Container(
|
||||
padding: const EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.primaryContainer,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.person_search_rounded,
|
||||
color: AppColors.primary,
|
||||
size: 20,
|
||||
),
|
||||
),
|
||||
subtitle: Observer(
|
||||
builder: (_) {
|
||||
if (_store.isLoading) {
|
||||
return const Text(
|
||||
'Consultando registros...',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: AppColors.textMuted,
|
||||
),
|
||||
);
|
||||
}
|
||||
if (_store.hasSearched) {
|
||||
return Text(
|
||||
'${_store.resultsCount} ${_store.resultsCount == 1 ? 'coincidencia encontrada' : 'coincidencias encontradas'}',
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
color: AppColors.primary,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
);
|
||||
}
|
||||
return const Text(
|
||||
'Localice pacientes por nombre, apellido, cédula o teléfono',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: AppColors.textMuted,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
bottomBar: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||
decoration: const BoxDecoration(
|
||||
color: AppColors.cardBg,
|
||||
border: Border(
|
||||
top: BorderSide(color: AppColors.border),
|
||||
),
|
||||
),
|
||||
child: const Row(
|
||||
children: [
|
||||
Icon(Icons.info_outline_rounded, size: 14, color: AppColors.textMuted),
|
||||
SizedBox(width: 6),
|
||||
Text(
|
||||
'Presione Enter para buscar · Esc para cerrar',
|
||||
style: TextStyle(
|
||||
fontSize: 11.5,
|
||||
color: AppColors.textMuted,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(20, 16, 20, 12),
|
||||
child: Observer(
|
||||
builder: (_) => SearchInputBar(
|
||||
isLoading: _store.isLoading,
|
||||
onSearch: (q) => _store.search(q),
|
||||
onClear: () => _store.clear(),
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Observer(
|
||||
builder: (_) {
|
||||
if (_store.isLoading) {
|
||||
return const SearchEmptyState(type: SearchStateViewType.loading);
|
||||
}
|
||||
if (_store.errorMessage != null) {
|
||||
return SearchEmptyState(
|
||||
type: SearchStateViewType.error,
|
||||
errorMessage: _store.errorMessage,
|
||||
onRetry: () => _store.search(_store.query),
|
||||
);
|
||||
}
|
||||
if (!_store.hasSearched) {
|
||||
return const SearchEmptyState(type: SearchStateViewType.initial);
|
||||
}
|
||||
if (_store.results.isEmpty) {
|
||||
return SearchEmptyState(
|
||||
type: SearchStateViewType.empty,
|
||||
query: _store.query,
|
||||
);
|
||||
}
|
||||
return SearchResultsList(
|
||||
patients: _store.results,
|
||||
onPatientSelected: _onSelectPatient,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user