Files
byre/web/dist/drafts.js
T

187 lines
5.2 KiB
JavaScript
Raw Normal View History

2026-10-16 08:42:48 -07:00
import { findTask, onEach, state } from "./state.js";
const composerTexts = new Map();
const composerImages = new Map();
const sending = new Set();
const lostImages = new Map();
const checked = new Map();
const texts = new Map();
let storeKey;
let timer = 0;
export function loadDrafts() {
storeKey = `byre.drafts.${state.me.login}`;
const saved = readSaved(storeKey);
for (const [key, d] of Object.entries(saved.composer)) {
if (d.text) {
composerTexts.set(key, d.text);
}
if (d.images > 0) {
lostImages.set(key, d.images);
}
}
for (const [id, opts] of Object.entries(saved.checked)) {
checked.set(id, opts);
}
for (const [id, text] of Object.entries(saved.texts)) {
texts.set(id, text);
}
prune();
onEach(["tasks", "inbox"], prune);
addEventListener("pagehide", flushDrafts);
}
function readSaved(key) {
const out = { composer: {}, checked: {}, texts: {} };
let raw;
try {
raw = JSON.parse(localStorage.getItem(key) ?? "{}");
}
catch (err) {
console.error("read drafts", err);
return out;
}
if (!isRecord(raw)) {
return out;
}
for (const [k, v] of Object.entries(isRecord(raw["composer"]) ? raw["composer"] : {})) {
if (isRecord(v) && typeof v["text"] === "string" && typeof v["images"] === "number") {
out.composer[k] = { text: v["text"], images: v["images"] };
}
}
for (const [k, v] of Object.entries(isRecord(raw["checked"]) ? raw["checked"] : {})) {
if (Array.isArray(v) && v.every((o) => typeof o === "string")) {
out.checked[k] = v;
}
}
for (const [k, v] of Object.entries(isRecord(raw["texts"]) ? raw["texts"] : {})) {
if (typeof v === "string") {
out.texts[k] = v;
}
}
return out;
}
function isRecord(v) {
return typeof v === "object" && v !== null && !Array.isArray(v);
}
function prune() {
let changed = false;
for (const map of [composerTexts, composerImages, lostImages]) {
for (const key of map.keys()) {
const taskId = key.replace(/^message:/, "");
if (taskId !== "lead" && findTask(taskId)?.status !== "active") {
map.delete(key);
changed = true;
}
}
}
for (const map of [checked, texts]) {
for (const id of map.keys()) {
if (!state.inbox.some((i) => i.id === id)) {
map.delete(id);
changed = true;
}
}
}
if (changed) {
save();
}
}
function save() {
clearTimeout(timer);
timer = setTimeout(flushDrafts, 400);
}
export function flushDrafts() {
clearTimeout(timer);
timer = 0;
if (!storeKey) {
return;
}
const out = { composer: {}, checked: Object.fromEntries(checked), texts: Object.fromEntries(texts) };
const keys = new Set([...composerTexts.keys(), ...composerImages.keys(), ...[...sending].map((s) => s.key), ...lostImages.keys()]);
for (const key of keys) {
const inFlight = [...sending].filter((s) => s.key === key);
const text = [...inFlight.map((s) => s.text), composerTexts.get(key) ?? ""].filter((t) => t).join("\n\n");
const images = (composerImages.get(key) ?? 0) + inFlight.reduce((n, s) => n + s.images, 0) + (lostImages.get(key) ?? 0);
if (text || images > 0) {
out.composer[key] = { text, images };
}
}
try {
localStorage.setItem(storeKey, JSON.stringify(out));
}
catch (err) {
console.error("save drafts", err);
}
}
export function composerText(key) {
return composerTexts.get(key) ?? "";
}
export function setComposerText(key, text) {
if (text) {
composerTexts.set(key, text);
}
else {
composerTexts.delete(key);
}
save();
}
export function setComposerImages(key, n) {
if (n > 0) {
composerImages.set(key, n);
}
else {
composerImages.delete(key);
}
save();
}
export function lostImageCount(key) {
return lostImages.get(key) ?? 0;
}
export function forgetLostImages(key) {
lostImages.delete(key);
save();
}
export function startSend(key, text, images) {
const send = { key, text, images };
sending.add(send);
composerTexts.delete(key);
return send;
}
export function endSend(send, ok) {
sending.delete(send);
if (ok) {
lostImages.delete(send.key);
}
else {
const text = [send.text, composerTexts.get(send.key) ?? ""].filter((t) => t).join("\n\n");
if (text) {
composerTexts.set(send.key, text);
}
}
flushDrafts();
}
export function checkedAnswer(id) {
return checked.get(id) ?? [];
}
export function setCheckedAnswer(id, options) {
checked.set(id, options);
save();
}
export function hasTextAnswer(id) {
return texts.has(id);
}
export function textAnswer(id) {
return texts.get(id);
}
export function setTextAnswer(id, text) {
texts.set(id, text);
save();
}
export function dropTextAnswer(id) {
texts.delete(id);
save();
}
export function clearAnswer(id) {
checked.delete(id);
texts.delete(id);
flushDrafts();
}
//# sourceMappingURL=drafts.js.map