stackchain-dashboard/frontend/photo-draft-inbox.js
timmy fa876e1e38
Some checks failed
CI / lint (pull_request) Successful in 3m40s
CI / build-release (pull_request) Successful in 7s
CI / browser-journey (pull_request) Failing after 6m31s
CI / release-candidate (pull_request) Has been skipped
feat: surface photo-only reply drafts in My Work (Closes #1396)
2026-08-25 13:17:23 +00:00

81 lines
3.0 KiB
JavaScript

(function (root, factory) {
const createPhotoDraftInbox = factory();
if (typeof module === 'object' && module.exports) module.exports = createPhotoDraftInbox;
else root.createPhotoDraftInbox = createPhotoDraftInbox;
})(typeof globalThis !== 'undefined' ? globalThis : this, function () {
'use strict';
function targetKey(route) {
if (route?.kind === 'update') {
const notificationId = Number(route.notification_id || 0);
return notificationId > 0 ? 'update:' + notificationId : '';
}
const kind = route?.kind === 'search' ? route.target_kind : route?.kind;
const repository = String(route?.repository || '');
const number = Number(route?.number || 0);
return ['issue', 'pull'].includes(kind) && repository && number > 0 ?
kind + ':' + repository.toLowerCase() + '#' + number : '';
}
function removeTarget(item) {
const route = item?.route || {};
if (route.kind === 'update') return { kind:'update', notificationId:Number(route.notification_id) };
return {
kind:route.kind === 'search' ? route.target_kind : route.kind,
repository:route.repository,
number:Number(route.number),
};
}
return function createPhotoDraftInbox({ conversation, search }) {
let items = [];
async function refresh(existing = []) {
const occupied = new Set(existing.map(item => targetKey(item?.route)).filter(Boolean));
const results = await Promise.allSettled([
conversation?.list?.() || [],
search?.list?.() || [],
]);
items = results.flatMap(result => result.status === 'fulfilled' && Array.isArray(result.value) ? result.value : [])
.filter(item => {
const key = targetKey(item?.route);
if (!key || occupied.has(key)) return false;
occupied.add(key);
return true;
})
.sort((left, right) => Number(right.updated_at || 0) - Number(left.updated_at || 0) ||
String(left.id || '').localeCompare(String(right.id || '')));
return items.slice();
}
function list() { return items.slice(); }
async function discard(item) {
if (!item || !items.some(candidate => candidate.id === item.id && candidate.photo_store === item.photo_store)) {
return false;
}
const store = item.photo_store === 'search' ? search : conversation;
if (!store?.remove) return false;
await store.remove(removeTarget(item));
items = items.filter(candidate => !(candidate.id === item.id && candidate.photo_store === item.photo_store));
return true;
}
function description(item) {
return item?.kind === 'photo-reply' ?
Number(item.photo_count || 0) + (Number(item.photo_count) === 1 ? ' saved photo' : ' saved photos') :
(item?.preview || 'Unfinished draft');
}
function searchTarget(item) {
const route = item?.route || {};
return {
kind:route.target_kind, repository:route.repository,
number:route.number, title:item?.title,
};
}
return { refresh, list, discard, description, searchTarget };
};
});