187 lines
5.2 KiB
JavaScript
187 lines
5.2 KiB
JavaScript
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
|