/** * GoingsOn - Groups (shared-workspace) client cache + badge helpers. * * A thin, lazily-populated cache of the groups you belong to, keyed by id, so * the UI can resolve a project's `groupId` to a human name without a round-trip * per render. Sharing is whole-project, so a task's share state is its project's * share state; the badge helpers reflect that. * * The admin/list commands themselves live on `GoingsOn.api.groups`; this module * is only the render-side cache. Invalidate it whenever group membership changes * (a group is created, joined, or renamed). */ (function() { 'use strict'; const esc = GoingsOn.utils.escapeHtml; const escAttr = GoingsOn.utils.escapeAttrValue; let cache = null; // Array of GroupDto, or null when unloaded. let byId = {}; // id -> GroupDto. /** * Load the group list into the cache if it is not already loaded. Non-fatal: * if sync is not configured the cache stays null and names do not * resolve (badges still render as a bare "Shared"). * @returns {Promise} the cached groups (possibly empty) */ async function ensureLoaded() { if (cache) return cache; try { const list = await GoingsOn.api.groups.list(); cache = list; byId = {}; list.forEach(g => { byId[g.id] = g; }); } catch (_) { // Leave cache null so a later call retries once sync is ready. } return cache || []; } /** Group name for an id, or null when unknown / cache not loaded. */ function nameFor(groupId) { if (!groupId) return null; const g = byId[groupId]; return g ? g.name : null; } /** Drop the cache so the next ensureLoaded refetches. */ function invalidate() { cache = null; byId = {}; } /** * Badge HTML for a project's card meta, or '' when the project is personal. * Shows the group name when known, otherwise a bare "Shared". */ function projectCardBadge(project) { if (!project || !project.groupId) return ''; const name = nameFor(project.groupId); const label = name ? `Shared · ${name}` : 'Shared'; return `${esc(label)}`; } /** * Small inline marker for a task row whose project is shared, resolved from * the projects cache (best-effort; no badge if projects are not loaded). */ function taskSharedBadge(projectId) { if (!projectId) return ''; const project = GoingsOn.getProjectsCache().find(p => p.id === projectId); if (!project || !project.groupId) return ''; const name = nameFor(project.groupId); const label = name ? `Shared · ${name}` : 'Shared'; return `Shared`; } GoingsOn.groups = { ensureLoaded, nameFor, invalidate, projectCardBadge, taskSharedBadge, list: () => cache || [], }; })();