forked from StellarSplit/StellarSplit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdraftRegistry.ts
More file actions
118 lines (102 loc) · 3.34 KB
/
Copy pathdraftRegistry.ts
File metadata and controls
118 lines (102 loc) · 3.34 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import type { DraftType, DraftMetadata, DraftEntry, DraftStorage } from '../types/draft';
const DRAFT_STORAGE_KEY = 'stellarsplit_drafts';
const DRAFT_EXPIRY_DAYS = 30; // Drafts expire after 30 days
const CURRENT_VERSION = 1;
class DraftRegistry {
private getStorage(): DraftStorage {
try {
const raw = localStorage.getItem(DRAFT_STORAGE_KEY);
let storage: DraftStorage;
if (raw) {
const parsed = JSON.parse(raw);
// Version mismatch fallback
if (!parsed.version || parsed.version !== CURRENT_VERSION) {
// Clear incompatible storage
storage = { version: CURRENT_VERSION, drafts: {} };
localStorage.setItem(DRAFT_STORAGE_KEY, JSON.stringify(storage));
} else {
storage = parsed;
}
} else {
storage = { version: CURRENT_VERSION, drafts: {} };
}
// Prune expired drafts
const now = new Date();
const expiryTime = DRAFT_EXPIRY_DAYS * 24 * 60 * 60 * 1000; // 30 days in ms
Object.keys(storage.drafts).forEach(key => {
const draft = storage.drafts[key];
const updatedAt = new Date(draft.metadata.updatedAt);
if (now.getTime() - updatedAt.getTime() > expiryTime) {
delete storage.drafts[key];
}
});
// Save pruned storage back if we had raw data
if (raw) {
localStorage.setItem(DRAFT_STORAGE_KEY, JSON.stringify(storage));
}
return storage;
} catch {
return { version: CURRENT_VERSION, drafts: {} };
}
}
private setStorage(storage: DraftStorage): void {
storage.version = CURRENT_VERSION;
localStorage.setItem(DRAFT_STORAGE_KEY, JSON.stringify(storage));
}
save(key: string, data: any, type: DraftType, title?: string): void {
const storage = this.getStorage();
storage.drafts[key] = {
data,
metadata: {
key,
type,
updatedAt: new Date().toISOString(),
title,
},
};
this.setStorage(storage);
}
load(key: string): any | null {
const storage = this.getStorage();
const entry = storage.drafts[key];
return entry ? entry.data : null;
}
list(): DraftMetadata[] {
const storage = this.getStorage();
return Object.values(storage.drafts).map(entry => entry.metadata);
}
delete(key: string): void {
const storage = this.getStorage();
delete storage.drafts[key];
this.setStorage(storage);
}
// Migration helpers for existing drafts
migrateWizardDraft(): void {
const oldKey = 'splitwizard_draft';
const raw = localStorage.getItem(oldKey);
if (raw) {
try {
const data = JSON.parse(raw);
this.save('wizard', data, 'wizard', data.title || 'Split Wizard Draft');
localStorage.removeItem(oldKey);
} catch {
// ignore
}
}
}
migrateReceiptDraft(splitId: string): void {
const oldKey = `stellarsplit-receipt-draft:${splitId}`;
const raw = localStorage.getItem(oldKey);
if (raw) {
try {
const data = JSON.parse(raw);
const title = data.imageName || data.manualEntry?.merchant || `Receipt Draft ${splitId}`;
this.save(`receipt:${splitId}`, data, 'receipt', title);
localStorage.removeItem(oldKey);
} catch {
// ignore
}
}
}
}
export const draftRegistry = new DraftRegistry();