Tofu/app/services/planning/createPlanningStore.js
2026-09-18 01:41:02 +02:00

48 lines
1.9 KiB
JavaScript

// Remote planning storage, backed by a WebDAV client.
//
// This factory and createMemoryPlanningStore implement the SAME contract on
// purpose: loadWeek / saveWeek / describeStorage. The page picks one of them
// once and never has to test `client === null` afterwards. Two implementations,
// one contract — that is what makes this brick replaceable.
function buildPlanningPath(folder, weekId) {
return folder + '/plannings/' + weekId + '.json'
}
// MKCOL only creates one level at a time, so the root folder comes first.
async function ensurePlanningFolder(client, folder) {
await client.ensureFolder(folder)
return client.ensureFolder(folder + '/plannings')
}
export function createPlanningStore(client, folder) {
// No try/catch here: the client already turns every network failure into a
// result object (see app/services/webdav), so nothing below can throw.
async function loadWeek(weekId) {
const result = await client.readJson(buildPlanningPath(folder, weekId))
if (result.ok) return { ok: true, planning: result.data }
// A week that was never written is not an error, it is an empty week.
if (result.failure.kind === 'notFound') return { ok: true, planning: null }
return { ok: false, failure: result.failure }
}
async function saveWeek(weekId, planning) {
const path = buildPlanningPath(folder, weekId)
const result = await client.writeJson(path, planning)
if (result.ok) return { ok: true }
// 409 means the parent folder is missing: create it and retry once.
if (result.failure.kind !== 'conflict') return result
const folderResult = await ensurePlanningFolder(client, folder)
if (!folderResult.ok) return folderResult
return client.writeJson(path, planning)
}
function describeStorage() {
return {
kind: 'nextcloud',
label: 'Enregistré sur Nextcloud dans « ' + folder + ' »'
}
}
return { loadWeek, saveWeek, describeStorage }
}