369 lines
17 KiB
HTML
369 lines
17 KiB
HTML
{% extends 'base.html' %}
|
|
{% load i18n static %}
|
|
{% load custom_filters %}
|
|
{%block title%} {% trans 'Upgrade Plan' %} {%endblock%}
|
|
|
|
{% block customCSS %}
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css" integrity="sha512-X..." crossorigin="anonymous" referrerpolicy="no-referrer" />
|
|
|
|
<style>
|
|
.pricing-card .card {
|
|
transition: all 0.3s ease-in-out;
|
|
}
|
|
|
|
.pricing-card .card.selected {
|
|
border-color: #0d6efd;
|
|
box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.4);
|
|
}
|
|
|
|
.btn-check:checked + .btn .card {
|
|
/* fallback if JS fails */
|
|
border-color: #0d6efd;
|
|
box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
|
|
}
|
|
|
|
.card.selected {
|
|
border-color: #0d6efd;
|
|
box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.4);
|
|
}
|
|
|
|
.summary-box {
|
|
border: 1px solid #8d8f94;
|
|
border-radius: 0.5rem;
|
|
padding: 1.5rem;
|
|
}
|
|
|
|
.summary-box h5 {
|
|
padding-bottom: 0.5rem;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.summary-item {
|
|
margin-bottom: 0.75rem;
|
|
}
|
|
|
|
.form-label {
|
|
font-weight: 500;
|
|
}
|
|
</style>
|
|
{% endblock customCSS %}
|
|
|
|
{% block content %}
|
|
<div class="container py-5">
|
|
<h1 class="text-center mb-5">{{ _("Choose Your Plan")}}</h1>
|
|
<form method="POST" action="{% url 'submit_plan' %}" id="wizardForm">
|
|
{% csrf_token %}
|
|
<!-- Step 1: Plan Selection -->
|
|
<div class="step" id="step1">
|
|
<h4 class="mb-4">1. {{ _("Select a Plan")}}</h4>
|
|
<div class="row g-4">
|
|
{% for pp in plan_list %}
|
|
<div class="col-md-6 col-lg-3">
|
|
<input type="radio" class="btn-check" name="selected_plan" id="plan_{{ forloop.counter }}" value="{{ pp.id }}"
|
|
data-name="{{ pp.plan.name }}" data-price="{{ pp.price }}" autocomplete="off" {% if forloop.first %}checked{% endif %}>
|
|
<label class="btn w-100 p-0 pricing-card" for="plan_{{ forloop.counter }}">
|
|
<div class="card h-100 border border-2 rounded-4">
|
|
<div class="card-body p-4">
|
|
<h4 class="mb-3">{{ pp.plan.name }}</h4>
|
|
<h5 class="mb-4">{{ pp.price }} <span class="currency">{{ CURRENCY }}</span><span class="fs-6 fw-normal">/ {{ pp.pricing.period }}</span> {% trans "days" %}</h5>
|
|
<h6>{{ _("Included") }}</h6>
|
|
<ul class="fa-ul ps-3">
|
|
{% if pp.plan.description %}
|
|
{% for line in pp.plan.description|splitlines %}
|
|
<li class="mb-2">
|
|
<span class="fa-li"><i class="fas fa-check text-primary"></i></span>
|
|
{{ line }}
|
|
</li>
|
|
{% endfor %}
|
|
{% endif %}
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</label>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Step 2: User Info -->
|
|
<div class="step d-none" id="step2">
|
|
<h4 class="mb-4">2. {{ _("Enter Your Information")}}</h4>
|
|
<div class="row g-3">
|
|
<div class="col-md-6">
|
|
<label class="form-label" for="first_name">{{ _("First Name")}}</label>
|
|
<div class="input-group">
|
|
<span class="input-group-text"><i class="fas fa-user"></i></span>
|
|
<input type="text" name="first_name" id="first_name" class="form-control form-control-sm" required placeholder="{{ _("First Name")}}" value="{{ request.user.first_name }}">
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label" for="last_name">{{ _("Last Name")}}</label>
|
|
<div class="input-group">
|
|
<span class="input-group-text"><i class="fas fa-user"></i></span>
|
|
<input type="text" name="last_name" id="last_name" class="form-control form-control-sm" required placeholder="{{ _("Last Name")}}" value="{{ request.user.last_name }}">
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label" for="email">{{ _("Email Address")}}</label>
|
|
<div class="input-group">
|
|
<span class="input-group-text"><i class="fas fa-envelope"></i></span>
|
|
<input type="email" name="email" id="email" class="form-control form-control-sm" required placeholder="email@example.com" value="{{ request.user.email }}">
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label" for="phone">{{ _("Phone Number")}}</label>
|
|
<div class="input-group">
|
|
<span class="input-group-text"><i class="fas fa-phone"></i></span>
|
|
<input type="text" name="phone" id="phone" class="form-control form-control-sm" dir="ltr" placeholder="{{ _("Phone Number")}}" value="{{ request.user.dealer.phone_number.raw_input }}" required>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label" for="company">{{ _("Company") }}</label>
|
|
<div class="input-group">
|
|
<span class="input-group-text"><i class="fas fa-building"></i></span>
|
|
<input type="text" name="company" id="company" class="form-control form-control-sm" placeholder="{{ _("Company") }}" value="{{ request.user.dealer.get_local_name }}">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Step 3: Payment -->
|
|
<div class="step d-none" id="step3">
|
|
<h4 class="mb-4">3. {{ _("Payment Information")}}</h4>
|
|
<div class="row g-3">
|
|
<div class="col-md-6">
|
|
<label class="form-label" for="card_name">{{ _("Cardholder Name")}}</label>
|
|
<div class="input-group">
|
|
<span class="input-group-text"><i class="fas fa-user"></i></span>
|
|
<input type="text" name="card_name" id="card_name" class="form-control form-control-sm" placeholder="{{ _("Cardholder Name")}}" required>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-6">
|
|
<label class="form-label" for="card_number">{{ _("Card Number")}}</label>
|
|
<div class="input-group">
|
|
<span class="input-group-text"><i class="fas fa-credit-card"></i></span>
|
|
<input type="text" name="card_number" id="card_number" class="form-control form-control-sm" placeholder="{{ _("Card Number")}}"
|
|
maxlength="19" pattern="^\d{4}\s\d{4}\s\d{4}\s\d{4}$"
|
|
inputmode="numeric" required title="Enter a 16-digit card number">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-4">
|
|
<label class="form-label" for="card_expiry">{{ _("Expiry Date")}} (MM/YY)</label>
|
|
<div class="input-group">
|
|
<span class="input-group-text"><i class="far fa-calendar-alt"></i></span>
|
|
<input type="text" name="card_expiry" id="card_expiry" class="form-control form-control-sm" placeholder="{{ _("Expiry Date")}}"
|
|
maxlength="5" pattern="^(0[1-9]|1[0-2])\/\d{2}$"
|
|
inputmode="numeric" required title="Enter expiry in MM/YY format">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-2">
|
|
<label class="form-label" for="card_cvv">{{ _("CVV") }}</label>
|
|
<div class="input-group">
|
|
<span class="input-group-text"><i class="fas fa-lock"></i></span>
|
|
<input type="text" name="card_cvv" id="card_cvv" class="form-control form-control-sm" placeholder="{{ _("CVV") }}"
|
|
maxlength="3" pattern="^\d{3}$"
|
|
inputmode="numeric" required title="Enter 3-digit CVV">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Step 4: Confirmation -->
|
|
<div class="step d-none" id="step4">
|
|
<h4 class="mb-4">4. {{ _("Confirm Your Information")}}</h4>
|
|
<div class="summary-box">
|
|
<h5><i class="fas fa-file-invoice-dollar me-2"></i>{{ _("Order Summary")}}</h5>
|
|
<div class="summary-item"><i class="fas fa-box"></i><strong>{{ _("Plan") }}:</strong> <span id="summary_plan"></span></div>
|
|
<div class="summary-item"><i class="fas fa-tag"></i><strong>{{ _("Price") }}:</strong> <span id="summary_price"></span></div>
|
|
<div class="summary-item"><i class="fas fa-receipt"></i><strong>{{ _("VAT") }} (15%):</strong> <span id="summary-tax">0.00</span> <span class="currency">{{ CURRENCY }}</span></div>
|
|
<hr>
|
|
<div class="summary-item"><i class="fas fa-hand-holding-usd"></i><strong>{{ _("Total") }}:</strong> <span id="summary-total">0.00</span> <span class="currency">{{ CURRENCY }}</span></div>
|
|
|
|
<h5 class="mt-4"><i class="fas fa-user me-2"></i>{{ _("User Information")}}</h5>
|
|
<div class="summary-item"><i class="fas fa-signature"></i><strong>{{ _("Name") }}:</strong> <span id="summary_name"></span></div>
|
|
<div class="summary-item"><i class="fas fa-envelope"></i><strong>{{ _("Email") }}:</strong> <span id="summary_email"></span></div>
|
|
<div class="summary-item"><i class="fas fa-building"></i><strong>{{ _("Company") }}:</strong> <span id="summary_company"></span></div>
|
|
<div class="summary-item"><i class="fas fa-phone"></i><strong>{{ _("Phone") }}:</strong> <span id="summary_phone"></span></div>
|
|
|
|
<h5 class="mt-4"><i class="fas fa-credit-card me-2"></i>{{ _("Payment") }}</h5>
|
|
<div class="summary-item"><i class="fas fa-user"></i><strong>{{ _("Cardholder") }}:</strong> <span id="summary_card_name"></span></div>
|
|
<div class="summary-item"><i class="fas fa-credit-card"></i><strong>{{ _("Card Number")}}:</strong> <span id="summary_card_number"></span></div>
|
|
<div class="summary-item"><i class="far fa-calendar-alt"></i><strong>{{ _("Expiry") }}:</strong> <span id="summary_card_expiry"></span></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Navigation -->
|
|
<div class="d-flex justify-content-between mt-4">
|
|
<button type="button" class="btn btn-outline-secondary" id="prevBtn" disabled>{{ _("Previous") }}</button>
|
|
<button type="button" class="btn btn-primary" id="nextBtn">{{ _("Next") }}</button>
|
|
<button type="submit" class="btn btn-success d-none" id="submitBtn">{{ _("Confirm") }}</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
{% endblock content %}
|
|
|
|
{% block customJS %}
|
|
<script>
|
|
document.addEventListener("DOMContentLoaded", function () {
|
|
const form = document.getElementById('wizardForm');
|
|
|
|
form.addEventListener('submit', function(e) {
|
|
e.preventDefault(); // Prevent default form submission
|
|
|
|
// Show loading alert
|
|
Swal.fire({
|
|
title: 'Processing...',
|
|
html: 'Please wait while we submit your form',
|
|
allowOutsideClick: false,
|
|
didOpen: () => {
|
|
Swal.showLoading();
|
|
}
|
|
});
|
|
|
|
// Submit the form after a slight delay to ensure Swal is shown
|
|
setTimeout(() => {
|
|
form.submit();
|
|
}, 100);
|
|
});
|
|
|
|
const radios = document.querySelectorAll('.btn-check');
|
|
radios.forEach(radio => {
|
|
radio.addEventListener('change', function () {
|
|
document.querySelectorAll('.pricing-card .card').forEach(card => {
|
|
card.classList.remove('selected');
|
|
});
|
|
if (this.checked) {
|
|
const selectedCard = document.querySelector(`label[for="${this.id}"] .card`);
|
|
selectedCard.classList.add('selected');
|
|
}
|
|
});
|
|
|
|
// Trigger change on page load if checked
|
|
if (radio.checked) {
|
|
const selectedCard = document.querySelector(`label[for="${radio.id}"] .card`);
|
|
selectedCard.classList.add('selected');
|
|
}
|
|
});
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////////////////////////////////////////////////////////////
|
|
let currentStep = 0;
|
|
const steps = document.querySelectorAll(".step");
|
|
const nextBtn = document.getElementById("nextBtn");
|
|
const prevBtn = document.getElementById("prevBtn");
|
|
const submitBtn = document.getElementById("submitBtn");
|
|
|
|
function showStep(index) {
|
|
steps.forEach((step, i) => {
|
|
step.classList.toggle("d-none", i !== index);
|
|
});
|
|
prevBtn.disabled = index === 0;
|
|
nextBtn.classList.toggle("d-none", index === steps.length - 1);
|
|
submitBtn.classList.toggle("d-none", index !== steps.length - 1);
|
|
|
|
// If last step, populate summary
|
|
if (index === steps.length - 1) {
|
|
populateSummary();
|
|
}
|
|
}
|
|
|
|
function populateSummary() {
|
|
const selectedPlan = document.querySelector('input[name="selected_plan"]:checked');
|
|
document.getElementById("summary_plan").textContent = selectedPlan.dataset.name;
|
|
document.getElementById("summary_price").textContent = selectedPlan.dataset.price;
|
|
|
|
/*const currencyElement = document.createElement("span");
|
|
currencyElement.classList.add("currency");
|
|
currencyElement.textContent = "{{ CURRENCY }}";
|
|
document.getElementById("summary_price").appendChild(currencyElement);*/
|
|
|
|
document.getElementById("summary_name").textContent = document.getElementById("first_name").value + " " + document.getElementById("last_name").value;
|
|
document.getElementById("summary_email").textContent = document.getElementById("email").value;
|
|
document.getElementById("summary_company").textContent = document.getElementById("company").value;
|
|
document.getElementById("summary_phone").textContent = document.getElementById("phone").value;
|
|
|
|
document.getElementById("summary_card_name").textContent = document.getElementById("card_name").value;
|
|
document.getElementById("summary_card_number").textContent = maskCard(document.getElementById("card_number").value);
|
|
document.getElementById("summary_card_expiry").textContent = document.getElementById("card_expiry").value;
|
|
}
|
|
|
|
function maskCard(cardNumber) {
|
|
const last4 = cardNumber.slice(-4);
|
|
return "**** **** **** " + last4;
|
|
}
|
|
|
|
nextBtn.addEventListener("click", () => {
|
|
if (currentStep < steps.length - 1) {
|
|
currentStep++;
|
|
showStep(currentStep);
|
|
}
|
|
});
|
|
|
|
prevBtn.addEventListener("click", () => {
|
|
if (currentStep > 0) {
|
|
currentStep--;
|
|
showStep(currentStep);
|
|
}
|
|
});
|
|
|
|
// Highlight selected plan
|
|
document.querySelectorAll(".btn-check").forEach(input => {
|
|
input.addEventListener("change", () => {
|
|
document.querySelectorAll(".pricing-card .card").forEach(card => card.classList.remove("selected"));
|
|
document.querySelector(`label[for="${input.id}"] .card`).classList.add("selected");
|
|
});
|
|
|
|
if (input.checked) {
|
|
document.querySelector(`label[for="${input.id}"] .card`).classList.add("selected");
|
|
}
|
|
});
|
|
|
|
showStep(currentStep);
|
|
//////////////////////////////////////////////////////////////////////////////////////
|
|
const cardNumberInput = document.getElementById("card_number");
|
|
cardNumberInput.addEventListener("input", function (e) {
|
|
let val = cardNumberInput.value.replace(/\D/g, "").substring(0, 16); // Only digits
|
|
let formatted = val.replace(/(.{4})/g, "$1 ").trim();
|
|
cardNumberInput.value = formatted;
|
|
});
|
|
|
|
// Format expiry date as MM/YY
|
|
const expiryInput = document.getElementById("card_expiry");
|
|
expiryInput.addEventListener("input", function (e) {
|
|
let val = expiryInput.value.replace(/\D/g, "").substring(0, 4); // Only digits
|
|
if (val.length >= 3) {
|
|
val = val.substring(0, 2) + "/" + val.substring(2);
|
|
}
|
|
expiryInput.value = val;
|
|
});
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////
|
|
const planInputs = document.querySelectorAll("input[name='selected_plan']");
|
|
const summaryPlanName = document.getElementById("summary_plan");
|
|
const summaryPrice = document.getElementById("summary_price"); //summary_price
|
|
const summaryTax = document.getElementById("summary-tax");
|
|
const summaryTotal = document.getElementById("summary-total");
|
|
|
|
function updateSummary() {
|
|
const selectedPlan = document.querySelector('input[name="selected_plan"]:checked');
|
|
if (selectedPlan) {
|
|
const price = parseFloat(selectedPlan.dataset.price);
|
|
const tax = price * 0.15;
|
|
const total = price + tax;
|
|
|
|
document.getElementById("summary_price").textContent = price.toFixed(2);
|
|
document.getElementById("summary-tax").textContent = tax.toFixed(2);
|
|
document.getElementById("summary-total").textContent = total.toFixed(2);
|
|
}
|
|
}
|
|
|
|
|
|
planInputs.forEach(input => input.addEventListener("change", updateSummary));
|
|
updateSummary(); // Initial call
|
|
});
|
|
</script>
|
|
|
|
{% endblock customJS %} |