feat: Sprachnotizen in Synchronisierung, Warteschlange und Abmelden (T7 L5 Task 18)
Wartende Sprachnotizen werden nach Einträgen und Fotos hochgeladen, je Notiz ein fester Idempotency-Key; endgültige 4xx markieren die Notiz mit festem deutschem Text, 401/408/429/5xx/Netz warten auf den nächsten Lauf, „wird bearbeitet“ wird übersprungen. Warteschlangen-Sheet mit Abschnitt „Sprachnotizen“ (Verwerfen je Notiz nur für den Besitzer, alle verwerfen mit Rückfrage, Hinweis bei zu vielen offenen Notizen), Offline-Band zählt nur wartende Notizen, Abmelden fragt bei wartenden Notizen nach. Zählen liest keine Audiodaten. Gates: Frontend lint, typecheck, 2886 Tests. Refs #27 Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
0c7147f626
commit
e614ded967
18 files changed
+1201
-30
No files matched your search
@@ -1,4 +1,4 @@
|
||||
import { getDb, type StoredVoiceNote } from "@/lib/offline/db";
|
||||
import { getDb, type QueueError, type StoredVoiceNote } from "@/lib/offline/db";
|
||||
import { newIdempotencyKey } from "@/lib/offline/idempotency";
|
||||
|
||||
export type { StoredVoiceNote } from "@/lib/offline/db";
|
||||
@@ -13,7 +13,7 @@ export type { StoredVoiceNote } from "@/lib/offline/db";
|
||||
/** The device had no room left for another recording. */
|
||||
export class VoiceStorageFullError extends Error {
|
||||
constructor() {
|
||||
super("Auf dem Gerät ist kein Platz mehr für die Aufnahme.");
|
||||
super("Auf dem Gerät ist kein Platz mehr für die Sprachnotiz.");
|
||||
this.name = "VoiceStorageFullError";
|
||||
}
|
||||
}
|
||||
@@ -98,3 +98,33 @@ export async function discardAllPendingVoice(ownerUserId: string): Promise<numbe
|
||||
await tx.done;
|
||||
return ids.length;
|
||||
}
|
||||
|
||||
/** One note by id, or undefined when it is gone (discarded meanwhile). */
|
||||
export async function getPendingVoice(id: string): Promise<StoredVoiceNote | undefined> {
|
||||
const db = await getDb();
|
||||
return db.get("pending-voice", id);
|
||||
}
|
||||
|
||||
/** Books the server's refusal on a note that still exists; the audio stays for the user to see. */
|
||||
export async function markVoiceFailed(id: string, error: QueueError): Promise<void> {
|
||||
const db = await getDb();
|
||||
const tx = db.transaction("pending-voice", "readwrite");
|
||||
const note = await tx.store.get(id);
|
||||
if (note) {
|
||||
const rejected: StoredVoiceNote = { ...note, lastError: error, state: "recorded" };
|
||||
delete rejected.blockedBy;
|
||||
await tx.store.put(rejected);
|
||||
}
|
||||
await tx.done;
|
||||
}
|
||||
|
||||
/** Notes that the server could take later (too many open): the sheet says so. */
|
||||
export async function markVoiceBlocked(id: string, blockedBy: "TOO_MANY_OPEN"): Promise<void> {
|
||||
const db = await getDb();
|
||||
const tx = db.transaction("pending-voice", "readwrite");
|
||||
const note = await tx.store.get(id);
|
||||
if (note) {
|
||||
await tx.store.put({ ...note, blockedBy });
|
||||
}
|
||||
await tx.done;
|
||||
}
|
||||
Reference in new issue
Block a user