import 'package:equatable/equatable.dart'; /// The two moments this terminal talks to the server. enum SyncEventType { catalogueImport('Catalogue Import', 'Pulled products from the server'), shiftReport('Shift Report', 'Pushed the day\'s takings to the server'); const SyncEventType(this.label, this.description); final String label; final String description; bool get isInbound => this == SyncEventType.catalogueImport; } enum SyncStatus { /// Held locally, not yet sent. Nothing is ever discarded in this state. pending('Pending'), syncing('Syncing'), synced('Synced'), failed('Failed'); const SyncStatus(this.label); final String label; bool get isTerminal => this == SyncStatus.synced; bool get needsAttention => this == SyncStatus.failed || this == SyncStatus.pending; } /// A durable record of one sync attempt. /// /// Events are never deleted on failure — a failed push stays queued so the /// day's takings survive a dropped connection. class SyncEvent extends Equatable { const SyncEvent({ required this.id, required this.type, required this.status, required this.createdAt, required this.summary, this.payload = const {}, this.syncedAt, this.error, this.attempts = 0, }); final String id; final SyncEventType type; final SyncStatus status; final DateTime createdAt; /// One-line description shown in the events log. final String summary; /// What would be transmitted. Kept so a retry needs no recomputation. final Map payload; final DateTime? syncedAt; final String? error; final int attempts; SyncEvent copyWith({ SyncStatus? status, DateTime? syncedAt, String? error, bool clearError = false, int? attempts, }) { return SyncEvent( id: id, type: type, status: status ?? this.status, createdAt: createdAt, summary: summary, payload: payload, syncedAt: syncedAt ?? this.syncedAt, error: clearError ? null : (error ?? this.error), attempts: attempts ?? this.attempts, ); } @override List get props => [id, status, attempts, syncedAt]; }