mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-08-11 09:28:27 -04:00
1484 - Dashboard visualizations
This commit is contained in:
71
app/assets/javascripts/dataVisualization.js
Normal file
71
app/assets/javascripts/dataVisualization.js
Normal file
@@ -0,0 +1,71 @@
|
||||
(function (window) {
|
||||
|
||||
// Dummy data (replace with API data)
|
||||
const data = {
|
||||
messageStats: {
|
||||
totalMessages: 1000,
|
||||
delivered: 800,
|
||||
pending: 100,
|
||||
failed: 100
|
||||
},
|
||||
dailyUsage: {
|
||||
dailyUsage: 20,
|
||||
dailyUsageLimit: 100
|
||||
},
|
||||
yearlyUsage: {
|
||||
yearlyUsage: 2000,
|
||||
yearlyUsageLimit: 250000
|
||||
}
|
||||
};
|
||||
|
||||
// Update total messages progress bar percentages
|
||||
const messageStats = data.messageStats;
|
||||
|
||||
const messageBars = ["delivered", "pending", "failed"];
|
||||
for (const bar of messageBars) {
|
||||
const percentage = messageStats[bar] / messageStats.totalMessages * 100;
|
||||
const elementId = `${bar}-bar`;
|
||||
const element = document.getElementById(elementId);
|
||||
element.style.width = `${parseFloat(percentage)}%`;
|
||||
}
|
||||
|
||||
// Update total messages progress bar percentages
|
||||
const dailyUsage = data.dailyUsage;
|
||||
const dailyUsageLimit = dailyUsage.dailyUsageLimit;
|
||||
const yearlyUsage = data.yearlyUsage;
|
||||
const yearlyUsageLimit = yearlyUsage.yearlyUsageLimit;
|
||||
|
||||
function updateUsageBar(elementId, dailyUsage, dailyUsageLimit, yearlyUsage, yearlyUsageLimit) {
|
||||
// Ensure element exists
|
||||
if (!elementId || !document.getElementById(elementId)) {
|
||||
console.error(`Element with ID "${elementId}" not found`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate percentage
|
||||
const percentage = dailyUsage / dailyUsageLimit * 100;
|
||||
|
||||
// Update bar width
|
||||
const element = document.getElementById(elementId);
|
||||
element.style.width = `${parseFloat(percentage)}%`;
|
||||
}
|
||||
|
||||
// Update usage bars
|
||||
updateUsageBar("dailyUsage-bar", dailyUsage.dailyUsage, dailyUsageLimit);
|
||||
updateUsageBar("dailyUsageRemaining-bar", dailyUsageLimit - dailyUsage.dailyUsage, dailyUsageLimit);
|
||||
updateUsageBar("yearlyUsage-bar", yearlyUsage.yearlyUsage, yearlyUsageLimit);
|
||||
updateUsageBar("yearlyUsageRemaining-bar", yearlyUsageLimit - yearlyUsage.yearlyUsage, yearlyUsageLimit);
|
||||
|
||||
// Update total messages legend values
|
||||
document.getElementById("total-value").innerText = `Total: ${messageStats.totalMessages} messages`;
|
||||
document.getElementById("delivered-value").innerText = `Delivered: ${messageStats.delivered}`;
|
||||
document.getElementById("pending-value").innerText = `Pending: ${messageStats.pending}`;
|
||||
document.getElementById("failed-value").innerText = `Failed: ${messageStats.failed}`;
|
||||
|
||||
// Update usage legend values
|
||||
document.getElementById("daily-usage-value").innerText = `Daily usage: ${dailyUsage.dailyUsage}`;
|
||||
document.getElementById("daily-remaining-value").innerText = `Remaining messages: ${dailyUsage.dailyUsageLimit - dailyUsage.dailyUsage}`;
|
||||
document.getElementById("yearly-usage-value").innerText = `Yearly usage: ${yearlyUsage.yearlyUsage}`;
|
||||
document.getElementById("yearly-remaining-value").innerText = `Remaining messages: ${yearlyUsage.yearlyUsageLimit - yearlyUsage.yearlyUsage}`;
|
||||
|
||||
})(window);
|
||||
79
app/assets/sass/uswds/_data-visualization.scss
Normal file
79
app/assets/sass/uswds/_data-visualization.scss
Normal file
@@ -0,0 +1,79 @@
|
||||
@use "uswds-core" as *;
|
||||
|
||||
$delivered: color('blue-50v');
|
||||
$pending: color('green-cool-40v');
|
||||
$failed: color('orange-30v');
|
||||
|
||||
.chart-container {
|
||||
display: flex;
|
||||
height: units(8);
|
||||
&.usage {
|
||||
height: units(4);
|
||||
}
|
||||
}
|
||||
|
||||
.bar {
|
||||
border-radius: units(0.5);
|
||||
&.delivered, &.usage {
|
||||
background-color: $delivered;
|
||||
margin-right: 1px;
|
||||
}
|
||||
&.pending{
|
||||
background-color: $pending;
|
||||
margin-right: 1px;
|
||||
}
|
||||
&.failed, &.remaining {
|
||||
background-color: $failed;
|
||||
}
|
||||
}
|
||||
|
||||
.legend {
|
||||
display: flex;
|
||||
margin: units(1) 0;
|
||||
.legend-item {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
margin-right: units(2);
|
||||
}
|
||||
.legend-color {
|
||||
width: units(3);
|
||||
height: units(3);
|
||||
margin-right: 0;
|
||||
padding: 0;
|
||||
border-radius: 2px;
|
||||
background-color: $delivered;
|
||||
&.pending {
|
||||
background-color: $pending;
|
||||
}
|
||||
&.failed, &.remaining {
|
||||
background-color: $failed;
|
||||
}
|
||||
}
|
||||
.legend-value {
|
||||
margin: 0 units(1);
|
||||
}
|
||||
}
|
||||
|
||||
.usa-tooltip {
|
||||
line-height: 1;
|
||||
.usa-tooltip__body {
|
||||
width: units(mobile);
|
||||
height: auto;
|
||||
white-space: wrap;
|
||||
line-height: 1.3;
|
||||
}
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
width: 300px;
|
||||
height: 20px;
|
||||
background-color: #eee;
|
||||
border-radius: 5px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.progress-bar-inner {
|
||||
height: 100%;
|
||||
background-color: #007bff;
|
||||
border-radius: inherit;
|
||||
}
|
||||
@@ -18,6 +18,39 @@
|
||||
|
||||
{{ ajax_block(partials, updates_url, 'upcoming') }}
|
||||
|
||||
<h2 class="font-body-xl margin-0">
|
||||
SMS Activity
|
||||
</h2>
|
||||
<h3 id="total-value" class="margin-y-1"></h3>
|
||||
<div class="chart-container">
|
||||
<div class="bar delivered" id="delivered-bar"></div>
|
||||
<div class="bar pending" id="pending-bar"></div>
|
||||
<div class="bar failed" id="failed-bar"></div>
|
||||
</div>
|
||||
<div class="legend">
|
||||
<div class="legend-item">
|
||||
<button type="button" class="usa-button usa-tooltip legend-color delivered" data-position="bottom"
|
||||
data-classes="width-full tablet:width-auto"
|
||||
title="Delivered means that the message was successfully delivered to the mobile device.">
|
||||
</button>
|
||||
<div class="legend-value" id="delivered-value"></div>
|
||||
</div>
|
||||
<div class="legend-item width-card">
|
||||
<button type="button" class="usa-button usa-tooltip legend-color pending" data-position="bottom"
|
||||
data-classes="width-full tablet:width-auto"
|
||||
title="Pending means that Notify has sent the message, but has not received the delivery status from the carrier. Messages remain in the Pending state until Notify has received the status, typically about five minutes.">
|
||||
</button>
|
||||
<div class="legend-value" id="pending-value"></div>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<button type="button" class="usa-button usa-tooltip legend-color failed" data-position="bottom"
|
||||
data-classes="width-full tablet:width-auto"
|
||||
title="Failed means that the carrier could not deliver the message, generally because the phone is unavailable or the number is no longer active.">
|
||||
</button>
|
||||
<div class="legend-value" id="failed-value"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 class="font-body-2xl line-height-sans-2 margin-0">
|
||||
Messages sent
|
||||
</h2>
|
||||
|
||||
2
poetry.lock
generated
2
poetry.lock
generated
@@ -1517,7 +1517,6 @@ files = [
|
||||
{file = "msgpack-1.0.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5fbb160554e319f7b22ecf530a80a3ff496d38e8e07ae763b9e82fadfe96f273"},
|
||||
{file = "msgpack-1.0.8-cp39-cp39-win32.whl", hash = "sha256:f9af38a89b6a5c04b7d18c492c8ccf2aee7048aff1ce8437c4683bb5a1df893d"},
|
||||
{file = "msgpack-1.0.8-cp39-cp39-win_amd64.whl", hash = "sha256:ed59dd52075f8fc91da6053b12e8c89e37aa043f8986efd89e61fae69dc1b011"},
|
||||
{file = "msgpack-1.0.8-py3-none-any.whl", hash = "sha256:24f727df1e20b9876fa6e95f840a2a2651e34c0ad147676356f4bf5fbb0206ca"},
|
||||
{file = "msgpack-1.0.8.tar.gz", hash = "sha256:95c02b0e27e706e48d0e5426d1710ca78e0f0628d6e89d5b5a5b91a5f12274f3"},
|
||||
]
|
||||
|
||||
@@ -2384,6 +2383,7 @@ files = [
|
||||
{file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"},
|
||||
|
||||
Reference in New Issue
Block a user