added product import and billing integration
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import '../../../app/providers.dart';
|
||||
import '../../../core/theme/app_colors.dart';
|
||||
import '../../../core/theme/app_dimens.dart';
|
||||
import '../../../core/utils/formatters.dart';
|
||||
import '../../../core/widgets/primary_button.dart';
|
||||
import '../../../data/sync/sync_engine.dart';
|
||||
import '../../../domain/entities/transaction.dart';
|
||||
import '../../../domain/repositories/sync_repository.dart';
|
||||
import '../../sync/providers/sync_controller.dart';
|
||||
@@ -26,10 +28,21 @@ class EventsView extends ConsumerWidget {
|
||||
final syncState = ref.watch(orderSyncProvider);
|
||||
final events = ref.watch(syncEventsProvider);
|
||||
|
||||
// The engine may not have emitted yet on a cold start, so fall back to
|
||||
// its current value rather than showing nothing. This is the same state
|
||||
// that drives the header pill — it is what actually knows whether the
|
||||
// automatic push right after a sale succeeded, not just what the manual
|
||||
// "Sync" button on this page last did.
|
||||
final engine = ref.watch(syncEngineStateProvider).value ??
|
||||
ref.watch(syncEngineProvider).state;
|
||||
|
||||
final r = report.value;
|
||||
|
||||
return ModulePage(
|
||||
children: [
|
||||
if (engine.lastError != null && pending > 0)
|
||||
_EngineWarningBanner(engine: engine),
|
||||
|
||||
Wrap(
|
||||
spacing: AppSpacing.lg,
|
||||
runSpacing: AppSpacing.lg,
|
||||
@@ -310,3 +323,81 @@ class EventsView extends ConsumerWidget {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Flags a bill that could not reach the server on its own — the automatic
|
||||
/// push right after checkout, not the manual "Sync" button below.
|
||||
///
|
||||
/// Sits above everything else on the page because a bill stuck here is the
|
||||
/// one thing on this screen that needs a person to notice it, rather than
|
||||
/// just waiting for the next background retry.
|
||||
class _EngineWarningBanner extends StatelessWidget {
|
||||
const _EngineWarningBanner({required this.engine});
|
||||
|
||||
final SyncEngineState engine;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final halted = engine.isHalted;
|
||||
final color = halted ? AppColors.danger : AppColors.warning;
|
||||
final surface = halted ? AppColors.dangerSurface : AppColors.warningSurface;
|
||||
|
||||
final retry = engine.nextAttemptAt;
|
||||
final retryNote = halted
|
||||
? 'Retrying will not help until this is fixed — press Sync below '
|
||||
'once it is sorted.'
|
||||
: retry == null
|
||||
? 'It will retry automatically, or press Sync below to try now.'
|
||||
: 'It will retry automatically at ${Formatters.time(retry)}, or '
|
||||
'press Sync below to try now.';
|
||||
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(bottom: AppSpacing.lg),
|
||||
padding: const EdgeInsets.all(AppSpacing.md),
|
||||
decoration: BoxDecoration(color: surface, borderRadius: AppRadius.brLg),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Icon(Icons.wifi_off_rounded, size: 20, color: color),
|
||||
const SizedBox(width: AppSpacing.md),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
halted
|
||||
? 'Sync halted — ${engine.pending} bill(s) not sent'
|
||||
: "Couldn't reach the server — "
|
||||
'${engine.pending} bill(s) not sent',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: color,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
engine.lastError ?? 'The last upload attempt failed.',
|
||||
style: TextStyle(
|
||||
fontSize: 12.5,
|
||||
color: color,
|
||||
height: 1.45,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
'$retryNote Every bill is still safe on this terminal — '
|
||||
'nothing is lost while it waits.',
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
color: AppColors.textSecondary,
|
||||
height: 1.45,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user