88 lines
4.2 KiB
Markdown
88 lines
4.2 KiB
Markdown
## KoolTap Flutter App — Planned Tab Sync
|
|
|
|
Add support for **planned tab names** that are synced from the server. The server now returns a `plannedTabNames` list in the sync response. The app should create open tabs for any planned names that don't already have an open tab.
|
|
|
|
### Background
|
|
|
|
The dashboard admin can manage a list of "planned customers" (e.g. "Jan", "Marie", "Thomas"). These names are sent to the device in every sync response. The device should ensure those tabs exist — creating new ones if a planned name doesn't already have an open tab.
|
|
|
|
### Existing Files (read these first)
|
|
|
|
- `lib/models/remote_command.dart` — contains `SyncResponse`, `RemoteCommand`, `SnapshotTab`, etc.
|
|
- `lib/services/remote_sync_service.dart` — the sync loop that processes the sync response
|
|
- `lib/services/bar_tab_service.dart` — creates and manages tabs (has `createTab(String customerName)`)
|
|
- `lib/models/bar_tab.dart` — the `BarTab` model
|
|
- `lib/database/app_database.dart` — the Drift database schema
|
|
- `lib/viewmodels/remote_sync_view_model.dart` — wraps the sync service as `ChangeNotifier`
|
|
- `lib/utils/app_config.dart` — server URL constant
|
|
|
|
### What to Change
|
|
|
|
#### 1. Update `SyncResponse` model
|
|
In `lib/models/remote_command.dart`, add `plannedTabNames` to the existing `SyncResponse` class (it already exists — add the field):
|
|
|
|
```dart
|
|
class SyncResponse {
|
|
final String cursor;
|
|
final List<RemoteCommand> commands;
|
|
final List<String> plannedTabNames; // ← add this
|
|
|
|
SyncResponse({
|
|
required this.cursor,
|
|
required this.commands,
|
|
required this.plannedTabNames, // ← add this
|
|
});
|
|
|
|
factory SyncResponse.fromJson(Map<String, dynamic> json) => SyncResponse(
|
|
cursor: json['cursor'] as String,
|
|
commands: (json['commands'] as List)
|
|
.map((e) => RemoteCommand.fromJson(e as Map<String, dynamic>))
|
|
.toList(),
|
|
plannedTabNames: (json['plannedTabNames'] as List?) // ← add this
|
|
?.map((e) => e as String)
|
|
.toList() ?? [],
|
|
);
|
|
}
|
|
```
|
|
|
|
#### 2. Process planned names in the sync service
|
|
In `lib/services/remote_sync_service.dart`, inside the `_performSync()` method (or wherever the sync response is handled), add logic to process `plannedTabNames` **after** commands are processed but **before** updating the cursor.
|
|
|
|
The logic:
|
|
```dart
|
|
// After processing commands and before updating cursor:
|
|
// Ensure planned tabs exist
|
|
for (final name in response.plannedTabNames) {
|
|
final hasOpenTab = openTabs.any((t) => t.customerName == name);
|
|
if (!hasOpenTab) {
|
|
await barTabService.createTab(name);
|
|
}
|
|
}
|
|
// Also: if a tab is open for a customer NOT in plannedTabNames,
|
|
// should we close it? Probably not — just leave it.
|
|
```
|
|
|
|
Where `openTabs` is the list of currently open tabs (already available from `barTabService.getOpenTabs()` or similar). Look for `getOpenTabs()` in `BarTabService` or access the local database.
|
|
|
|
#### 3. Handle the first sync (no existing tabs)
|
|
On first sync, the device might have zero open tabs and receive a list of planned names. The code should create tabs for all planned names.
|
|
|
|
### Important Notes
|
|
|
|
- `BarTabService.createTab(String customerName)` already exists — it opens a new tab with version 1. Call it directly.
|
|
- Do NOT close existing tabs that aren't in the planned list — planned tabs are additive only
|
|
- If a planned name already has an open tab (same `customerName`), skip creating it
|
|
- The sync service already tracks `openTabs` — it sends them in the `SyncRequest` via `SnapshotTab`. You can get the current open tabs from the local database using `BarTabService.getOpenTabs()` or `BarTabService.openTabs` stream
|
|
- This logic should run inside the existing sync loop, after processing commands but before saving the cursor
|
|
|
|
### Testing
|
|
|
|
- Add "Jan" and "Marie" as planned names in the dashboard
|
|
- Run a sync on the Flutter app — tabs for "Jan" and "Marie" should appear
|
|
- Remove "Jan" from planned names and re-sync — the "Jan" tab should NOT be closed (planned tabs are additive only)
|
|
- Add a new name "Thomas" — a new tab should appear on next sync
|
|
|
|
### Files to Modify
|
|
|
|
- `lib/models/remote_command.dart` — add `plannedTabNames` field to `SyncResponse`
|
|
- `lib/services/remote_sync_service.dart` — add planned tab creation logic in sync loop |