ticket labels e ticket receipt

This commit is contained in:
2026-05-10 14:09:57 +02:00
parent 385c3da0a5
commit 5c86483563
20 changed files with 1024 additions and 157 deletions

View File

@@ -217,46 +217,7 @@ class _OperationFormScreenState extends State<OperationFormScreen> {
final isUltraWide = constraints.maxWidth > 1400;
final isDesktop = constraints.maxWidth > 900;
if (isUltraWide) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
flex: 4,
child: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: _buildMainFormContent(
theme,
state,
displayStatus,
showFiles: false,
),
),
),
VerticalDivider(width: 1, color: theme.dividerColor),
Expanded(
flex: 3,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: _buildNotesSection(isDesktop: true),
),
),
VerticalDivider(width: 1, color: theme.dividerColor),
Expanded(
flex: 3,
child: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: SharedAttachmentsSection(
parentType: AttachmentParentType.operation,
parentId: state.operation.id,
titleForUpload:
state.operation.customerDisplayName ??
'Nuova pratica',
onGenerateIdForQr: _generateIdForQr,
),
),
),
],
);
return _buildUltraWide(state, theme);
} else if (isDesktop) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -365,48 +326,92 @@ class _OperationFormScreenState extends State<OperationFormScreen> {
);
}
Widget _buildMainFormContent(
ThemeData theme,
OperationFormState state,
OperationStatus displayStatus, {
bool showFiles = true,
}) {
final currentOp = state.operation;
final currentType = currentOp.type;
return Column(
Widget _buildUltraWide(OperationFormState state, ThemeData theme) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
StaffSection(
staffId: currentOp.staffId,
staffName: currentOp.staffDisplayName,
onStaffSelected: (staff) => {
context.read<OperationFormCubit>().updateFields(
staffId: staff.id,
staffDisplayName: staff.name,
Expanded(
flex: 4,
child: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildStaffSection(state),
const Divider(height: 50),
_buildOperationStatusSection(state),
const Divider(height: 32),
_buildCustomerSection(state),
const SizedBox(height: 16),
_buildReferenceSection(state),
const Divider(height: 50),
_buildOperationTypeSection(state),
const SizedBox(height: 16),
_buildQuantitySection(state),
const Divider(height: 50),
_buildDetailsSection(state),
const Divider(height: 50),
],
),
},
),
),
const Divider(height: 50),
VerticalDivider(width: 1, color: theme.dividerColor),
Expanded(
flex: 3,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: _buildNotesSection(isDesktop: true),
),
),
VerticalDivider(width: 1, color: theme.dividerColor),
Expanded(
flex: 3,
child: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: _buildAttachmentSection(state),
),
),
],
);
}
// --- SEZIONE STATO OPERAZIONE ---
Widget _buildStaffSection(OperationFormState state) {
return StaffSection(
staffId: state.operation.staffId,
staffName: state.operation.staffDisplayName,
onStaffSelected: (staff) => {
context.read<OperationFormCubit>().updateFields(
staffId: staff.id,
staffDisplayName: staff.name,
),
},
);
}
Widget _buildOperationStatusSection(OperationFormState state) {
return Column(
children: [
_buildSectionTitle('Esito / Stato Operazione'),
Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
decoration: BoxDecoration(
color: _getStatusColor(displayStatus).withValues(alpha: 0.1),
color: _getStatusColor(
state.operation.status,
).withValues(alpha: 0.1),
border: Border.all(
color: _getStatusColor(displayStatus).withValues(alpha: 0.3),
color: _getStatusColor(
state.operation.status,
).withValues(alpha: 0.3),
),
borderRadius: BorderRadius.circular(12),
),
child: DropdownButtonHideUnderline(
child: DropdownButton<OperationStatus>(
isExpanded: true,
value: displayStatus,
value: state.operation.status,
icon: Icon(
Icons.arrow_drop_down,
color: _getStatusColor(displayStatus),
color: _getStatusColor(state.operation.status),
),
items: OperationStatus.values
/* .where(
@@ -450,34 +455,41 @@ class _OperationFormScreenState extends State<OperationFormScreen> {
),
const SizedBox(height: 8),
Text(
displayStatus == OperationStatus.success
state.operation.status == OperationStatus.success
? 'Lascia OK se la pratica è stata caricata con successo.'
: 'Attenzione: la pratica verrà salvata come ${displayStatus.displayName}.',
: 'Attenzione: la pratica verrà salvata come ${state.operation.status.displayName}.',
style: TextStyle(fontSize: 12, color: Colors.grey.shade600),
),
const Divider(height: 32),
],
);
}
//_buildSectionTitle('Cliente & Riferimento'),
SharedCustomerSection(
customerId: currentOp.customerId,
customerName: currentOp.customerDisplayName,
onCustomerSelected: (customer) {
context.read<OperationFormCubit>().updateFields(
customerId: customer.id,
customerDisplayName: customer.name,
);
},
),
const SizedBox(height: 16),
TextFormField(
controller: _referenceController,
decoration: const InputDecoration(
labelText: 'Riferimento (es. numero di telefono, targa...)',
prefixIcon: Icon(Icons.tag),
),
),
const Divider(height: 32),
Widget _buildCustomerSection(OperationFormState state) {
return SharedCustomerSection(
customerId: state.operation.customerId,
customerName: state.operation.customerDisplayName,
onCustomerSelected: (customer) {
context.read<OperationFormCubit>().updateFields(
customerId: customer.id,
customerDisplayName: customer.name,
);
},
);
}
Widget _buildReferenceSection(OperationFormState state) {
return TextFormField(
controller: _referenceController,
decoration: const InputDecoration(
labelText: 'Riferimento (es. numero di telefono, targa...)',
prefixIcon: Icon(Icons.tag),
),
);
}
Widget _buildOperationTypeSection(OperationFormState state) {
return Column(
children: [
_buildSectionTitle('Cosa stiamo facendo?'),
Wrap(
spacing: 8.0,
@@ -485,7 +497,7 @@ class _OperationFormScreenState extends State<OperationFormScreen> {
children: _availableTypes.map((type) {
return ChoiceChip(
label: Text(type),
selected: currentType == type,
selected: state.operation.type == type,
onSelected: (selected) {
if (selected) {
context.read<OperationFormCubit>().setTypeWithSmartDefault(
@@ -496,63 +508,90 @@ class _OperationFormScreenState extends State<OperationFormScreen> {
);
}).toList(),
),
const Divider(height: 32),
],
);
}
Widget _buildDetailsSection(OperationFormState state) {
return Column(
children: [
_buildSectionTitle('Dettagli Servizio'),
DetailsSection(
currentOp: currentOp,
currentType: currentType,
currentOp: state.operation,
currentType: state.operation.type,
freeTextSubtypeController: _freeTextSubtypeController,
freeTextDescriptionController: _freeTextDescriptionController,
durationQuickPicks: _buildDurationQuickPicks(currentOp),
durationQuickPicks: _buildDurationQuickPicks(state.operation),
),
],
);
}
Widget _buildQuantitySection(OperationFormState state) {
return Row(
children: [
const Text('Quantità: '),
IconButton(
icon: const Icon(Icons.remove),
onPressed: () {
final q = state.operation.quantity;
if (q > 1) {
context.read<OperationFormCubit>().updateFields(quantity: q - 1);
}
},
),
Text(
'${state.operation.quantity}',
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
IconButton(
icon: const Icon(Icons.add),
onPressed: () {
final q = state.operation.quantity;
context.read<OperationFormCubit>().updateFields(quantity: q + 1);
},
),
],
);
}
Widget _buildAttachmentSection(OperationFormState state) {
return SharedAttachmentsSection(
parentType: AttachmentParentType.operation,
parentId: state.operation.id,
titleForUpload: state.operation.customerDisplayName ?? 'Nuova pratica',
onGenerateIdForQr: _generateIdForQr,
);
}
Widget _buildMainFormContent(
ThemeData theme,
OperationFormState state,
OperationStatus displayStatus, {
bool showFiles = true,
}) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildStaffSection(state),
const Divider(height: 50),
_buildOperationStatusSection(state),
const Divider(height: 32),
_buildCustomerSection(state),
const SizedBox(height: 16),
_buildReferenceSection(state),
const Divider(height: 50),
_buildOperationTypeSection(state),
const SizedBox(height: 16),
_buildQuantitySection(state),
const Divider(height: 50),
_buildDetailsSection(state),
const Divider(height: 50),
// QUANTITÀ
Row(
children: [
const Text('Quantità: '),
IconButton(
icon: const Icon(Icons.remove),
onPressed: () {
final q = currentOp.quantity;
if (q > 1) {
context.read<OperationFormCubit>().updateFields(
quantity: q - 1,
);
}
},
),
Text(
'${currentOp.quantity}',
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
IconButton(
icon: const Icon(Icons.add),
onPressed: () {
final q = currentOp.quantity;
context.read<OperationFormCubit>().updateFields(
quantity: q + 1,
);
},
),
],
),
const Divider(height: 32),
if (showFiles) ...[
SharedAttachmentsSection(
parentType: AttachmentParentType.operation,
parentId: currentOp.id,
titleForUpload:
state.operation.customerDisplayName ?? 'Nuova pratica',
onGenerateIdForQr: _generateIdForQr,
),
/* SharedFilesSection(
titleNameForUpload:
state.operation.customerDisplayName ?? 'Nuova pratica',
onGenerateIdForQr: _generateIdForQr,
), */
],
if (showFiles) ...[_buildAttachmentSection(state)],
],
);
}