diff --git a/cp/app/Controllers/DapiController.php b/cp/app/Controllers/DapiController.php index 82cb967..bd34e4b 100644 --- a/cp/app/Controllers/DapiController.php +++ b/cp/app/Controllers/DapiController.php @@ -756,4 +756,26 @@ class DapiController extends Controller return $response; } + public function domainPrice(Request $request, Response $response): Response + { + $params = $request->getQueryParams(); + $db = $this->container->get('db'); + + $domain_name = $params['domain_name'] ?? ''; + $date_add = (int) ($params['date_add'] ?? 12); + $command = $params['command'] ?? 'create'; + $currency = $params['currency'] ?? 'USD'; + $registrar_id = !empty($params['registrar_id']) ? $params['registrar_id'] : ($_SESSION['auth_registrar_id'] ?? null); + + $parts = extractDomainAndTLD($domain_name); + $domain_extension = $parts['tld']; + + $tld_id = $db->selectValue('SELECT id FROM domain_tld WHERE tld = ?', [ '.'.$domain_extension ]); + + $result = getDomainPrice($db, $domain_name, $tld_id, $date_add, $command, $registrar_id, $currency); + + $response->getBody()->write(json_encode($result)); + return $response->withHeader('Content-Type', 'application/json'); + } + } \ No newline at end of file diff --git a/cp/app/Controllers/DomainsController.php b/cp/app/Controllers/DomainsController.php index 7d8abcb..eea7e46 100644 --- a/cp/app/Controllers/DomainsController.php +++ b/cp/app/Controllers/DomainsController.php @@ -921,12 +921,20 @@ class DomainsController extends Controller $registrars = $db->select("SELECT id, clid, name FROM registrar"); if ($_SESSION["auth_roles"] != 0) { $registrar = true; + $currency = $_SESSION['_currency'] ?? 'USD'; + if (!empty($_SESSION['auth_registrar_id'])) { + $currency = $db->selectValue( + 'SELECT currency FROM registrar WHERE id = ?', + [$_SESSION['auth_registrar_id']] + ) ?? 'USD'; // Default to USD if no result + } } else { $registrar = null; + $currency = $_SESSION['_currency'] ?? 'USD'; } + $registry_currency = $_SESSION['registry_currency'] ?? 'USD'; $locale = (isset($_SESSION['_lang']) && !empty($_SESSION['_lang'])) ? $_SESSION['_lang'] : 'en_US'; - $currency = $_SESSION['_currency'] ?? 'USD'; // Default to USD if not set $formatter = new \NumberFormatter($locale, \NumberFormatter::CURRENCY); $formatter->setTextAttribute(\NumberFormatter::CURRENCY_CODE, $currency); @@ -947,6 +955,7 @@ class DomainsController extends Controller 'registrar' => $registrar, 'launch_phases' => $launch_phases, 'currency' => $currency, + 'registry_currency' => $registry_currency, ]); } @@ -1899,10 +1908,19 @@ class DomainsController extends Controller $registrars = $db->select("SELECT id, clid, name FROM registrar"); if ($_SESSION["auth_roles"] != 0) { $registrar = true; + $currency = $_SESSION['_currency'] ?? 'USD'; + if (!empty($_SESSION['auth_registrar_id'])) { + $currency = $db->selectValue( + 'SELECT currency FROM registrar WHERE id = ?', + [$_SESSION['auth_registrar_id']] + ) ?? 'USD'; // Default to USD if no result + } } else { $registrar = null; + $currency = $_SESSION['_currency'] ?? 'USD'; } - + $registry_currency = $_SESSION['registry_currency'] ?? 'USD'; + $uri = $request->getUri()->getPath(); if ($args) { @@ -1943,7 +1961,6 @@ class DomainsController extends Controller $maxYears = 10 - $yearsUntilExpiration; $locale = (isset($_SESSION['_lang']) && !empty($_SESSION['_lang'])) ? $_SESSION['_lang'] : 'en_US'; - $currency = $_SESSION['_currency'] ?? 'USD'; // Default to USD if not set $formatter = new \NumberFormatter($locale, \NumberFormatter::CURRENCY); $formatter->setTextAttribute(\NumberFormatter::CURRENCY_CODE, $currency); @@ -1970,7 +1987,8 @@ class DomainsController extends Controller 'currentUri' => $uri, 'currencySymbol' => $symbol, 'currencyPosition' => $position, - 'currency' => $currency + 'currency' => $currency, + 'registry_currency' => $registry_currency ]); } else { // Domain does not exist, redirect to the domains view @@ -2661,12 +2679,20 @@ class DomainsController extends Controller $registrars = $db->select("SELECT id, clid, name FROM registrar"); if ($_SESSION["auth_roles"] != 0) { $registrar = true; + $currency = $_SESSION['_currency'] ?? 'USD'; + if (!empty($_SESSION['auth_registrar_id'])) { + $currency = $db->selectValue( + 'SELECT currency FROM registrar WHERE id = ?', + [$_SESSION['auth_registrar_id']] + ) ?? 'USD'; // Default to USD if no result + } } else { $registrar = null; + $currency = $_SESSION['_currency'] ?? 'USD'; } - + $registry_currency = $_SESSION['registry_currency'] ?? 'USD'; + $locale = (isset($_SESSION['_lang']) && !empty($_SESSION['_lang'])) ? $_SESSION['_lang'] : 'en_US'; - $currency = $_SESSION['_currency'] ?? 'USD'; // Default to USD if not set $formatter = new \NumberFormatter($locale, \NumberFormatter::CURRENCY); $formatter->setTextAttribute(\NumberFormatter::CURRENCY_CODE, $currency); @@ -2683,7 +2709,8 @@ class DomainsController extends Controller 'registrar' => $registrar, 'currencySymbol' => $symbol, 'currencyPosition' => $position, - 'currency' => $currency + 'currency' => $currency, + 'registry_currency' => $registry_currency ]); } diff --git a/cp/resources/views/admin/domains/createDomain.twig b/cp/resources/views/admin/domains/createDomain.twig index 3586257..957e191 100644 --- a/cp/resources/views/admin/domains/createDomain.twig +++ b/cp/resources/views/admin/domains/createDomain.twig @@ -244,45 +244,45 @@ {% if launch_phases == 'on' %} @@ -363,6 +363,7 @@ document.addEventListener("DOMContentLoaded", function() { // Display year value from slider yearSlider.addEventListener('input', function() { yearValueDisplay.textContent = `${yearSlider.value} Year${yearSlider.value > 1 ? 's' : ''}`; + updatePrice(); // Call updatePrice() directly when slider moves }); function createNameserverGroup(count) { @@ -444,102 +445,92 @@ document.addEventListener("DOMContentLoaded", function() { dnssecData.style.display = 'none'; } }); - + const domainInput = document.getElementById('domainName'); const yearInput = document.getElementById('registrationYears'); const priceDisplay = document.getElementById('domainPriceDisplay'); const priceValue = document.getElementById('domainPrice'); - function extractTLD(domain) { - const parts = domain.split('.'); - - // If the domain has more than two segments (e.g., 'test.com.test'), return the last two segments - if (parts.length > 2) { - return parts.slice(-2).join('.').toLowerCase(); - } - // If the domain has two or fewer segments (e.g., 'test.test' or 'test'), return the last segment - else { - return parts[parts.length - 1].toLowerCase(); - } - } - function getDomainPrice(domain, years, registrarId) { - const tld = extractTLD(domain); - if (!tld) { - return Promise.reject("Invalid TLD"); - } + const currency = "{{ currency }}"; + const apiUrl = `/dapi/domain/price?domain_name=${encodeURIComponent(domain)}&date_add=${years * 12}&command=create®istrar_id=${encodeURIComponent(registrarId)}¤cy=${encodeURIComponent(currency)}`; - // Regular expression for exact TLD match - const tldRegex = new RegExp(`${tld.toLowerCase()}$`); - - // Fetch both promotional pricing and regular pricing - return Promise.all([ - fetch(`/api/records/promotion_pricing?join=domain_tld`).then(response => response.json()), - fetch(`/api/records/domain_price?join=domain_tld`).then(response => response.json()) - ]) - .then(([promoData, pricingData]) => { - const today = new Date(); - - // Check for a valid promotion - const promo = promoData.records.find(record => - record.tld_id && tldRegex.test(record.tld_id.tld.toLowerCase()) && - new Date(record.start_date) <= today && - new Date(record.end_date) >= today && - (!record.years_of_promotion || record.years_of_promotion >= years) - ); - - // Find the regular price for the TLD with registrar ID - let tldData = pricingData.records.find(record => - record.tldid && tldRegex.test(record.tldid.tld.toLowerCase()) && - record.command === 'create' && - record.registrar_id == registrarId - ); - - // If no registrar-specific price found, find the generic price - if (!tldData) { - tldData = pricingData.records.find(record => - record.tldid && tldRegex.test(record.tldid.tld.toLowerCase()) && - record.command === 'create' && - record.registrar_id == null - ); - } - - if (tldData) { - const priceField = `m${years * 12}`; - let price = parseFloat(tldData[priceField]); - if (!isNaN(price)) { - if (promo) { - // Apply the promotion discount - price -= (price * parseFloat(promo.discount_percentage) / 100); - } - return price; + return fetch(apiUrl) + .then(response => response.json()) + .then(data => { + // If the response is a raw number (e.g., 0.5), wrap it in an object + if (typeof data === "number") { + data = { price: data }; } - } - return Promise.reject("TLD price not found"); - }) - .catch(error => { - console.error("Error fetching pricing data:", error); - return Promise.reject("Error fetching pricing data"); - }); + + if (!data || typeof data !== "object" || !("price" in data)) { + console.error("Invalid API response structure:", data); + return Promise.reject("Invalid API response structure"); + } + + // Convert price to float safely + const price = parseFloat(data.price); + if (isNaN(price)) { + console.error("Invalid price received:", data.price); + return Promise.reject("Invalid price received"); + } + + return { price, type: data.type || "regular" }; + }) + .catch(error => { + console.error("Error fetching domain price:", error); + return Promise.reject("Error fetching domain price"); + }); } function formatPrice(price) { switch(window.currencyPosition) { case 'before': - return `{{ currency }} ${price.toFixed(2)}`; + return `${"{{ currency }}"} ${price.toFixed(2)}`; case 'after': - return `${price.toFixed(2)} {{ currency }}`; + return `${price.toFixed(2)} ${"{{ currency }}"} `; default: return price.toFixed(2); } } function updatePrice() { - if (domainInput.value) { - const registrarId = registrarDropdown.value; - getDomainPrice(domainInput.value, yearInput.value, registrarId).then(price => { - priceValue.innerText = formatPrice(price); + const domainValue = document.getElementById('domainName')?.value.trim() || ""; + const registrarId = document.getElementById('registrarDropdown')?.value || ""; + const years = parseInt(document.getElementById('registrationYears')?.value, 10) || 1; + + if (domainValue) { + getDomainPrice(domainValue, years, registrarId).then(({ price, type }) => { + if (isNaN(price)) { + console.error("Invalid price received:", price); + priceValue.innerText = formatPrice(0.00); + return; + } + + // Multiply price by years + const totalPrice = price * years; + + priceValue.innerText = formatPrice(totalPrice); priceDisplay.style.display = 'block'; + + // Remove existing color classes + priceValue.classList.remove('text-red', 'text-green', 'text-blue'); + + // Apply appropriate colors based on type + if (type === "promotion") { + priceValue.classList.add('text-green'); // Mark as promotion + priceDisplay.title = "Promotional Price"; + } else if (type === "premium") { + priceValue.classList.add('text-red'); // Mark as premium + priceDisplay.title = "Premium Price"; + } else { + priceValue.classList.add('text-blue'); // Default regular price + priceDisplay.title = "Regular Price"; + } + + }).catch(error => { + console.error("Error fetching price:", error); + priceDisplay.style.display = 'none'; }); } else { priceDisplay.style.display = 'none'; @@ -549,6 +540,7 @@ document.addEventListener("DOMContentLoaded", function() { domainInput.addEventListener('input', updatePrice); yearInput.addEventListener('input', updatePrice); registrarDropdown.addEventListener('change', updatePrice); + yearSlider.addEventListener('input', updatePrice); }); {% endblock %} \ No newline at end of file diff --git a/cp/resources/views/admin/domains/renewDomain.twig b/cp/resources/views/admin/domains/renewDomain.twig index 9fb09fe..5533808 100644 --- a/cp/resources/views/admin/domains/renewDomain.twig +++ b/cp/resources/views/admin/domains/renewDomain.twig @@ -78,117 +78,103 @@ document.addEventListener("DOMContentLoaded", function() { const yearSlider = document.getElementById('renewalYears'); const yearValueDisplay = document.getElementById('yearValue'); - - // Display year value from slider - yearSlider.addEventListener('input', function() { - yearValueDisplay.textContent = `${yearSlider.value} Year${yearSlider.value > 1 ? 's' : ''}`; - }); - - const registrarId = "{{ registrars.id }}"; // Embedded securely in JavaScript - const domainInput = document.getElementById('domainName'); + const domainValue = "{{ domain.name }}"; // Get domain from Twig directly const yearInput = document.getElementById('renewalYears'); const priceDisplay = document.getElementById('domainPriceDisplay'); const priceValue = document.getElementById('domainPrice'); - - function extractTLD(domain) { - const parts = domain.split('.'); - - // If the domain has more than two segments (e.g., 'test.com.test'), return the last two segments - if (parts.length > 2) { - return parts.slice(-2).join('.').toLowerCase(); - } - // If the domain has two or fewer segments (e.g., 'test.test' or 'test'), return the last segment - else { - return parts[parts.length - 1].toLowerCase(); - } - } - + + // Display year value from slider + yearSlider.addEventListener('input', function() { + yearValueDisplay.textContent = `${yearSlider.value} Year${yearSlider.value > 1 ? 's' : ''}`; + updatePrice(); // Call updatePrice() directly when slider moves + }); + function getDomainPrice(domain, years, registrarId) { - const tld = extractTLD(domain); - if (!tld) { - return Promise.reject("Invalid TLD"); - } + const currency = "{{ currency }}"; + const apiUrl = `/dapi/domain/price?domain_name=${encodeURIComponent(domain)}&date_add=${years * 12}&command=renew®istrar_id=${encodeURIComponent(registrarId)}¤cy=${encodeURIComponent(currency)}`; - // Regular expression for exact TLD match - const tldRegex = new RegExp(`${tld.toLowerCase()}$`); - - // Fetch both promotional pricing and regular pricing - return Promise.all([ - fetch(`/api/records/promotion_pricing?join=domain_tld`).then(response => response.json()), - fetch(`/api/records/domain_price?join=domain_tld`).then(response => response.json()) - ]) - .then(([promoData, pricingData]) => { - const today = new Date(); - - // Check for a valid promotion - const promo = promoData.records.find(record => - record.tld_id && tldRegex.test(record.tld_id.tld.toLowerCase()) && - new Date(record.start_date) <= today && - new Date(record.end_date) >= today && - (!record.years_of_promotion || record.years_of_promotion >= years) - ); - - // Find the regular price for the TLD with registrar ID - let tldData = pricingData.records.find(record => - record.tldid && tldRegex.test(record.tldid.tld.toLowerCase()) && - record.command === 'renew' && - record.registrar_id == registrarId - ); - - // If no registrar-specific price found, find the generic price - if (!tldData) { - tldData = pricingData.records.find(record => - record.tldid && tldRegex.test(record.tldid.tld.toLowerCase()) && - record.command === 'renew' && - record.registrar_id == null - ); - } - - if (tldData) { - const priceField = `m${years * 12}`; - let price = parseFloat(tldData[priceField]); - if (!isNaN(price)) { - if (promo) { - // Apply the promotion discount - price -= (price * parseFloat(promo.discount_percentage) / 100); - } - return price; + return fetch(apiUrl) + .then(response => response.json()) + .then(data => { + // If the response is a raw number (e.g., 0.5), wrap it in an object + if (typeof data === "number") { + data = { price: data }; } - } - return Promise.reject("TLD price not found"); - }) - .catch(error => { - console.error("Error fetching pricing data:", error); - return Promise.reject("Error fetching pricing data"); - }); + + if (!data || typeof data !== "object" || !("price" in data)) { + console.error("Invalid API response structure:", data); + return Promise.reject("Invalid API response structure"); + } + + // Convert price to float safely + const price = parseFloat(data.price); + if (isNaN(price)) { + console.error("Invalid price received:", data.price); + return Promise.reject("Invalid price received"); + } + + return { price, type: data.type || "regular" }; + }) + .catch(error => { + console.error("Error fetching domain price:", error); + return Promise.reject("Error fetching domain price"); + }); } function formatPrice(price) { switch(window.currencyPosition) { case 'before': - return `{{ currency }} ${price.toFixed(2)}`; + return `${"{{ currency }}"} ${price.toFixed(2)}`; case 'after': - return `${price.toFixed(2)} {{ currency }}`; + return `${price.toFixed(2)} ${"{{ currency }}"} `; default: return price.toFixed(2); } } function updatePrice() { - if (domainInput.textContent) { - getDomainPrice(domainInput.textContent, yearInput.value, registrarId).then(price => { - priceValue.innerText = formatPrice(price); + const domainValue = "{{ domain.name }}"; + const registrarId = document.getElementById('registrarDropdown')?.value || ""; + const years = parseInt(document.getElementById('renewalYears')?.value, 10) || 1; + + if (domainValue) { + getDomainPrice(domainValue, years, registrarId).then(({ price, type }) => { + if (isNaN(price)) { + console.error("Invalid price received:", price); + priceValue.innerText = formatPrice(0.00); + return; + } + + // Multiply price by years + const totalPrice = price * years; + + priceValue.innerText = formatPrice(totalPrice); priceDisplay.style.display = 'block'; + + // Remove existing color classes + priceValue.classList.remove('text-red', 'text-green', 'text-blue'); + + // Apply appropriate colors based on type + if (type === "promotion") { + priceValue.classList.add('text-green'); // Mark as promotion + priceDisplay.title = "Promotional Price"; + } else if (type === "premium") { + priceValue.classList.add('text-red'); // Mark as premium + priceDisplay.title = "Premium Price"; + } else { + priceValue.classList.add('text-blue'); // Default regular price + priceDisplay.title = "Regular Price"; + } + }).catch(error => { - console.error(error); - // Handle the error or display a message as needed + console.error("Error fetching price:", error); + priceDisplay.style.display = 'none'; }); } else { priceDisplay.style.display = 'none'; } } - domainInput.addEventListener('input', updatePrice); yearInput.addEventListener('input', updatePrice); updatePrice(); diff --git a/cp/resources/views/admin/domains/requestTransfer.twig b/cp/resources/views/admin/domains/requestTransfer.twig index c97587a..cac75de 100644 --- a/cp/resources/views/admin/domains/requestTransfer.twig +++ b/cp/resources/views/admin/domains/requestTransfer.twig @@ -91,108 +91,97 @@ document.addEventListener("DOMContentLoaded", function() { const yearSlider = document.getElementById('transferYears'); const yearValueDisplay = document.getElementById('yearValue'); - - // Display year value from slider - yearSlider.addEventListener('input', function() { - yearValueDisplay.textContent = `${yearSlider.value} Year${yearSlider.value > 1 ? 's' : ''}`; - }); - const domainInput = document.getElementById('domainName'); const yearInput = document.getElementById('transferYears'); const priceDisplay = document.getElementById('domainPriceDisplay'); const priceValue = document.getElementById('domainPrice'); - const registrarDropdown = document.getElementById('registrarDropdown'); - - function extractTLD(domain) { - const parts = domain.split('.'); - - // If the domain has more than two segments (e.g., 'test.com.test'), return the last two segments - if (parts.length > 2) { - return parts.slice(-2).join('.').toLowerCase(); - } - // If the domain has two or fewer segments (e.g., 'test.test' or 'test'), return the last segment - else { - return parts[parts.length - 1].toLowerCase(); - } - } + + // Display year value from slider + yearSlider.addEventListener('input', function() { + yearValueDisplay.textContent = `${yearSlider.value} Year${yearSlider.value > 1 ? 's' : ''}`; + updatePrice(); // Call updatePrice() directly when slider moves + }); function getDomainPrice(domain, years, registrarId) { - const tld = extractTLD(domain); - if (!tld) { - return Promise.reject("Invalid TLD"); - } + const currency = "{{ currency }}"; + const apiUrl = `/dapi/domain/price?domain_name=${encodeURIComponent(domain)}&date_add=${years * 12}&command=transfer®istrar_id=${encodeURIComponent(registrarId)}¤cy=${encodeURIComponent(currency)}`; - // Regular expression for exact TLD match - const tldRegex = new RegExp(`${tld.toLowerCase()}$`); - - // Fetch both promotional pricing and regular pricing - return Promise.all([ - fetch(`/api/records/promotion_pricing?join=domain_tld`).then(response => response.json()), - fetch(`/api/records/domain_price?join=domain_tld`).then(response => response.json()) - ]) - .then(([promoData, pricingData]) => { - const today = new Date(); - - // Check for a valid promotion - const promo = promoData.records.find(record => - record.tld_id && tldRegex.test(record.tld_id.tld.toLowerCase()) && - new Date(record.start_date) <= today && - new Date(record.end_date) >= today && - (!record.years_of_promotion || record.years_of_promotion >= years) - ); - - // Find the regular price for the TLD with registrar ID - let tldData = pricingData.records.find(record => - record.tldid && tldRegex.test(record.tldid.tld.toLowerCase()) && - record.command === 'transfer' && - record.registrar_id == registrarId - ); - - // If no registrar-specific price found, find the generic price - if (!tldData) { - tldData = pricingData.records.find(record => - record.tldid && tldRegex.test(record.tldid.tld.toLowerCase()) && - record.command === 'transfer' && - record.registrar_id == null - ); - } - - if (tldData) { - const priceField = `m${years * 12}`; - let price = parseFloat(tldData[priceField]); - if (!isNaN(price)) { - if (promo) { - // Apply the promotion discount - price -= (price * parseFloat(promo.discount_percentage) / 100); - } - return price; + return fetch(apiUrl) + .then(response => response.json()) + .then(data => { + // If the response is a raw number (e.g., 0.5), wrap it in an object + if (typeof data === "number") { + data = { price: data }; } - } - return Promise.reject("TLD price not found"); - }) - .catch(error => { - console.error("Error fetching pricing data:", error); - return Promise.reject("Error fetching pricing data"); - }); + + if (!data || typeof data !== "object" || !("price" in data)) { + console.error("Invalid API response structure:", data); + return Promise.reject("Invalid API response structure"); + } + + // Convert price to float safely + const price = parseFloat(data.price); + if (isNaN(price)) { + console.error("Invalid price received:", data.price); + return Promise.reject("Invalid price received"); + } + + return { price, type: data.type || "regular" }; + }) + .catch(error => { + console.error("Error fetching domain price:", error); + return Promise.reject("Error fetching domain price"); + }); } function formatPrice(price) { switch(window.currencyPosition) { case 'before': - return `{{ currency }} ${price.toFixed(2)}`; + return `${"{{ currency }}"} ${price.toFixed(2)}`; case 'after': - return `${price.toFixed(2)} {{ currency }}`; + return `${price.toFixed(2)} ${"{{ currency }}"} `; default: return price.toFixed(2); } } function updatePrice() { - if (domainInput.value) { - const registrarId = registrarDropdown.value; - getDomainPrice(domainInput.value, yearInput.value, registrarId).then(price => { - priceValue.innerText = formatPrice(price); + const domainValue = document.getElementById('domainName')?.value.trim() || ""; + const registrarId = document.getElementById('registrarDropdown')?.value || ""; + const years = parseInt(document.getElementById('transferYears')?.value, 10) || 1; + + if (domainValue) { + getDomainPrice(domainValue, years, registrarId).then(({ price, type }) => { + if (isNaN(price)) { + console.error("Invalid price received:", price); + priceValue.innerText = formatPrice(0.00); + return; + } + + // Multiply price by years + const totalPrice = price * years; + + priceValue.innerText = formatPrice(totalPrice); priceDisplay.style.display = 'block'; + + // Remove existing color classes + priceValue.classList.remove('text-red', 'text-green', 'text-blue'); + + // Apply appropriate colors based on type + if (type === "promotion") { + priceValue.classList.add('text-green'); // Mark as promotion + priceDisplay.title = "Promotional Price"; + } else if (type === "premium") { + priceValue.classList.add('text-red'); // Mark as premium + priceDisplay.title = "Premium Price"; + } else { + priceValue.classList.add('text-blue'); // Default regular price + priceDisplay.title = "Regular Price"; + } + + }).catch(error => { + console.error("Error fetching price:", error); + priceDisplay.style.display = 'none'; }); } else { priceDisplay.style.display = 'none'; @@ -202,6 +191,7 @@ document.addEventListener("DOMContentLoaded", function() { domainInput.addEventListener('input', updatePrice); yearInput.addEventListener('input', updatePrice); registrarDropdown.addEventListener('change', updatePrice); + yearSlider.addEventListener('input', updatePrice); }); {% endblock %} \ No newline at end of file diff --git a/cp/routes/web.php b/cp/routes/web.php index ca46ad3..892323e 100644 --- a/cp/routes/web.php +++ b/cp/routes/web.php @@ -163,6 +163,7 @@ $app->group('', function ($route) { $route->get('/dapi/applications', [DapiController::class, 'listApplications']); $route->get('/dapi/payments', [DapiController::class, 'listPayments']); $route->get('/dapi/statements', [DapiController::class, 'listStatements']); + $route->get('/dapi/domain/price', [DapiController::class, 'domainPrice']); })->add(new AuthMiddleware($container)); $app->any('/api[/{params:.*}]', function (