import 'package:flutter/material.dart';
import 'package:issel_code_widgets/issel_code_widgets.dart';
import 'package:issel_code_widgets/issel_core.dart';
import '../../domain/entities/customer.dart';
import '../../domain/repositories/customer_repository.dart';
import '../controllers/customers_controller.dart';
class CustomersView extends StatefulWidget {
const CustomersView({super.key, required this.repository});
final CustomerRepository repository;
@override
State<CustomersView> createState() => _CustomersViewState();
}
class _CustomersViewState extends State<CustomersView> {
final _formKey = GlobalKey<FormState>();
final _name = TextEditingController();
final _email = TextEditingController();
late final CustomersController _controller;
CustomerType? _type;
bool _active = true;
@override
void initState() {
super.initState();
_controller = CustomersController(widget.repository);
_controller.load();
}
@override
void dispose() {
_controller.dispose();
_name.dispose();
_email.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final colors = Theme.of(context).colorScheme;
final text = Theme.of(context).textTheme;
return Scaffold(
appBar: AppBar(title: const Text('Clientes')),
body: SafeArea(
child: AnimatedBuilder(
animation: _controller,
builder: (context, _) {
final busy = _controller.isSaving || _controller.isLoading;
return SingleChildScrollView(
padding: const EdgeInsets.all(24),
child: Center(
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 760),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: colors.surface,
borderRadius: BorderRadius.circular(16),
),
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text('Nuevo cliente', style: text.titleMedium),
const SizedBox(height: 16),
AbsorbPointer(
absorbing: busy,
child: Column(
crossAxisAlignment:
CrossAxisAlignment.stretch,
children: [
const Text('Nombre'),
const SizedBox(height: 6),
IsselTextFormField(
controller: _name,
hintText: 'Nombre del cliente',
fillColor: colors.surfaceContainer,
readOnly: busy,
validator: (value) =>
(value ?? '').trim().isEmpty
? 'Escribe el nombre'
: null,
),
const SizedBox(height: 12),
const Text('Correo'),
const SizedBox(height: 6),
IsselTextFormField(
controller: _email,
hintText: 'correo@ejemplo.com',
fillColor: colors.surfaceContainer,
readOnly: busy,
keyboardType: TextInputType.emailAddress,
validator: (value) =>
(value ?? '').trim().contains('@')
? null
: 'Escribe un correo válido',
),
const SizedBox(height: 12),
const Text('Tipo de cliente'),
const SizedBox(height: 6),
IsselDropdown2<CustomerType>(
value: _type,
hintText: 'Selecciona un tipo',
color: colors.surfaceContainer,
items: const [
DropdownMenuItem(
value: CustomerType.person,
child: Text('Persona'),
),
DropdownMenuItem(
value: CustomerType.company,
child: Text('Empresa'),
),
],
onChanged: (value) =>
setState(() => _type = value),
validator: (value) => value == null
? 'Selecciona el tipo'
: null,
),
const SizedBox(height: 12),
IsselToggleField(
title: 'Activo',
value: _active,
backColor: colors.surfaceContainer,
valueBackColor: colors.surface,
onChanged: (value) =>
setState(() => _active = value),
),
],
),
),
const SizedBox(height: 20),
IsselButton(
text: _controller.isSaving
? 'Guardando…'
: 'Guardar cliente',
onTap: busy ? null : _save,
),
],
),
),
),
const SizedBox(height: 24),
Text('Clientes registrados', style: text.titleMedium),
const SizedBox(height: 12),
..._buildCustomers(context),
],
),
),
),
);
},
),
),
);
}
List<Widget> _buildCustomers(BuildContext context) {
if (_controller.isLoading) {
return const [
SizedBox(
height: 50,
child: IsselShimmer(width: double.infinity, height: 50),
)
];
}
final failure = _controller.loadFailure;
if (failure != null) {
return [
Text(failure.message),
const SizedBox(height: 12),
IsselButton(
text: 'Reintentar',
onTap: () {
_controller.load();
}),
];
}
if (_controller.customers.isEmpty) {
return const [Text('Todavía no hay clientes. Crea el primero arriba.')];
}
return [
for (final customer in _controller.customers)
Padding(
padding: const EdgeInsets.only(bottom: 8),
child: ListTile(
title: Text(customer.name),
subtitle: Text(customer.email),
trailing: SizedBox(
width: 90,
child: IsselPill(
text: customer.active ? 'Activo' : 'Inactivo',
height: 36,
),
),
),
),
];
}
Future<void> _save() async {
if (!(_formKey.currentState?.validate() ?? false)) return;
final result = await _controller.createCustomer(CustomerDraft(
name: _name.text,
email: _email.text,
type: _type!,
active: _active,
));
if (!mounted) return;
switch (result) {
case AppSuccess<CustomerEntity>(:final value):
_formKey.currentState?.reset();
_name.clear();
_email.clear();
setState(() {
_type = null;
_active = true;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Cliente ${value.name} creado')),
);
case AppError<CustomerEntity>(:final failure):
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(failure.message)),
);
}
}
}