- You do not have access to update
+
@@ -163,6 +163,8 @@
+
+
diff --git a/widget/js/authManager.js b/widget/js/authManager.js
index 8fd7aba..97c3229 100644
--- a/widget/js/authManager.js
+++ b/widget/js/authManager.js
@@ -10,4 +10,15 @@ const authManager = {
});
});
},
+ login: () => {
+ return new Promise((resolve, reject) => {
+ buildfire.auth.login({ allowCancel: true }, (err, user) => {
+ if (err) {
+ reject(err);
+ } else {
+ resolve(user);
+ }
+ });
+ });
+ },
};
diff --git a/widget/js/classes/histories.js b/widget/js/classes/histories.js
new file mode 100644
index 0000000..7bc49be
--- /dev/null
+++ b/widget/js/classes/histories.js
@@ -0,0 +1,110 @@
+class Histories {
+ constructor() {}
+
+ // Get the big Object (history object)
+ static getHistories(clientProfile) {
+ return new Promise((resolve, reject) => {
+ buildfire.publicData.get(`history${clientProfile}`, (err, result) => {
+ if (err) {
+ console.error(err);
+ return reject(err);
+ }
+ else {
+ // Check if there is already objects in the database
+ if (!result.data.metrics) {
+ // If there is no object, then create the parent object
+ buildfire.publicData.save(
+ { metrics: {} },
+ `history${clientProfile}`,
+ (err, result) => {
+ if (err) {
+ console.error(err);
+ return reject(err);
+ }
+ else {
+ this.getHistories(clientProfile).then((result) => {
+ resolve(result);
+ });
+ }
+ }
+ );
+ } else {
+ result.data.id = result.id;
+ resolve(result.data);
+ }
+ }
+ });
+ });
+ }
+
+ static updateMetricHistory({ clientProfile, nodeSelector, historyId }, data) {
+ const absoluteDate = helpers.getAbsoluteDate();
+ const dateOnly = helpers.getAbsoluteDate().slice(0, 10);
+
+ return new Promise((resolve, reject) => {
+ if (!nodeSelector) return reject("nodeSelector not provided");
+ if (!historyId) return reject("historyId not provided");
+ if (
+ nodeSelector.slice(-7) === "metrics" ||
+ nodeSelector.slice(-8) === "metrics."
+ ) {
+ console.error("ERROR");
+ return reject("nodeSelector is not right");
+ }
+
+ buildfire.publicData.searchAndUpdate(
+ { [`${nodeSelector}.history.date`]: { $regex: `.*${dateOnly}.*` } },
+ {
+ $set: {
+ [`${nodeSelector}.history.$.value`]: data.value,
+ [`${nodeSelector}.history.$.lastUpdatedOn`]: new Date(),
+ [`${nodeSelector}.history.$.lastUpdatedBy`]: data.username,
+ },
+ },
+ `history${clientProfile}`,
+ (err, res) => {
+ if (err) {
+ console.error(err);
+ return reject(err);
+ }
+ if (res.nModified === 0) {
+ buildfire.publicData.update(
+ historyId,
+ {
+ $push: {
+ [`${nodeSelector}.history`]: {
+ date: absoluteDate,
+ createdOn: new Date(),
+ createdBy: data.username,
+ lastUpdatedOn: new Date(),
+ lastUpdatedBy: data.username,
+ value: data.value,
+ },
+ },
+ },
+ `history${clientProfile}`,
+ (err, result) => {
+ if (err) {
+ console.error(err);
+ return reject(err);
+ } else {
+ result.data.id = result.id;
+ resolve(result.data);
+ }
+ }
+ );
+ }
+ // Extract metric id from nodeSelector
+ let updatedMetricId = nodeSelector.slice().split(".");
+ updatedMetricId = updatedMetricId[updatedMetricId.length - 1];
+ // Track action
+ Analytics.trackAction(`METRIC_${updatedMetricId}_HISTORY_UPDATE`);
+
+ Metrics.getMetrics().then((result) => {
+ resolve(result);
+ });
+ }
+ );
+ });
+ }
+}
diff --git a/widget/js/classes/history.js b/widget/js/classes/history.js
new file mode 100644
index 0000000..29b7841
--- /dev/null
+++ b/widget/js/classes/history.js
@@ -0,0 +1,6 @@
+class ClientHistory {
+ constructor(data = {}) {
+ this.id = data.id || "";
+ this.history = data.history || [];
+ }
+}
diff --git a/widget/js/classes/metrics.js b/widget/js/classes/metrics.js
index 2e2854a..080245c 100644
--- a/widget/js/classes/metrics.js
+++ b/widget/js/classes/metrics.js
@@ -3,28 +3,14 @@ class Metrics {
static getMetrics() {
return new Promise((resolve, reject) => {
- buildfire.publicData.get("metrics", (err, result) => {
+ buildfire.datastore.get("metrics", (err, result) => {
if (err) reject(err);
else {
- // Check if there is already objects in the database
- if (!result.data.metrics) {
- // If there is no object, then create the parent object
- buildfire.publicData.save(
- { metrics: {}, sortBy: "manual" },
- "metrics",
- (err, result) => {
- if (err) reject(err);
- else {
- this.getMetrics().then((result) => {
- resolve(result);
- });
- }
- }
- );
- } else {
- result.data.id = result.id;
- resolve(result.data);
+ if (!result || !result.data) {
+ result = { data: { metrics: {} } };
}
+ result.data.id = result.id;
+ resolve(result.data);
}
});
});
@@ -32,6 +18,7 @@ class Metrics {
static updateMetricHistory({ nodeSelector, metricsId }, data) {
const absoluteDate = helpers.getAbsoluteDate();
+ const dateOnly = helpers.getAbsoluteDate().slice(0, 10);
return new Promise((resolve, reject) => {
if (!nodeSelector) return reject("nodeSelector not provided");
@@ -41,9 +28,8 @@ class Metrics {
nodeSelector.slice(-8) === "metrics."
)
return reject("nodeSelector is not right");
-
- buildfire.publicData.searchAndUpdate(
- { [`${nodeSelector}.history.date`]: absoluteDate },
+ buildfire.datastore.searchAndUpdate(
+ { [`${nodeSelector}.history.date`]: { $regex: `.*${dateOnly}.*` } },
{
$set: {
[`${nodeSelector}.history.$.value`]: data.value,
@@ -55,7 +41,7 @@ class Metrics {
(err, res) => {
if (err) reject(err);
if (res.nModified === 0) {
- buildfire.publicData.update(
+ buildfire.datastore.update(
metricsId,
{
$push: {
@@ -93,51 +79,179 @@ class Metrics {
});
}
- static getHistoryValue(metric, inde) {
+ // static getHistoryValue(metric, inde) {
+ // if (metric.type === "metric") {
+ // let todayDate = new Date();
+ // for (var i = 1; i <= 7; i++) {
+ // if (metric.history[metric.history.length - i]) {
+ // let metricHistoryDate = new Date(
+ // metric.history[metric.history.length - i].date
+ // );
+ // const diffTime = Math.abs(todayDate - metricHistoryDate);
+ // const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
+
+ // if (diffDays >= inde) {
+ // let val = metric.history[metric.history.length - i].value;
+ // if (inde === 1) {
+ // metric.value = val || 0;
+ // } else if (inde === 2) {
+ // metric.previousValue = val || 0;
+ // }
+ // return val;
+ // }
+ // }
+ // }
+ // return "No value";
+ // } else if (metric.type === "parent" || !metric.type) {
+ // if (metric.metrics && Object.keys(metric.metrics).length === 0) {
+ // return "No value";
+ // }
+ // if (metric.metrics) {
+ // let sum = 0;
+ // let numberChildren = 0;
+ // for (let key in metric.metrics) {
+ // let result = Metrics.getHistoryValue(metric.metrics[key], inde);
+ // if (!isNaN(result)) {
+ // numberChildren++;
+ // sum += Metrics.getHistoryValue(metric.metrics[key], inde);
+ // }
+ // }
+ // let avg = sum / numberChildren;
+ // if (inde === 1) {
+ // metric.value = parseFloat(avg.toPrecision(3)) || 0;
+ // } else if (inde === 2) {
+ // metric.previousValue = parseFloat(avg.toPrecision(3)) || 0;
+ // }
+ // return avg;
+ // }
+ // return 0;
+ // }
+ // }
+
+ static extractHistoryValues(metric) {
if (metric.type === "metric") {
- let todayDate = helpers.getAbsoluteDate();
- for (var i = 1; i <= 7; i++) {
- if (metric.history[metric.history.length - i]) {
- if (
- new Date(
- todayDate -
- new Date(metric.history[metric.history.length - i].date)
- ).getDate() >= inde
- ) {
- let val = metric.history[metric.history.length - i].value;
- if (inde === 1) {
- metric.value = val || 0;
- } else if (inde === 2) {
- metric.previousValue = val || 0;
+ // Get the metric history array
+ let history = metric.history;
+
+ // Creates the set to be able to calculate the average in this format:
+ // [{"date":"11/14/2020","value":0},{"date":"11/13/2020","value":0}, .....]
+ let dataset = helpers.getLast7Days();
+
+ // To track which value from the history to take;
+ let index = 1;
+
+ // Loop throw the set created above
+ dataset.forEach((set) => {
+ if (!history[history.length - index]) {
+ // This means that this has no value change at this date
+ set.value = "No value";
+ } else {
+ // Convert the ISO date from the coming from the database to local date
+ let historyDate = new Date(
+ history[history.length - index].date
+ ).toLocaleDateString();
+
+ // If the saved date was one day ahead of the current date, don't take the current value, take the previous one;
+ if (set.date < historyDate) {
+ index++;
+ set.value = history[history.length - index].value || 0;
+
+ // Check if there is another element in the history
+ if (
+ history[history.length - index] &&
+ history[history.length - index].date
+ ) {
+ let lastDate = new Date(
+ history[history.length - index].date
+ ).toLocaleDateString();
+ // If the previous value's date === the the current set.date we just used then we need to move on to the next value,
+ // other wise we skip
+ if (set.date === lastDate) {
+ index++;
+ }
+ } else {
+ set.value = history[history.length - index].value
+ ? history[history.length - index].value
+ : 0;
}
- return val;
+ } else if (set.date === historyDate) {
+ set.value = history[history.length - index].value || 0;
+ index++;
+ } else {
+ set.value = history[history.length - index].value
+ ? history[history.length - index].value
+ : 0;
}
}
- }
- return "No value";
+ });
+ // Assign current and previous average for the child metric
+ metric.value =
+ dataset[0] && !isNaN(dataset[0].value) ? dataset[0].value : 0;
+ metric.previousValue =
+ dataset[1] && !isNaN(dataset[1].value) ? dataset[1].value : 0;
+
+ return dataset;
} else if (metric.type === "parent" || !metric.type) {
if (metric.metrics && Object.keys(metric.metrics).length === 0) {
- return "No value";
- }
- if (metric.metrics) {
- let sum = 0;
- let numberChildren = 0;
+ return helpers.getLast7DaysNoValue();
+ } else if (metric.metrics) {
+ // Creates the set to be able to calculate the average in this format:
+ let historyDataset = helpers.getLast7DaysNoValue();
+ // [{"date":"11/14/2020","value":0},{"date":"11/13/2020","value":0}, .....]
for (let key in metric.metrics) {
- let result = Metrics.getHistoryValue(metric.metrics[key], inde);
- if (!isNaN(result)) {
- numberChildren++;
- sum += Metrics.getHistoryValue(metric.metrics[key], inde);
- }
- }
- let avg = sum / numberChildren;
- if (inde === 1) {
- metric.value = parseFloat(avg.toPrecision(3)) || 0;
- } else if (inde === 2) {
- metric.previousValue = parseFloat(avg.toPrecision(3)) || 0;
+ let metricHistory = Metrics.extractHistoryValues(metric.metrics[key]);
+
+ historyDataset.forEach((day, i) => {
+ if (!isNaN(metricHistory[i].value)) {
+ if (isNaN(day.value)) day.value = 0;
+ day.value += metricHistory[i].value;
+
+ // Add-increase the value of children which have values (type number) to calculate the average
+ // based on the sum of the calculated children
+ if (!day.increased) {
+ day.increased = 1;
+ } else day.increased++;
+ }
+ });
}
- return avg;
+ // Calculate the average
+ historyDataset.forEach((input) => {
+ if (input.increased) {
+ input.value = input.value / input.increased;
+ }
+ });
+ // Assign current and previous average for the parent metric
+ metric.value = !isNaN(historyDataset[0].value)
+ ? parseFloat(historyDataset[0].value.toPrecision(3))
+ : 0;
+ metric.previousValue = !isNaN(historyDataset[1].value)
+ ? parseFloat(historyDataset[1].value.toPrecision(3))
+ : 0;
+
+ return historyDataset;
}
- return 0;
}
}
+
+ static getHistoryValues(metrics) {
+ // Reverse the data to be displayed on the chart
+ let historyDataset = Metrics.extractHistoryValues(metrics).reverse();
+
+ // Extract the values only from the history
+ let historyData = historyDataset.map((elem) => {
+ if (isNaN(elem.value)) return 0;
+ return parseFloat(elem.value.toPrecision(3));
+ });
+ // Format the dates which will appear on the chart
+ let historyDays = historyDataset.map((elem) => {
+ let date = elem.date.split("/");
+ date.pop();
+ return date.join("/");
+ });
+
+ return {
+ historyData,
+ historyDays,
+ };
+ }
}
diff --git a/widget/js/helper.js b/widget/js/helper.js
index 0ff2c76..b57e806 100644
--- a/widget/js/helper.js
+++ b/widget/js/helper.js
@@ -3,7 +3,7 @@ const helpers = {
uuidv4: (m = Math, d = Date, h = 16, s = (s) => m.floor(s).toString(h)) =>
s(d.now() / 1000) + " ".repeat(h).replace(/./g, () => s(m.random() * h)),
// Return absolute date
- getAbsoluteDate: () => new Date(new Date().setHours(0, 0, 0, 0)),
+ getAbsoluteDate: () => new Date().toISOString(),
nodeSplitter: (nodeSelector, metrics) => {
let splittedNode = nodeSelector.split(".");
if (splittedNode[splittedNode.length - 1] !== "metrics") {
@@ -15,20 +15,37 @@ const helpers = {
let metricsParent = null;
let metricsSortBy = "";
- splittedNode.forEach((item, i) => {
- // If we are at the home page (top of the object)
- if (nodeSelector === "metrics") {
- metricsParent = metrics;
- metricsSortBy = metrics.sortBy;
- }
- // Assign the parent metric sortBy value (If we are in parent metric);
- if (nodeSelector !== "metrics" && i === splittedNode.length - 2) {
- metricsParent = metricsChildren[item];
- metricsSortBy = metricsChildren[item].sortBy;
+ try {
+ splittedNode.forEach((item, i) => {
+ // If we are at the home page (top of the object)
+ if (nodeSelector === "metrics") {
+ metricsParent = metrics;
+ metricsSortBy = metrics.sortBy;
+ }
+ // Assign the parent metric sortBy value (If we are in parent metric);
+ if (nodeSelector !== "metrics" && i === splittedNode.length - 2) {
+ metricsParent = metricsChildren[item];
+ metricsSortBy = metricsChildren[item].sortBy;
+ }
+
+ metricsChildren = metricsChildren[item];
+ });
+ } catch (err) {
+ let snackbar = helpers.getElem('.mdc-snackbar .mdc-snackbar__label');
+ // Change snackbar error text
+ if (isDeeplink) {
+ snackbar.innerHTML = "The note you selected has been removed, taking you back home."
+ } else {
+ snackbar.innerHTML = "Something went wrong, taking you back home."
}
+ // Show snackbar
+ snackbarMessages.open();
+
+ setTimeout(() => {
+ buildfire.navigation._goBackOne();
+ }, 2000);
+ }
- metricsChildren = metricsChildren[item];
- });
return { metricsChildren, metricsSortBy, metricsParent };
},
sortMetrics: (currentMetricList, sortBy) => {
@@ -42,19 +59,19 @@ const helpers = {
}
return currentMetricList;
},
- getLast7Days: () => {
- let days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
- let result = [];
- let date = helpers.getAbsoluteDate();
- result.push(days[date.getDay()]);
+ // getLast7Days: () => {
+ // let days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
+ // let result = [];
+ // let date = new Date();
+ // result.push(`${date.getMonth()}-${date.getDate()}`);
- for (let i = 1; i <= 6; i++) {
- let copiedDate = new Date(date);
- copiedDate.setDate(date.getDate() - i);
- result.push(days[copiedDate.getDay()]);
- }
- return result.reverse();
- },
+ // for (let i = 1; i <= 6; i++) {
+ // let copiedDate = new Date(date);
+ // copiedDate.setDate(date.getDate() - i);
+ // result.push(`${copiedDate.getMonth()}/${copiedDate.getDate()}`);
+ // }
+ // return result.reverse();
+ // },
hideElem: (selector) => {
let elements = document.querySelectorAll(selector);
@@ -71,4 +88,71 @@ const helpers = {
getElem: (selector) => {
return document.querySelector(selector);
},
+ // Filter Metrics based on the provided customer
+ filterCustomerMetrics: (metrics, clientProfile) => {
+ return new Promise((resolve, reject) => {
+ // Get client history data;
+ Histories.getHistories(clientProfile).then((result) => {
+ histories = result;
+ // Add the history data to each metric
+ helpers.addHistoryToMetrics(metrics, histories);
+
+ resolve(metrics.metrics);
+ });
+ });
+ },
+ // Loop recursively on the metrics object and add the history value from histories object
+ addHistoryToMetrics: (metrics, histories) => {
+ if (Object.keys(metrics.metrics).length > 0) {
+ for (var key in metrics.metrics) {
+ if (
+ histories.metrics[key] &&
+ metrics.metrics[key].type === "parent" &&
+ Object.keys(metrics.metrics[key].metrics).length > 0
+ ) {
+ helpers.addHistoryToMetrics(
+ metrics.metrics[key],
+ histories.metrics[key]
+ );
+ } else {
+ if (histories.metrics[key] && histories.metrics[key].history) {
+ metrics.metrics[key].history = histories.metrics[key].history;
+ } else {
+ metrics.metrics[key].history = [];
+ }
+ }
+ }
+ }
+ },
+
+ getLast7Days: () => {
+ let result = [];
+ let date = new Date();
+ result.push({ date: date.toLocaleDateString(), value: 0 });
+
+ for (let i = 1; i <= 6; i++) {
+ let copiedDate = new Date(date);
+ copiedDate.setDate(date.getDate() - i);
+ result.push({
+ date: copiedDate.toLocaleDateString(),
+ value: 0,
+ });
+ }
+ return result;
+ },
+ getLast7DaysNoValue: () => {
+ let result = [];
+ let date = new Date();
+ result.push({ date: date.toLocaleDateString(), value: "No value" });
+
+ for (let i = 1; i <= 6; i++) {
+ let copiedDate = new Date(date);
+ copiedDate.setDate(date.getDate() - i);
+ result.push({
+ date: copiedDate.toLocaleDateString(),
+ value: "No value",
+ });
+ }
+ return result;
+ }
};
diff --git a/widget/js/lib/listView.js b/widget/js/lib/listView.js
index 6ee2a75..d5f01d2 100644
--- a/widget/js/lib/listView.js
+++ b/widget/js/lib/listView.js
@@ -63,6 +63,9 @@ class ListViewItem {
this.id = obj.id;
this.title = obj.title;
this.icon = obj.icon;
+ this.history = obj.history;
+ this.type = obj.type;
+ this.metrics = obj.metrics;
this.value = obj.value || 0;
this.data = obj.data;
this.order = obj.order || null;
@@ -75,6 +78,9 @@ class ListViewItem {
id: this.id,
title: this.title,
icon: this.icon,
+ history: this.history,
+ type: this.type,
+ metrics: this.metrics,
value: this.value,
data: this.data,
order: this.order,
@@ -170,8 +176,17 @@ class ListViewItem {
"mdc-button__icon",
]);
}
+ this.viewdValue = this.value;
+
+ if (
+ (this.history.length === 0 && this.type === "metric") ||
+ (this.type === "parent" && Object.keys(this.metrics).length === 0) ||
+ (this.value === 0 && Object.keys(this.metrics).length > 0)
+ ) {
+ this.viewdValue = "- ";
+ }
- ui.create("span", listViewItemToolbar, `${this.value}%`, [
+ ui.create("span", listViewItemToolbar, `${this.viewdValue}%`, [
"listViewItemToolbarItem",
"value",
]);
diff --git a/widget/style.css b/widget/style.css
index c305d9d..8246c95 100644
--- a/widget/style.css
+++ b/widget/style.css
@@ -175,7 +175,7 @@ span {
}
.summary-card .trending-icon {
- padding-left: 15px;
+ padding-left: 12px;
font-size: 20px;
vertical-align: middle;
}