ec11dd8d2b
Benutzerweiter Vessel-Pool (E2E, Sync, Migration von Legacy-Yachts) mit LogbookVesselSelection und LogbookVesselPicker. Profil mit Accordion (Flotte & Crew); Demo und Onboarding-Tour inkl. profile_vessel_pool. Co-authored-by: Cursor <cursoragent@cursor.com>
84 lines
2.4 KiB
TypeScript
84 lines
2.4 KiB
TypeScript
import { db } from './db.js'
|
|
import { getActiveMasterKey } from './auth.js'
|
|
import { apiFetch } from './api.js'
|
|
|
|
const API_BASE = '/api/auth/person-pool'
|
|
|
|
function isNewer(timeA: string | Date, timeB: string | Date): boolean {
|
|
return new Date(timeA).getTime() > new Date(timeB).getTime()
|
|
}
|
|
|
|
export async function syncPersonPool(): Promise<void> {
|
|
if (!navigator.onLine || !getActiveMasterKey() || !localStorage.getItem('active_userid')) return
|
|
|
|
await pushPersonPool()
|
|
await pullPersonPool()
|
|
}
|
|
|
|
async function pushPersonPool(): Promise<void> {
|
|
const pending = (await db.userSyncQueue.toArray()).filter((item) => item.type === 'person')
|
|
if (pending.length === 0) return
|
|
|
|
try {
|
|
const response = await apiFetch(`${API_BASE}/push`, {
|
|
method: 'POST',
|
|
body: JSON.stringify({ items: pending })
|
|
})
|
|
if (!response.ok) {
|
|
console.warn('Person pool push rejected')
|
|
return
|
|
}
|
|
|
|
const { results } = await response.json()
|
|
for (let i = 0; i < results.length; i++) {
|
|
const res = results[i]
|
|
const item = pending[i]
|
|
if (!item) continue
|
|
if (res.status === 'success' && item.id !== undefined) {
|
|
await db.userSyncQueue.delete(item.id)
|
|
}
|
|
}
|
|
} catch (err) {
|
|
console.warn('Person pool push failed:', err)
|
|
}
|
|
}
|
|
|
|
async function pullPersonPool(): Promise<void> {
|
|
try {
|
|
const response = await apiFetch(API_BASE, { method: 'GET' })
|
|
if (!response.ok) return
|
|
|
|
const { persons } = await response.json()
|
|
if (!Array.isArray(persons)) return
|
|
|
|
const serverMap = new Map<string, (typeof persons)[0]>()
|
|
for (const p of persons) {
|
|
serverMap.set(p.payloadId, p)
|
|
const local = await db.personPool.get(p.payloadId)
|
|
if (!local || isNewer(p.updatedAt, local.updatedAt)) {
|
|
await db.personPool.put({
|
|
payloadId: p.payloadId,
|
|
encryptedData: p.encryptedData,
|
|
iv: p.iv,
|
|
tag: p.tag,
|
|
updatedAt: p.updatedAt
|
|
})
|
|
}
|
|
}
|
|
|
|
const localAll = await db.personPool.toArray()
|
|
for (const local of localAll) {
|
|
if (!serverMap.has(local.payloadId)) {
|
|
const pendingCreate = await db.userSyncQueue
|
|
.where({ payloadId: local.payloadId, action: 'create' })
|
|
.first()
|
|
if (!pendingCreate) {
|
|
await db.personPool.delete(local.payloadId)
|
|
}
|
|
}
|
|
}
|
|
} catch (err) {
|
|
console.warn('Person pool pull failed:', err)
|
|
}
|
|
}
|