67 lines
3.2 KiB
JavaScript
67 lines
3.2 KiB
JavaScript
function createConsumptionPlanDetailController({ messageTypes, requestConsumerTokenServiceOnce, sendRuntimeMessage,
|
|
appendBackgroundRequestLog, renderPlanDetailBadges, environment }) {
|
|
const { document } = environment;
|
|
const states = new WeakMap();
|
|
const pending = new Map();
|
|
|
|
function createPlanDetailSection(plan) {
|
|
const section = document.createElement("div");
|
|
section.className = "opportunities-extension-plan-detail-badges";
|
|
section.dataset.subPlanNum = String(plan.subPlanNum || "").trim();
|
|
section.setAttribute("aria-live", "polite");
|
|
states.set(section, { status: "idle" });
|
|
return section;
|
|
}
|
|
async function request(subPlanNum) {
|
|
const authorizations = await requestConsumerTokenServiceOnce();
|
|
const response = await sendRuntimeMessage({ type: messageTypes.requestConsumptionPlanDetail, subPlanNum,
|
|
authorization: authorizations && authorizations.accountPlans });
|
|
appendBackgroundRequestLog(response?.debugRequests);
|
|
if (!response?.ok) throw new Error(response?.error || "Unable to load consumption plan details.");
|
|
return response.items;
|
|
}
|
|
function loadPlanDetailForPanel(panel, plan) {
|
|
const section = panel?.querySelector(".opportunities-extension-plan-detail-badges");
|
|
if (!section) return Promise.resolve();
|
|
const state = states.get(section);
|
|
if (state?.status === "ready") return Promise.resolve();
|
|
if (state?.status === "loading") return state.promise;
|
|
const subPlanNum = String(plan.subPlanNum || "").trim();
|
|
section.textContent = "";
|
|
section.setAttribute("aria-busy", "true");
|
|
const skeleton = document.createElement("span");
|
|
skeleton.className = "opportunities-extension-account-plans-skeleton-bar opportunities-extension-plan-detail-skeleton";
|
|
skeleton.setAttribute("role", "status");
|
|
skeleton.setAttribute("aria-label", "Loading plan projection");
|
|
section.append(skeleton);
|
|
const current = { status: "loading", promise: null };
|
|
states.set(section, current);
|
|
current.promise = (async () => {
|
|
try {
|
|
if (!subPlanNum) throw new Error("Sub plan number is unavailable.");
|
|
if (!pending.has(subPlanNum)) {
|
|
const promise = request(subPlanNum).finally(() => { if (pending.get(subPlanNum) === promise) pending.delete(subPlanNum); });
|
|
pending.set(subPlanNum, promise);
|
|
}
|
|
const items = await pending.get(subPlanNum);
|
|
if (!section.isConnected || states.get(section) !== current) return;
|
|
current.status = "ready";
|
|
renderPlanDetailBadges(section, items);
|
|
} catch (error) {
|
|
if (!section.isConnected || states.get(section) !== current) return;
|
|
current.status = "error";
|
|
section.textContent = "";
|
|
const notice = document.createElement("span");
|
|
notice.className = "opportunities-extension-plan-detail-error";
|
|
notice.setAttribute("role", "alert");
|
|
notice.textContent = error.message || "Unable to load plan details.";
|
|
section.append(notice);
|
|
} finally {
|
|
if (states.get(section) === current) section.setAttribute("aria-busy", "false");
|
|
}
|
|
})();
|
|
return current.promise;
|
|
}
|
|
return { createPlanDetailSection, loadPlanDetailForPanel, resetRequests: () => pending.clear() };
|
|
}
|