From 0e88a8d13ea600da025face7a99c61daa279ea09 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 23 Jun 2025 13:25:46 +0200 Subject: [PATCH] move code to static files --- hub/services/static/css/price-calculator.css | 33 +++++++++++ hub/services/static/js/price-calculator.js | 20 ++++++- .../templates/services/offering_detail.html | 55 ------------------- hub/services/templatetags/json_ld_tags.py | 31 ++++------- 4 files changed, 64 insertions(+), 75 deletions(-) diff --git a/hub/services/static/css/price-calculator.css b/hub/services/static/css/price-calculator.css index de8074e..5efe5f6 100644 --- a/hub/services/static/css/price-calculator.css +++ b/hub/services/static/css/price-calculator.css @@ -33,4 +33,37 @@ to { opacity: 1; } +} + + +/* Subtle styling for the best plan */ +.card.border-success.border-2 { + box-shadow: 0 0.25rem 0.75rem rgba(25, 135, 84, 0.1) !important; + transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out; +} + +.card.border-success.border-2:hover { + transform: translateY(-2px); + box-shadow: 0 0.5rem 1rem rgba(25, 135, 84, 0.15) !important; +} + +/* Best choice badge styling */ +.badge.bg-success { + background: linear-gradient(135deg, #198754 0%, #20c997 100%) !important; + border: 2px solid white; + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); + white-space: nowrap; + font-size: 0.75rem; + padding: 0.5rem 0.75rem; + min-width: max-content; +} + +/* Subtle enhancement for best plan button */ +.btn-success.shadow { + transition: all 0.2s ease-in-out; +} + +.btn-success.shadow:hover { + transform: translateY(-1px); + box-shadow: 0 0.25rem 0.75rem rgba(25, 135, 84, 0.2) !important; } \ No newline at end of file diff --git a/hub/services/static/js/price-calculator.js b/hub/services/static/js/price-calculator.js index 54b2af9..9ea66bb 100644 --- a/hub/services/static/js/price-calculator.js +++ b/hub/services/static/js/price-calculator.js @@ -1834,4 +1834,22 @@ document.addEventListener('DOMContentLoaded', () => { if (document.getElementById('cpuRange')) { new PriceCalculator(); } -}); \ No newline at end of file +}); + +function selectPlan(element) { + const planId = element.getAttribute('data-plan-id'); + const planName = element.getAttribute('data-plan-name'); + + // Find the plan dropdown in the contact form + const planDropdown = document.getElementById('id_choice'); + if (planDropdown) { + // Find the option with matching plan id and select it + for (let i = 0; i < planDropdown.options.length; i++) { + const optionValue = planDropdown.options[i].value; + if (optionValue.startsWith(planId + '|')) { + planDropdown.selectedIndex = i; + break; + } + } + } +} \ No newline at end of file diff --git a/hub/services/templates/services/offering_detail.html b/hub/services/templates/services/offering_detail.html index 15e9e72..7263024 100644 --- a/hub/services/templates/services/offering_detail.html +++ b/hub/services/templates/services/offering_detail.html @@ -9,62 +9,7 @@ - {% json_ld_structured_data %} - - - {% endblock %} {% block content %} diff --git a/hub/services/templatetags/json_ld_tags.py b/hub/services/templatetags/json_ld_tags.py index e95ba70..eb18007 100644 --- a/hub/services/templatetags/json_ld_tags.py +++ b/hub/services/templatetags/json_ld_tags.py @@ -225,19 +225,21 @@ def json_ld_structured_data(context): # Add offers if available if hasattr(offering, "plans") and offering.plans.exists(): # Get all plans with pricing - plans_with_prices = offering.plans.filter(plan_prices__isnull=False).distinct() - + plans_with_prices = offering.plans.filter( + plan_prices__isnull=False + ).distinct() + if plans_with_prices.exists(): # Create individual offers for each plan offers = [] all_prices = [] - + for plan in plans_with_prices: plan_prices = plan.plan_prices.all() if plan_prices.exists(): first_price = plan_prices.first() all_prices.extend([p.amount for p in plan_prices]) - + offer = { "@type": "Offer", "name": plan.name, @@ -245,25 +247,19 @@ def json_ld_structured_data(context): "priceCurrency": first_price.currency, "availability": "https://schema.org/InStock", "url": offering_url + "#plan-order-form", - "seller": { - "@type": "Organization", - "name": "VSHN" - } + "seller": {"@type": "Organization", "name": "VSHN"}, } offers.append(offer) - + # Add aggregate offer with all individual offers data["offers"] = { "@type": "AggregateOffer", "availability": "https://schema.org/InStock", "offerCount": len(offers), "offers": offers, - "seller": { - "@type": "Organization", - "name": "VSHN" - } + "seller": {"@type": "Organization", "name": "VSHN"}, } - + # Add lowPrice, highPrice and priceCurrency if we have prices if all_prices: data["offers"]["lowPrice"] = str(min(all_prices)) @@ -272,7 +268,7 @@ def json_ld_structured_data(context): first_plan_with_prices = plans_with_prices.first() first_currency = first_plan_with_prices.plan_prices.first().currency data["offers"]["priceCurrency"] = first_currency - + # Note: aggregateRating and review fields are not included as this is a B2B # service marketplace without a review system. These could be added in the future # if customer reviews/ratings are implemented. @@ -289,10 +285,7 @@ def json_ld_structured_data(context): "@type": "AggregateOffer", "availability": "https://schema.org/InStock", "offerCount": offering.plans.count(), - "seller": { - "@type": "Organization", - "name": "VSHN" - } + "seller": {"@type": "Organization", "name": "VSHN"}, } else: