diff --git a/public/build-solution.js b/public/build-solution.js
new file mode 100644
index 0000000..326dbce
--- /dev/null
+++ b/public/build-solution.js
@@ -0,0 +1,564 @@
+document.addEventListener('DOMContentLoaded', function() {
+ //Drop Down Menu
+ const dropdown = document.querySelector('.drop-down');
+ const dropdownBtn = document.querySelector('.menu');
+
+ window.toggleDropdown = function toggleDropdown() {
+ dropdownBtn.classList.toggle('opened');
+ dropdownBtn.setAttribute('aria-expanded', dropdownBtn.classList.contains('opened'))
+ dropdown.classList.toggle('show-menu');
+ }
+
+ //Tabs
+ var currentTab = 0;
+ showTab(currentTab);
+
+ let serviceArray = [
+ { title: 'Virtual Number', items: [] },
+ { title: 'Talk Time', items: [] },
+ { title: 'Call Transferring', items: [] },
+ { title: 'Ring Groups', items: [] },
+ { title: 'Auto Attendant', items: [] },
+ { title: 'Call Recording', items: [] },
+ { title: 'None', items: [] }
+ ];
+
+ let hardwareArray = [
+ {title: 'Yealink T31P', items: []},
+ {title: 'Yealink T43U', items: []},
+ {title: 'Yealink W56h', items: []},
+ {title: 'Yeastar App', items: []},
+ {title: 'Network Switch', items: []},
+ {title: 'Ethernet Cable', items: []}
+ ];
+
+ function showTab(n) {
+ var tab = document.getElementsByClassName("tab");
+ tab[n].style.display = "block";
+ tab
+ checkValidity(false);
+ };
+
+ window.nextPrev = function nextPrev(n) {
+ var tab = document.getElementsByClassName("tab");
+ tab[currentTab].style.display = "none";
+ currentTab += n;
+ showTab(currentTab)
+ };
+
+ function checkValidity(isValid) {
+ const nextBtn = document.getElementById('next-button');
+ const totalFooter = document.getElementsByClassName('footer-total')[0];
+
+ if (!nextBtn || !totalFooter) {
+ console.error('Next Button or Footer total not found');
+ return; // Exit the function if elements are not found
+ }
+
+ if (isValid) {
+ nextBtn.disabled = false;
+ nextBtn.style.opacity = '1';
+ nextBtn.style.cursor = 'pointer';
+ totalFooter.style.display = 'inline-flex';
+ populateServiceTable(); // Populate the table only if valid
+ populateHardwareTable();
+ totalMonthlyCost(serviceArray);
+ } else {
+ nextBtn.disabled = true;
+ nextBtn.style.opacity = '0.6';
+ nextBtn.style.cursor = 'default';
+ totalFooter.style.display = 'none';
+ }
+ }
+
+ //Price Formatter
+
+ function formatPrice(price) {
+ return new Intl.NumberFormat('en-ZA', {
+ style: 'currency',
+ currency: 'ZAR',
+ maximumSignificantDigits: 5
+ }).format(price);
+ }
+
+ function updateServiceArray(categoryTitle, itemDetails, removeTitle) {
+ let category = serviceArray.find(category => category.title === categoryTitle);
+
+ if (!category) {
+ console.error('Category not found');
+ return;
+ }
+
+ // Remove conflicting item if specified
+ if (removeTitle) {
+ category.items = category.items.filter(item => item.title !== removeTitle);
+ }
+
+ // Update or add the new item
+ let existingItemIndex = category.items.findIndex(item => item.title === itemDetails.title);
+
+ if (existingItemIndex !== -1) {
+ category.items[existingItemIndex] = itemDetails;
+ } else {
+ category.items.push(itemDetails);
+ }
+ }
+
+
+ function populateServiceTable(){
+ const tbody = document.querySelector('.review-services table tbody');
+ tbody.innerHTML = '';
+
+ serviceArray.forEach(category => {
+ category.items.forEach(item => {
+ const row = document.createElement('tr');
+
+ row.innerHTML =
+ `
+
+
+ |
+
+ ${item.title}
+ ${item.description}
+ |
+
+ ${item.quantity}
+ |
+
+ ${item.price}
+ |
+ `;
+
+ tbody.appendChild(row);
+ });
+ });
+ }
+
+ function updateHardwareArray(hardwareTitle, itemDetails) {
+ // This function should be designed to add or update the hardware item in a global array
+ let found = false;
+
+ for (let category of hardwareArray) {
+ if (category.title === hardwareTitle) {
+ found = true;
+ const existingIndex = category.items.findIndex(item => item.title === itemDetails.title);
+ if (existingIndex !== -1) {
+ if (itemDetails.quantity === 0) {
+ // Remove the item if quantity is zero
+ category.items.splice(existingIndex, 1);
+ } else {
+ // Update existing item
+ category.items[existingIndex] = itemDetails;
+ }
+ } else if (itemDetails.quantity > 0) {
+ // Add new item
+ category.items.push(itemDetails);
+ }
+ break;
+ }
+ }
+
+ if (!found) {
+ console.error('Hardware title not found in array');
+ }
+
+ // Assuming you have a function to repopulate the hardware table based on `hardwareArray`
+ populateHardwareTable();
+ }
+
+
+ function populateHardwareTable(){
+ const tbody = document.querySelector('.review-hardware table tbody');
+ tbody.innerHTML = '';
+
+ hardwareArray.forEach(category => {
+ category.items.forEach(item => {
+ const row = document.createElement('tr');
+
+ row.innerHTML =
+ `
+
+
+ |
+
+ ${item.title}
+ ${item.description}
+ |
+
+ ${item.quantity}
+ |
+
+ ${item.price}
+ |
+ `;
+
+ tbody.appendChild(row);
+ });
+ });
+ }
+
+ //Hardware
+ window.updateHardware = function updateHardware(event, isAdding) {
+ const hardwareCard = event.target.closest('.hardware-card');
+ if (!hardwareCard) return;
+
+ const hardwareQty = hardwareCard.querySelector('.hardware-qty');
+ const hardwareMinus = hardwareCard.querySelector('.hardware-minus');
+ const hardwarePriceElement = hardwareCard.querySelector('h4');
+ let qty = parseInt(hardwareQty.dataset.qty) || 0;
+ let basePrice = parseInt(hardwarePriceElement.dataset.basePrice) || parseInt(hardwarePriceElement.textContent);
+
+ qty = isAdding ? Math.min(qty + 1, 9) : Math.max(qty - 1, 0);
+ let deviceSum = basePrice * qty; // Calculate total price based on current quantity.
+
+ hardwareCard.classList.toggle('selected', qty > 0);
+ hardwareQty.style.display = qty > 0 ? 'block' : 'none';
+ hardwareMinus.style.display = qty > 0 ? 'inline-flex' : 'none';
+ hardwareQty.innerHTML = qty.toString();
+ hardwareQty.dataset.qty = qty.toString();
+
+ const hardwareTitle = hardwareCard.querySelector('.hardware-title h2').textContent;
+ const hardwareImage = hardwareCard.querySelector('.hardware-img').src;
+ const hardwareDescription = hardwareCard.querySelector('.hardware-title h3').textContent;
+
+ // Update hardware array to reflect the current state of selections
+ updateHardwareArray(hardwareTitle, {
+ image: hardwareImage,
+ title: hardwareTitle,
+ description: hardwareDescription,
+ quantity: qty,
+ price: formatPrice(deviceSum)
+ });
+
+ hardwareTotals();
+ const totalQty = hardwareQtyTotal();
+
+ updateSwitchAndCable(totalQty);
+ };
+
+ function updateSwitchAndCable(totalQty) {
+ const switchPorts = Math.ceil(totalQty / 2) * 2;
+ const cableLength = totalQty * 20;
+
+ updateHardwareArray('Network Switch', {
+ image: 'Assets/s-zoom.jpg',
+ title: 'Network Switch',
+ description: switchPorts + ' Port POE',
+ quantity: 1,
+ price: 'Included'
+ });
+
+ updateHardwareArray('Ethernet Cable', {
+ image: 'Assets/Group 1780.png',
+ title: 'Ethernet Cable',
+ description: 'In meters',
+ quantity: cableLength,
+ price: 'Included'
+ });
+ }
+
+
+ function hardwareQtyTotal() {
+ const hardwareItems = document.querySelectorAll('.hardware-card');
+ let totalQty = 0;
+
+ hardwareItems.forEach(item => {
+ const qty = parseInt(item.querySelector('.hardware-qty').dataset.qty) || 0;
+
+ totalQty += qty;
+ });
+
+ return totalQty;
+ };
+
+ function hardwarePriceTotal() {
+ const hardwareItems = document.querySelectorAll('.hardware-card');
+ let totalPrice = 0;
+
+ hardwareItems.forEach(item => {
+ const qty = parseInt(item.querySelector('.hardware-qty').dataset.qty) || 0;
+ const basePrice = parseInt(item.querySelector('h4').dataset.basePrice) || parseInt(item.querySelector('h4').textContent);
+ const devicePrice = basePrice * qty;
+
+ totalPrice += devicePrice;
+ });
+
+ return totalPrice;
+ };
+
+ function hardwareTotals() {
+ const totalPrice = hardwarePriceTotal()
+ const totalQty = hardwareQtyTotal();
+ const isValid = totalQty > 0;
+
+ document.getElementById('total-footer-price').textContent = formatPrice(totalPrice);
+ document.getElementById('total-cost-period').style.display = 'none';
+ document.getElementById('total-once-off-cost').textContent = formatPrice(totalPrice);
+
+ checkValidity(isValid);
+ };
+
+ //Horizontal Scroll
+ // document.getElementById('scroll-button').addEventListener('click', function() {
+ // const hardwareContainer = document.getElementsByClassName('hardware-container-outer')[0];
+ // const scrollAmount = 300;
+ // hardwareContainer.scrollLeft += scrollAmount;
+ // });
+
+ //Virtual Number
+
+ const newNumberInput = document.getElementById('new-number-input');
+ const portNumberInput = document.getElementById("port-number-input");
+ const newNumberBtn = document.getElementById('new-number');
+ const portNumberBtn = document.getElementById('port-number');
+
+
+ window.virtualNumberBtn = function virtualNumberBtn(n) {
+
+ if (n === 0) {
+ newNumberInput.style.display = 'block'
+ newNumberInput.classList.add('slide-in-top')
+ portNumberInput.style.display = 'none'
+ newNumberBtn.classList.add('selected')
+ portNumberBtn.classList.remove('selected')
+ portNumberInput.value = ''
+ document.getElementById('provider-file').style.display = 'none';
+ checkValidity(false)
+ } else if(n === 1) {
+ portNumberInput.style.display = 'block'
+ portNumberInput.classList.add('slide-in-top')
+ newNumberInput.style.display = 'none'
+ newNumberBtn.classList.remove('selected')
+ portNumberBtn.classList.add('selected')
+ newNumberInput.value = '0'
+ document.getElementById('provider-file').style.display = 'block';
+ checkValidity(false)
+ }
+ };
+
+ // New Number Validation
+ newNumberInput.addEventListener('change', function () {
+ const newNumberValue = newNumberInput.value;
+
+ if (newNumberValue !== '0') {
+ newNumberInput.style.border = "2px solid #4BD37B";
+ updateServiceArray('Virtual Number', {
+ image: 'Assets/Group 1685.png',
+ title: 'New Number',
+ description: '',
+ quantity: 1,
+ price: formatPrice(90)
+ }, 'Transfer Number');
+
+ document.getElementById('total-footer-price').textContent = formatPrice(90);
+ document.getElementById('total-cost-period').style.display = 'inline-flex';
+ checkValidity(true);
+ } else {
+ newNumberInput.style.border = "2px solid whitesmoke";
+ checkValidity(false);
+ }
+ });
+
+ // Transfer Number Validation
+ portNumberInput.addEventListener('input', function () {
+ const portNumberValue = portNumberInput.value;
+
+ if (portNumberValue.length > 0 && portNumberInput.checkValidity()) {
+ portNumberInput.style.border = "2px solid #4BD37B";
+ updateServiceArray('Virtual Number', {
+ image: 'Assets/Group 1685.png',
+ title: 'Transfer Number',
+ description: '[ ' + portNumberValue + ' ]',
+ quantity: 1,
+ price: formatPrice(90)
+ }, 'New Number'); // Specify to remove 'New Number'
+ document.getElementById('total-footer-price').textContent = formatPrice(90);
+ document.getElementById('total-cost-period').style.display = 'inline-flex';
+ checkValidity(true);
+ } else {
+ portNumberInput.style.border = "2px solid #FF5A79";
+ checkValidity(false);
+ }
+ });
+
+
+ //Talk time
+
+ // Initialize progress on page load for the range slider
+ const initialTalkTimeValue = document.getElementById('talk-time').value;
+ const max = parseInt(document.getElementById('talk-time').max, 10);
+ const min = parseInt(document.getElementById('talk-time').min, 10);
+ const percentage = ((initialTalkTimeValue - min) / (max - min)) * 100;
+ document.getElementById('talk-time').style.background = `linear-gradient(90deg, #0071E3 ${percentage}%, #D9D9D9 ${percentage}%)`;
+
+ document.getElementById('talk-time').addEventListener('input', function () {
+ const talkTimeValue = this.value; // Using 'this' as it refers to the element that triggered the event
+ const perMinutePrice = 0.28;
+ const talkTimeDescription = document.getElementById('talk-time-description');
+
+ // Update displayed values for talk time
+ document.getElementById('talk-time-value').textContent = new Intl.NumberFormat('fr-FR').format(talkTimeValue);
+ document.getElementById('total-footer-price').textContent = formatPrice(talkTimeValue * perMinutePrice);
+
+ updateServiceArray('Talk Time', {
+ image: 'Assets/Group 1684.png',
+ title: 'Talk Time',
+ description: '',
+ quantity: talkTimeValue + ' Minutes',
+ price: formatPrice(talkTimeValue * perMinutePrice)
+ }); // Ensure this function call is properly closed with a semicolon
+
+ // Conditional descriptions based on talkTimeValue
+ if (talkTimeValue >= 500 && talkTimeValue <= 1500) {
+ talkTimeDescription.textContent = 'For small businesses (1-2 employees)';
+ } else if (talkTimeValue > 1500 && talkTimeValue <= 5000) {
+ talkTimeDescription.textContent = 'For medium businesses (3-10 employees)';
+ } else if (talkTimeValue > 5000) {
+ talkTimeDescription.textContent = 'For large businesses (10+ employees)';
+ } else if (talkTimeValue < 500) {
+ talkTimeDescription.textContent = 'For businesses who only recieve calls';
+ }
+
+ checkValidity(true);
+
+ // Update range slider progress
+ const max = parseInt(this.max, 10);
+ const min = parseInt(this.min, 10);
+ const value = parseInt(talkTimeValue, 10);
+ const percentage = ((value - min) / (max - min)) * 100;
+ // Update the background gradient to reflect the current value
+ this.style.background = `linear-gradient(90deg, #0071E3 ${percentage}%, #D9D9D9 ${percentage}%)`;
+ });
+
+ //System Features
+
+ function extentionPriceTotal(){
+ const qty = hardwareQtyTotal();
+ let totalPrice = qty * 25;
+
+ return totalPrice;
+ }
+
+ window.featuresAdd = function featuresAdd(event) {
+ const featureCard = event.target.closest('.features-card');
+ if (!featureCard) return;
+
+ const allFeatureCards = document.querySelectorAll('.features-card');
+ const finalFeatureCard = document.getElementById('no-features');
+ const featuresAdd = featureCard.querySelector('.features-add');
+
+ // If the final feature card is clicked
+ if (featureCard.id === 'no-features') {
+ allFeatureCards.forEach(card => {
+ // Deselect all other feature cards
+ if (card.id !== 'no-features') {
+ card.classList.remove('selected');
+ const featuresAddBtn = card.querySelector('.features-add');
+ if (featuresAddBtn) {
+ featuresAddBtn.classList.remove('clicked');
+ }
+ }
+ });
+
+ // Toggle the final feature card
+ featureCard.classList.toggle('selected');
+ document.getElementById('total-footer-price').textContent = formatPrice(0);
+ document.getElementById('total-cost-period').style.display = 'inline-flex';
+ checkValidity(featureCard.classList.contains('selected'));
+ } else {
+ // For any non-final feature card
+ featureCard.classList.toggle('selected');
+ if (featuresAdd) {
+ featuresAdd.classList.toggle('clicked');
+ }
+
+ // If any non-final feature card is selected, deselect the final feature card
+ if (finalFeatureCard.classList.contains('selected')) {
+ finalFeatureCard.classList.remove('selected');
+ // Reset any state/effects associated with the final feature card
+ // For example, setting total price back to the sum of selected non-final features
+ document.getElementById('total-footer-price').textContent = formatPrice(extentionPriceTotal()); // Assuming hardwarePriceTotal() recalculates the correct total
+ document.getElementById('total-cost-period').style.display = 'none'; // Adjust based on desired behavior
+ }
+
+ // Update feature state and check validity for non-final feature cards
+ updateFeatureState(); // This should now consider the deselection of the final feature card
+ }
+
+ const featureTitle = featureCard.querySelector('.features-card-text h3').textContent;
+ const featureImage = featureCard.querySelector('.features-card img').src;
+ const featureDescription = featureCard.querySelector('.features-card-text p').textContent;
+
+ updateServiceArray(featureTitle, {
+ image: featureImage,
+ title: featureTitle,
+ description: '',
+ quantity: 1,
+ price: 'included'
+ });
+
+ };
+
+ function updateFeatureState() {
+ const featureCards = document.querySelectorAll('.features-card:not(#no-features)');
+ let isSelected = Array.from(featureCards).some(card => card.classList.contains('selected'));
+
+ if (isSelected) {
+ document.getElementById('total-footer-price').textContent = formatPrice(extentionPriceTotal());
+ document.getElementById('total-cost-period').style.display = 'inline-flex';
+ checkValidity(true);
+ } else {
+ document.getElementById('total-footer-price').textContent = formatPrice(0);
+ document.getElementById('total-cost-period').style.display = 'none';
+ checkValidity(false);
+ }
+ }
+
+ function totalMonthlyCost(serviceArray) {
+ let totalPrice = 0;
+
+ serviceArray.forEach(service => {
+ service.items.forEach(item => {
+ totalPrice += Number(item.price);
+ });
+ });
+ document.getElementById('total-monthly-cost').textContent = formatPrice(totalPrice);
+ }
+
+ //Paystack Recieve Payment
+ const paymentForm = document.getElementById('paymentForm');
+ paymentForm.addEventListener("submit", payWithPaystack, false);
+
+ function payWithPaystack(e) {
+ e.preventDefault();
+
+ // Fetch the Paystack public key from the server
+ fetch('https://pure-crag-27853-51c2ba2d1731.herokuapp.com/paystack-key')
+ .then(response => response.json())
+ .then(data => {
+ let handler = PaystackPop.setup({
+ key: data.key, // Use the public key from the server
+ email: document.getElementById("email-address").value,
+ amount: hardwarePriceTotal() * 100,
+ ref: '' + Math.floor((Math.random() * 1000000000) + 1),
+ currency: 'ZAR',
+ onClose: function(){
+ alert('Window closed.');
+ },
+ callback: function(response){
+ let message = 'Payment complete! Reference: ' + response.reference;
+ alert(message);
+ }
+ });
+
+ handler.openIframe();
+ })
+ .catch(error => {
+ console.error('Failed to load Paystack key:', error);
+ alert('There was an error processing your payment. Please try again.');
+ });
+ }
+
+
+});
\ No newline at end of file