Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
2026-05-01 11:54:39 +02:00
parent f8bcac51e1
commit ac97e47771
9 changed files with 358 additions and 321 deletions

View File

@@ -135,8 +135,8 @@ class CustomerCubit extends Cubit<CustomerState> {
String? email,
}) async {
final newCustomer = CustomerModel(
nome: name,
telefono: phone ?? '',
name: name,
phoneNumber: phone ?? '',
email: email ?? '',
companyId: _sessionCubit.state.company!.id!,
note: '',

View File

@@ -1,74 +1,74 @@
import 'package:equatable/equatable.dart';
import 'package:flux/core/utils/extensions.dart';
import 'package:flux/features/customers/models/customer_file_model.dart';
import 'package:flux/features/attachments/models/attachment_model.dart';
class CustomerModel extends Equatable {
final String? id; // Bigint in SQL
final DateTime? createdAt;
final String nome;
final String telefono;
final String name;
final String phoneNumber;
final String email;
final String note;
final DateTime? dataUltimoContatto;
final bool nonDisturbare;
final DateTime? lastContactDate;
final bool doNotDisturb;
final String companyId; // UUID
final bool isActive;
final List<CustomerFileModel> files;
final List<AttachmentModel> attachments;
const CustomerModel({
this.id,
this.createdAt,
required this.nome,
required this.telefono,
required this.name,
required this.phoneNumber,
required this.email,
required this.note,
this.dataUltimoContatto,
this.nonDisturbare = false,
this.lastContactDate,
this.doNotDisturb = false,
required this.companyId,
this.isActive = true,
this.files = const [],
this.attachments = const [],
});
@override
List<Object?> get props => [
id,
createdAt,
nome,
telefono,
name,
phoneNumber,
email,
note,
dataUltimoContatto,
nonDisturbare,
lastContactDate,
doNotDisturb,
companyId,
isActive,
files,
attachments,
];
CustomerModel copyWith({
String? id,
DateTime? createdAt,
String? nome,
String? telefono,
String? name,
String? phoneNumber,
String? email,
String? note,
DateTime? dataUltimoContatto,
bool? nonDisturbare,
DateTime? lastContactDate,
bool? doNotDisturb,
String? companyId,
bool? isActive,
List<CustomerFileModel>? files,
List<AttachmentModel>? attachments,
}) {
return CustomerModel(
id: id ?? this.id,
createdAt: createdAt ?? this.createdAt,
nome: nome ?? this.nome,
telefono: telefono ?? this.telefono,
name: name ?? this.name,
phoneNumber: phoneNumber ?? this.phoneNumber,
email: email ?? this.email,
note: note ?? this.note,
dataUltimoContatto: dataUltimoContatto ?? this.dataUltimoContatto,
nonDisturbare: nonDisturbare ?? this.nonDisturbare,
lastContactDate: lastContactDate ?? this.lastContactDate,
doNotDisturb: doNotDisturb ?? this.doNotDisturb,
companyId: companyId ?? this.companyId,
isActive: isActive ?? this.isActive,
files: files ?? this.files,
attachments: attachments ?? this.attachments,
);
}
@@ -78,34 +78,29 @@ class CustomerModel extends Equatable {
createdAt: map['created_at'] != null
? DateTime.parse(map['created_at'])
: null,
nome: (map['nome'] as String).myFormat(),
telefono: map['telefono'],
name: (map['name'] as String).myFormat(),
phoneNumber: map['phone_number'],
email: map['email'],
note: map['note'] ?? '',
dataUltimoContatto: map['data_ultimo_contatto'] != null
? DateTime.parse(map['data_ultimo_contatto'])
lastContactDate: map['last_contact_date'] != null
? DateTime.parse(map['last_contact_date'])
: null,
nonDisturbare: map['non_disturbare'] ?? false,
doNotDisturb: map['do_not_disturb'] ?? false,
companyId: map['company_id'] as String,
isActive: map['is_active'] ?? true,
files:
(map['customer_file'] as List?)
?.map((x) => CustomerFileModel.fromMap(x))
.toList() ??
const [],
);
}
Map<String, dynamic> toJson() {
return {
if (id != null) 'id': id,
'nome': nome.toLowerCase().trim(),
'telefono': telefono,
'name': name.toLowerCase().trim(),
'phone_number': phoneNumber,
'email': email.toLowerCase().trim(),
'note': note,
if (dataUltimoContatto != null)
'data_ultimo_contatto': dataUltimoContatto!.toIso8601String(),
'non_disturbare': nonDisturbare,
if (lastContactDate != null)
'last_contact_date': lastContactDate!.toIso8601String(),
'do_not_disturb': doNotDisturb,
'company_id': companyId,
'is_active': isActive,
};

View File

@@ -62,7 +62,7 @@ class _CustomerDetailScreenState extends State<CustomerDetailScreen> {
backgroundColor: context.background,
appBar: AppBar(
title: Text(
widget.customer.nome,
widget.customer.name,
style: const TextStyle(fontWeight: FontWeight.bold),
),
backgroundColor: context.background,
@@ -103,7 +103,7 @@ class _CustomerDetailScreenState extends State<CustomerDetailScreen> {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_infoTile(Icons.phone_android, "Telefono", widget.customer.telefono),
_infoTile(Icons.phone_android, "Telefono", widget.customer.phoneNumber),
_infoTile(
Icons.email_outlined,
"Email",
@@ -117,7 +117,7 @@ class _CustomerDetailScreenState extends State<CustomerDetailScreen> {
: widget.customer.note,
),
const SizedBox(height: 20),
if (widget.customer.nonDisturbare)
if (widget.customer.doNotDisturb)
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
@@ -191,8 +191,8 @@ class _CustomerDetailScreenState extends State<CustomerDetailScreen> {
context: context,
builder: (context) => QrUploadDialog(
deepLinkUrl:
'fluxapp://customer/${widget.customer.id}/upload?name=${Uri.encodeComponent(widget.customer.nome)}',
title: 'Scatta per ${widget.customer.nome}',
'fluxapp://customer/${widget.customer.id}/upload?name=${Uri.encodeComponent(widget.customer.name)}',
title: 'Scatta per ${widget.customer.name}',
),
);
},

View File

@@ -30,15 +30,15 @@ class _CustomerFormState extends State<CustomerForm> {
void initState() {
super.initState();
// Se widget.customer è null, i campi saranno vuoti
_nomeController = TextEditingController(text: widget.customer?.nome ?? '');
_nomeController = TextEditingController(text: widget.customer?.name ?? '');
_telefonoController = TextEditingController(
text: widget.customer?.telefono ?? '',
text: widget.customer?.phoneNumber ?? '',
);
_emailController = TextEditingController(
text: widget.customer?.email ?? '',
);
_noteController = TextEditingController(text: widget.customer?.note ?? '');
_nonDisturbare = widget.customer?.nonDisturbare ?? false;
_nonDisturbare = widget.customer?.doNotDisturb ?? false;
}
@override
@@ -56,19 +56,19 @@ class _CustomerFormState extends State<CustomerForm> {
// o creandone uno da zero, preservando l'ID in caso di modifica.
final updatedCustomer =
widget.customer?.copyWith(
nome: _nomeController.text.trim(),
telefono: _telefonoController.text.trim(),
name: _nomeController.text.trim(),
phoneNumber: _telefonoController.text.trim(),
email: _emailController.text.trim(),
note: _noteController.text.trim(),
nonDisturbare: _nonDisturbare,
doNotDisturb: _nonDisturbare,
) ??
CustomerModel(
// Caso nuovo cliente
nome: _nomeController.text.trim(),
telefono: _telefonoController.text.trim(),
name: _nomeController.text.trim(),
phoneNumber: _telefonoController.text.trim(),
email: _emailController.text.trim(),
note: _noteController.text.trim(),
nonDisturbare: _nonDisturbare,
doNotDisturb: _nonDisturbare,
companyId: '', // Verrà iniettato dal Bloc o dal chiamante
);

View File

@@ -103,7 +103,7 @@ class _CustomerSearchSheetState extends State<CustomerSearchSheet> {
if (nuovoCliente != null) {
operationsCubit.updateField(
customerId: nuovoCliente.id,
customerDisplayName: nuovoCliente.nome,
customerDisplayName: nuovoCliente.name,
);
setState(() {
@@ -151,7 +151,7 @@ class _CustomerSearchSheetState extends State<CustomerSearchSheet> {
final customer = state.customers[index];
// Assumo che il tuo CustomerModel abbia le proprietà name e surname.
// Adatta queste variabili al tuo modello reale!
final displayName = customer.nome.trim();
final displayName = customer.name.trim();
return ListTile(
contentPadding: EdgeInsets.zero,

View File

@@ -166,7 +166,7 @@ class _CustomerTile extends StatelessWidget {
radius: 24,
backgroundColor: context.accent.withValues(alpha: 0.1),
child: Text(
customer.nome.isNotEmpty ? customer.nome[0].toUpperCase() : '?',
customer.name.isNotEmpty ? customer.name[0].toUpperCase() : '?',
style: TextStyle(
color: context.accent,
fontWeight: FontWeight.bold,
@@ -174,7 +174,7 @@ class _CustomerTile extends StatelessWidget {
),
),
title: Text(
customer.nome,
customer.name,
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
),
subtitle: Padding(
@@ -184,7 +184,7 @@ class _CustomerTile extends StatelessWidget {
Icon(Icons.phone_android, size: 14, color: context.secondaryText),
const SizedBox(width: 4),
Text(
customer.telefono,
customer.phoneNumber,
style: TextStyle(color: context.secondaryText),
),
if (customer.email.isNotEmpty) ...[