General source code refactoring
This commit is contained in:
171
src/features/consumption/trend-controller.js
Normal file
171
src/features/consumption/trend-controller.js
Normal file
@@ -0,0 +1,171 @@
|
||||
function createConsumptionTrendController({
|
||||
messageTypes,
|
||||
CONSUMPTION_TREND_PERIODS,
|
||||
DEFAULT_CONSUMPTION_TREND_PERIOD,
|
||||
appendBackgroundRequestLog,
|
||||
consumptionTrendState,
|
||||
renderConsumptionTrendChart,
|
||||
requestConsumerTokenServiceOnce,
|
||||
sendRuntimeMessage,
|
||||
environment
|
||||
}) {
|
||||
const { document } = environment;
|
||||
function createConsumptionTrendSection(plan) {
|
||||
const section = document.createElement("section");
|
||||
section.className = "opportunities-extension-consumption-trend";
|
||||
section.dataset.subPlanNum = String(plan.subPlanNum || "");
|
||||
section.dataset.period = DEFAULT_CONSUMPTION_TREND_PERIOD;
|
||||
|
||||
const header = document.createElement("header");
|
||||
header.className = "opportunities-extension-consumption-trend-header";
|
||||
|
||||
const periodControls = document.createElement("div");
|
||||
periodControls.className = "opportunities-extension-consumption-periods";
|
||||
periodControls.setAttribute("role", "group");
|
||||
periodControls.setAttribute("aria-label", "Consumption period");
|
||||
|
||||
CONSUMPTION_TREND_PERIODS.forEach((periodOption) => {
|
||||
const button = document.createElement("button");
|
||||
button.type = "button";
|
||||
button.dataset.period = periodOption.value;
|
||||
button.setAttribute("aria-pressed", String(periodOption.value === DEFAULT_CONSUMPTION_TREND_PERIOD));
|
||||
button.textContent = periodOption.label;
|
||||
button.addEventListener("click", () => {
|
||||
section.dataset.period = periodOption.value;
|
||||
consumptionTrendState.consumptionTrendWindowOffsets.set(
|
||||
createConsumptionTrendKey(section.dataset.subPlanNum, periodOption.value),
|
||||
0
|
||||
);
|
||||
loadConsumptionTrendForPanel(section.closest("[role='tabpanel']"), plan, periodOption.value);
|
||||
});
|
||||
periodControls.append(button);
|
||||
});
|
||||
|
||||
const chart = document.createElement("div");
|
||||
chart.className = "opportunities-extension-consumption-chart";
|
||||
chart.setAttribute("aria-live", "polite");
|
||||
header.append(periodControls);
|
||||
section.append(header, chart);
|
||||
return section;
|
||||
}
|
||||
|
||||
function loadConsumptionTrendForPanel(panel, plan, period) {
|
||||
if (!panel) {
|
||||
return;
|
||||
}
|
||||
|
||||
const section = panel.querySelector(".opportunities-extension-consumption-trend");
|
||||
|
||||
if (!section) {
|
||||
return;
|
||||
}
|
||||
|
||||
const subPlanNum = String(plan.subPlanNum || "").trim();
|
||||
const selectedPeriod = CONSUMPTION_TREND_PERIODS.some((item) => item.value === period)
|
||||
? period
|
||||
: DEFAULT_CONSUMPTION_TREND_PERIOD;
|
||||
const key = createConsumptionTrendKey(subPlanNum, selectedPeriod);
|
||||
const chart = section.querySelector(".opportunities-extension-consumption-chart");
|
||||
section.dataset.period = selectedPeriod;
|
||||
chart.dataset.requestKey = key;
|
||||
updateConsumptionPeriodButtons(section, selectedPeriod);
|
||||
|
||||
if (!subPlanNum) {
|
||||
renderConsumptionTrendError(chart, "Sub plan number is unavailable.");
|
||||
return;
|
||||
}
|
||||
|
||||
const cached = consumptionTrendState.consumptionTrendCache.get(key);
|
||||
|
||||
renderConsumptionTrendSkeleton(chart);
|
||||
|
||||
if (cached && cached.status === "loading") {
|
||||
cached.promise
|
||||
.then((items) => renderConsumptionTrendIfCurrent(section, chart, items, selectedPeriod, subPlanNum, key))
|
||||
.catch((error) => renderConsumptionTrendErrorIfCurrent(chart, error.message, key));
|
||||
return;
|
||||
}
|
||||
|
||||
const request = requestConsumerTokenServiceOnce()
|
||||
.then((authorizations) => sendRuntimeMessage({
|
||||
type: messageTypes.requestConsumptionTrend,
|
||||
subPlanNum,
|
||||
period: selectedPeriod,
|
||||
authorization: authorizations && authorizations.accountPlans
|
||||
}))
|
||||
.then((response) => {
|
||||
appendBackgroundRequestLog(response && response.debugRequests);
|
||||
|
||||
if (!response || !response.ok) {
|
||||
throw new Error(response && response.error ? response.error : "Unable to load consumption trend.");
|
||||
}
|
||||
|
||||
return Array.isArray(response.items) ? response.items : [];
|
||||
})
|
||||
.finally(() => {
|
||||
if (consumptionTrendState.consumptionTrendCache.get(key)?.promise === request) {
|
||||
consumptionTrendState.consumptionTrendCache.delete(key);
|
||||
}
|
||||
});
|
||||
|
||||
consumptionTrendState.consumptionTrendCache.set(key, { status: "loading", promise: request });
|
||||
request
|
||||
.then((items) => renderConsumptionTrendIfCurrent(section, chart, items, selectedPeriod, subPlanNum, key))
|
||||
.catch((error) => renderConsumptionTrendErrorIfCurrent(chart, error.message, key));
|
||||
}
|
||||
|
||||
function createConsumptionTrendKey(subPlanNum, period) {
|
||||
return `${subPlanNum}:${period}`;
|
||||
}
|
||||
|
||||
function updateConsumptionPeriodButtons(section, period) {
|
||||
section.querySelectorAll(".opportunities-extension-consumption-periods button").forEach((button) => {
|
||||
button.setAttribute("aria-pressed", String(button.dataset.period === period));
|
||||
});
|
||||
}
|
||||
|
||||
function renderConsumptionTrendIfCurrent(section, chart, items, period, subPlanNum, key) {
|
||||
if (chart.dataset.requestKey === key) {
|
||||
renderConsumptionTrendChart(section, chart, items, period, subPlanNum);
|
||||
}
|
||||
}
|
||||
|
||||
function renderConsumptionTrendErrorIfCurrent(chart, errorMessage, key) {
|
||||
if (chart.dataset.requestKey === key) {
|
||||
renderConsumptionTrendError(chart, errorMessage || "Unable to load consumption trend.");
|
||||
}
|
||||
}
|
||||
|
||||
function renderConsumptionTrendSkeleton(chart) {
|
||||
chart.textContent = "";
|
||||
chart.setAttribute("aria-busy", "true");
|
||||
const skeleton = document.createElement("div");
|
||||
skeleton.className = "opportunities-extension-consumption-chart-skeleton";
|
||||
const announcement = document.createElement("span");
|
||||
announcement.className = "opportunities-extension-visually-hidden";
|
||||
announcement.textContent = "Loading consumption trend";
|
||||
const plot = document.createElement("div");
|
||||
plot.className = "opportunities-extension-consumption-chart-skeleton-plot";
|
||||
|
||||
for (let index = 0; index < 13; index += 1) {
|
||||
const bar = document.createElement("span");
|
||||
bar.style.height = `${28 + ((index * 17) % 58)}%`;
|
||||
plot.append(bar);
|
||||
}
|
||||
|
||||
skeleton.append(announcement, plot);
|
||||
chart.append(skeleton);
|
||||
}
|
||||
|
||||
function renderConsumptionTrendError(chart, errorMessage) {
|
||||
chart.textContent = "";
|
||||
chart.setAttribute("aria-busy", "false");
|
||||
const error = document.createElement("p");
|
||||
error.className = "opportunities-extension-consumption-chart-error";
|
||||
error.setAttribute("role", "alert");
|
||||
error.textContent = errorMessage;
|
||||
chart.append(error);
|
||||
}
|
||||
|
||||
return { createConsumptionTrendSection, loadConsumptionTrendForPanel, createConsumptionTrendKey, updateConsumptionPeriodButtons, renderConsumptionTrendIfCurrent, renderConsumptionTrendErrorIfCurrent, renderConsumptionTrendSkeleton, renderConsumptionTrendError };
|
||||
}
|
||||
Reference in New Issue
Block a user