99 lines
5.3 KiB
JavaScript
99 lines
5.3 KiB
JavaScript
function createOpportunityCrmServiceRequests({ requestCrmServiceRequest, isCurrentPeriodRequest, bindPopover, closePopover, createSrButton, closeSrForm, allowsCrmActivities, reportProgress, activityCache, setBadgeContent, formatDate, environment }) {
|
|
let status = "idle";
|
|
let byOpportunity = new Map();
|
|
let pending = null;
|
|
let generation = 0;
|
|
let loadedItems = [];
|
|
function reset() { closeSrForm(); closePopover(); generation += 1; pending = null; status = "idle"; byOpportunity = new Map(); loadedItems = []; reportProgress("idle"); }
|
|
function load(token, version, cacheOptions = null) {
|
|
if (!allowsCrmActivities() || !isCurrentPeriodRequest(version)) return;
|
|
if (status === "ready") {
|
|
return Promise.resolve(cacheOptions ? activityCache.write("sr", "all", cacheOptions.cachedAt, loadedItems) : undefined).then(() => true);
|
|
}
|
|
if (!pending) {
|
|
const request = run(token, version, generation, cacheOptions);
|
|
pending = request;
|
|
request.finally(() => { if (pending === request) pending = null; });
|
|
}
|
|
return pending;
|
|
}
|
|
async function run(token, version, currentGeneration, cacheOptions) {
|
|
const isActive = () => currentGeneration === generation;
|
|
status = "loading";
|
|
try {
|
|
const cached = cacheOptions ? await activityCache.read("sr", "all", cacheOptions.cachedAt) : null;
|
|
if (!isActive()) return false;
|
|
if (!cached && cacheOptions?.cacheOnly) { status = "idle"; return false; }
|
|
let items = cached?.items;
|
|
if (!items) {
|
|
reportProgress("running", 0);
|
|
items = await requestCrmServiceRequest(token, version, isActive, (count, total) => {
|
|
if (isActive()) reportProgress("running", count, total);
|
|
});
|
|
if (items && isActive() && cacheOptions) await activityCache.write("sr", "all", cacheOptions.cachedAt, items);
|
|
}
|
|
if (!items || !isActive()) return false;
|
|
const grouped = new Map();
|
|
for (const item of items) {
|
|
const number = item?.OpportunityName_Id_c?.OptyNumber;
|
|
if (!number) continue;
|
|
const key = String(number);
|
|
if (!grouped.has(key)) grouped.set(key, []);
|
|
grouped.get(key).push(item);
|
|
}
|
|
byOpportunity = grouped;
|
|
loadedItems = items;
|
|
status = "ready";
|
|
if (!cached) reportProgress("complete", items.length, items.length);
|
|
return true;
|
|
} catch {
|
|
if (isActive()) { status = "error"; reportProgress("error"); }
|
|
return false;
|
|
}
|
|
}
|
|
function getSummary(optyNumber) {
|
|
if (!allowsCrmActivities() || !optyNumber) return null;
|
|
const items = byOpportunity.get(String(optyNumber)) || [];
|
|
const hours = items.map(item => item.ReportedHours_c).filter(value =>
|
|
(typeof value === "number" || (typeof value === "string" && value.trim() !== "")) && Number.isFinite(Number(value))
|
|
).map(Number);
|
|
return {
|
|
state: status === "ready" ? items.length ? "matched" : "missing" : status,
|
|
reportedHours: hours.length === items.length ? hours.reduce((total, value) => total + value, 0) : null,
|
|
hasUnderFourHours: status === "ready" && hours.some(value => value < 4)
|
|
};
|
|
}
|
|
function createBadge(optyNumber) {
|
|
if (!allowsCrmActivities() || !optyNumber || status === "idle" || status === "loading") return null;
|
|
const items = byOpportunity.get(String(optyNumber)) || [];
|
|
const badge = environment.document.createElement(items.length && status === "ready" ? "button" : "span");
|
|
badge.className = "opportunities-extension-crm-sr-badge";
|
|
badge.setAttribute("data-state", status === "error" ? "error" : items.length ? "matched" : "missing");
|
|
const summary = getSummary(optyNumber);
|
|
const reportedHours = summary.reportedHours !== null
|
|
? new Intl.NumberFormat("en-US", { useGrouping: false, maximumFractionDigits: 10 }).format(summary.reportedHours)
|
|
: "N/A";
|
|
setBadgeContent(badge, "sr", status === "error" ? "?" : items.length ? `${reportedHours}${reportedHours === "N/A" ? "" : "h"}` : "0h");
|
|
const display = value => value === null || value === undefined || value === "" ? "N/A" : String(value);
|
|
const descriptions = items.map(item => [
|
|
`Title: ${display(item.Title)}`,
|
|
`Opportunity: ${display(item.OpportunityName_Id_c?.OptyNumber)}`,
|
|
`Reported Hours: ${display(item.ReportedHours_c)}`,
|
|
`Customer Deadline: ${display(formatDate(item.CustomerDeadline_c))}`,
|
|
`Owner: ${[item.Owner?.PersonFirstName, item.Owner?.PersonLastName].filter(Boolean).join(" ") || "N/A"}`,
|
|
`Email: ${display(item.Owner?.PrimaryEmail?.EmailAddress)}`,
|
|
`Do Not Call: ${display(item.DoNotCallFlag)}`, `Do Not Email: ${display(item.DoNotEmailFlag)}`
|
|
].join("\n"));
|
|
const description = status === "error" ? "Unable to check CRM service requests. See Debug Requests."
|
|
: !items.length ? "No matching CRM service request with status SVC_PENDING_DELIVERY in your SR team."
|
|
: items.map((item, index) => `SR Number: ${display(item.SrNumber)}\n${descriptions[index]}`).join("\n\n");
|
|
badge.setAttribute("aria-label", description);
|
|
badge.title = "Whether a Service Request has been created for the opportunities.";
|
|
if (items.length && status === "ready") bindPopover(badge, items, descriptions);
|
|
if (!items.length && status === "ready") badge.append(createSrButton(String(optyNumber)));
|
|
badge.tabIndex = 0;
|
|
return badge;
|
|
}
|
|
return { reset, load, createBadge, getSummary };
|
|
}
|