Repository navigation
Expand file tree
/
Copy pathapp.js
More file actions
95 lines (84 loc) · 3.48 KB
/
Copy pathapp.js
File metadata and controls
95 lines (84 loc) · 3.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
(function () {
"use strict";
const logic = window.ReplyPilotLogic;
const menuButton = document.querySelector(".menu-button");
const navigation = document.querySelector(".primary-nav");
menuButton.addEventListener("click", () => {
const expanded = menuButton.getAttribute("aria-expanded") === "true";
menuButton.setAttribute("aria-expanded", String(!expanded));
navigation.classList.toggle("open", !expanded);
});
navigation.querySelectorAll("a").forEach((link) => {
link.addEventListener("click", () => {
menuButton.setAttribute("aria-expanded", "false");
navigation.classList.remove("open");
});
});
const form = document.querySelector("#roi-form");
const fields = {
tickets: document.querySelector("#tickets"),
minutes: document.querySelector("#minutes"),
hourlyCost: document.querySelector("#hourly-cost"),
automation: document.querySelector("#automation"),
};
const errors = {
tickets: document.querySelector("#tickets-error"),
minutes: document.querySelector("#minutes-error"),
hourlyCost: document.querySelector("#cost-error"),
automation: document.querySelector("#automation-error"),
};
const hoursOutput = document.querySelector("#hours-saved");
const savingsOutput = document.querySelector("#labor-savings");
const numberFormatter = new Intl.NumberFormat("en-US", { maximumFractionDigits: 1 });
const moneyFormatter = new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
maximumFractionDigits: 0,
});
function validateField(key, input) {
let message = "";
const value = Number(input.value);
if (input.value.trim() === "" || !Number.isFinite(value)) message = "Enter a valid number.";
else if (value < 0) message = "Use zero or a positive number.";
else if (key === "automation" && value > 100) message = "Use a percentage from 0 to 100.";
errors[key].textContent = message;
input.setAttribute("aria-invalid", String(Boolean(message)));
return !message;
}
function updateROI() {
const valid = Object.entries(fields).every(([key, input]) => validateField(key, input));
if (!valid) {
hoursOutput.textContent = "—";
savingsOutput.textContent = "—";
return;
}
const result = logic.calculateROI({
tickets: fields.tickets.value,
minutes: fields.minutes.value,
hourlyCost: fields.hourlyCost.value,
automation: fields.automation.value,
});
hoursOutput.textContent = numberFormatter.format(result.hoursSaved);
savingsOutput.textContent = moneyFormatter.format(result.laborSavings);
}
form.addEventListener("input", updateROI);
updateROI();
const billingButtons = document.querySelectorAll("[data-billing]");
billingButtons.forEach((button) => {
button.addEventListener("click", () => {
const cycle = button.dataset.billing;
billingButtons.forEach((item) => {
const selected = item === button;
item.classList.toggle("active", selected);
item.setAttribute("aria-pressed", String(selected));
});
document.querySelectorAll(".price strong[data-monthly]").forEach((price) => {
price.textContent = cycle === "yearly" ? price.dataset.yearly : price.dataset.monthly;
});
document.querySelectorAll(".billing-note").forEach((note) => {
note.textContent = cycle === "yearly" ? note.dataset.yearlyNote : note.dataset.monthlyNote;
});
});
});
document.querySelector("#year").textContent = new Date().getFullYear();
})();