Adds authentication and pricing pages for user onboarding
Introduces comprehensive user authentication flow with plan selection and registration Includes: - Pricing page with plan details and selection - Payment page with plan summary and card information - Signup page for different plan tiers - Shared authentication layout and design system improvements Enhances user onboarding experience with clear plan information and streamlined signup process
This commit is contained in:
parent
cd092f8290
commit
217a9cd95c
18 changed files with 2312 additions and 165 deletions
219
PlanTempus.Application/Features/Accounts/Pages/Payment.cshtml
Normal file
219
PlanTempus.Application/Features/Accounts/Pages/Payment.cshtml
Normal file
|
|
@ -0,0 +1,219 @@
|
|||
@page "/payment"
|
||||
@model PlanTempus.Application.Features.Accounts.Pages.PaymentModel
|
||||
@{
|
||||
ViewData["Title"] = "Betaling";
|
||||
Layout = "/Features/_Shared/Pages/_AuthLayout.cshtml";
|
||||
|
||||
var plan = Model.SelectedPlan;
|
||||
}
|
||||
|
||||
<swp-auth-layout>
|
||||
<!-- Order Summary Panel -->
|
||||
<swp-auth-plan-panel>
|
||||
<swp-auth-logo>
|
||||
<i class="ph ph-calendar-check"></i>
|
||||
<span>PlanTempus</span>
|
||||
</swp-auth-logo>
|
||||
|
||||
<swp-selected-plan-header>Din ordre</swp-selected-plan-header>
|
||||
|
||||
<swp-plan-card class="selected">
|
||||
<swp-plan-badge class="@plan.BadgeClass">
|
||||
<i class="ph @plan.BadgeIcon"></i>
|
||||
@plan.BadgeText
|
||||
</swp-plan-badge>
|
||||
<swp-plan-name>@plan.Name</swp-plan-name>
|
||||
<swp-plan-users>@plan.UserRange</swp-plan-users>
|
||||
@if (plan.PricePerMonth.HasValue)
|
||||
{
|
||||
<swp-plan-price>
|
||||
<swp-plan-price-amount>@plan.PriceDisplay</swp-plan-price-amount>
|
||||
<swp-plan-price-period>kr/md</swp-plan-price-period>
|
||||
</swp-plan-price>
|
||||
}
|
||||
|
||||
<swp-plan-features>
|
||||
@foreach (var feature in plan.Features)
|
||||
{
|
||||
<swp-plan-feature>
|
||||
<i class="ph ph-check-circle"></i>
|
||||
@feature
|
||||
</swp-plan-feature>
|
||||
}
|
||||
</swp-plan-features>
|
||||
|
||||
<swp-order-summary>
|
||||
<swp-order-line>
|
||||
<span>@plan.Name abonnement</span>
|
||||
<span>@(plan.PricePerMonth.HasValue ? $"{plan.PriceDisplay} kr" : "–")</span>
|
||||
</swp-order-line>
|
||||
<swp-order-line class="discount">
|
||||
<span>14 dages gratis prøve</span>
|
||||
<span>-@(plan.PricePerMonth.HasValue ? $"{plan.PriceDisplay} kr" : "–")</span>
|
||||
</swp-order-line>
|
||||
<swp-order-divider></swp-order-divider>
|
||||
<swp-order-line class="total">
|
||||
<span>At betale i dag</span>
|
||||
<span>0 kr</span>
|
||||
</swp-order-line>
|
||||
</swp-order-summary>
|
||||
</swp-plan-card>
|
||||
|
||||
<swp-change-plan-link>
|
||||
<a href="/pricing">
|
||||
<i class="ph ph-arrow-left"></i>
|
||||
Skift abonnement
|
||||
</a>
|
||||
</swp-change-plan-link>
|
||||
</swp-auth-plan-panel>
|
||||
|
||||
<!-- Payment Form Panel -->
|
||||
<swp-auth-form-panel>
|
||||
<swp-auth-form-container>
|
||||
<swp-auth-header>
|
||||
<swp-auth-title>Betalingsoplysninger</swp-auth-title>
|
||||
<swp-auth-description>Dit kort debiteres først efter prøveperioden</swp-auth-description>
|
||||
</swp-auth-header>
|
||||
|
||||
<swp-auth-form id="paymentForm">
|
||||
<swp-form-group>
|
||||
<swp-form-label>Kortnummer</swp-form-label>
|
||||
<swp-form-input class="has-icon">
|
||||
<input type="text"
|
||||
id="cardNumber"
|
||||
placeholder="1234 5678 9012 3456"
|
||||
maxlength="19"
|
||||
autocomplete="cc-number" />
|
||||
<span class="input-icon">
|
||||
<i class="ph ph-credit-card"></i>
|
||||
</span>
|
||||
</swp-form-input>
|
||||
</swp-form-group>
|
||||
|
||||
<swp-form-row>
|
||||
<swp-form-group>
|
||||
<swp-form-label>Udløbsdato</swp-form-label>
|
||||
<swp-form-input>
|
||||
<input type="text"
|
||||
id="expiry"
|
||||
placeholder="MM/ÅÅ"
|
||||
maxlength="5"
|
||||
autocomplete="cc-exp" />
|
||||
</swp-form-input>
|
||||
</swp-form-group>
|
||||
|
||||
<swp-form-group>
|
||||
<swp-form-label>CVV</swp-form-label>
|
||||
<swp-form-input>
|
||||
<input type="text"
|
||||
id="cvv"
|
||||
placeholder="123"
|
||||
maxlength="4"
|
||||
autocomplete="cc-csc" />
|
||||
</swp-form-input>
|
||||
</swp-form-group>
|
||||
</swp-form-row>
|
||||
|
||||
<swp-form-group>
|
||||
<swp-form-label>Navn på kort</swp-form-label>
|
||||
<swp-form-input>
|
||||
<input type="text"
|
||||
id="cardName"
|
||||
placeholder="Som det står på kortet"
|
||||
autocomplete="cc-name" />
|
||||
</swp-form-input>
|
||||
</swp-form-group>
|
||||
|
||||
<swp-payment-secure>
|
||||
<i class="ph ph-lock"></i>
|
||||
<span>Sikker betaling med SSL-kryptering</span>
|
||||
</swp-payment-secure>
|
||||
|
||||
<swp-btn class="primary full-width lg" id="submitPayment">
|
||||
<span>Start gratis prøveperiode</span>
|
||||
<i class="ph ph-arrow-right"></i>
|
||||
</swp-btn>
|
||||
</swp-auth-form>
|
||||
|
||||
<!-- Processing State -->
|
||||
<swp-payment-processing id="processingState" style="display: none;">
|
||||
<swp-spinner></swp-spinner>
|
||||
<swp-processing-text>Behandler betaling...</swp-processing-text>
|
||||
</swp-payment-processing>
|
||||
|
||||
<!-- Success State -->
|
||||
<swp-payment-success id="successState" style="display: none;">
|
||||
<swp-success-icon>
|
||||
<i class="ph ph-check-circle"></i>
|
||||
</swp-success-icon>
|
||||
<swp-success-title>Betaling godkendt!</swp-success-title>
|
||||
<swp-success-text>Omdirigerer til oprettelse af konto...</swp-success-text>
|
||||
</swp-payment-success>
|
||||
|
||||
<swp-auth-footer>
|
||||
<swp-auth-footer-text>
|
||||
Ved at fortsætte accepterer du vores <a href="/terms">vilkår</a>
|
||||
</swp-auth-footer-text>
|
||||
</swp-auth-footer>
|
||||
</swp-auth-form-container>
|
||||
</swp-auth-form-panel>
|
||||
</swp-auth-layout>
|
||||
|
||||
@section Scripts {
|
||||
<script>
|
||||
// Format card number with spaces
|
||||
const cardNumber = document.getElementById('cardNumber');
|
||||
cardNumber.addEventListener('input', function(e) {
|
||||
let value = e.target.value.replace(/\s/g, '').replace(/\D/g, '');
|
||||
let formatted = value.match(/.{1,4}/g)?.join(' ') || '';
|
||||
e.target.value = formatted;
|
||||
});
|
||||
|
||||
// Format expiry date
|
||||
const expiry = document.getElementById('expiry');
|
||||
expiry.addEventListener('input', function(e) {
|
||||
let value = e.target.value.replace(/\D/g, '');
|
||||
if (value.length >= 2) {
|
||||
value = value.substring(0, 2) + '/' + value.substring(2, 4);
|
||||
}
|
||||
e.target.value = value;
|
||||
});
|
||||
|
||||
// CVV - numbers only
|
||||
const cvv = document.getElementById('cvv');
|
||||
cvv.addEventListener('input', function(e) {
|
||||
e.target.value = e.target.value.replace(/\D/g, '');
|
||||
});
|
||||
|
||||
// Simulate payment processing
|
||||
const submitBtn = document.getElementById('submitPayment');
|
||||
const form = document.getElementById('paymentForm');
|
||||
const processingState = document.getElementById('processingState');
|
||||
const successState = document.getElementById('successState');
|
||||
|
||||
submitBtn.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
// Simple validation
|
||||
if (!cardNumber.value || !expiry.value || !cvv.value || !document.getElementById('cardName').value) {
|
||||
alert('Udfyld venligst alle felter');
|
||||
return;
|
||||
}
|
||||
|
||||
// Show processing
|
||||
form.style.display = 'none';
|
||||
processingState.style.display = 'flex';
|
||||
|
||||
// Simulate processing delay
|
||||
setTimeout(function() {
|
||||
processingState.style.display = 'none';
|
||||
successState.style.display = 'flex';
|
||||
|
||||
// Redirect to signup after success
|
||||
setTimeout(function() {
|
||||
window.location.href = '/signup?plan=@Model.SelectedPlan.Key&payment=complete';
|
||||
}, 1500);
|
||||
}, 2000);
|
||||
});
|
||||
</script>
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using PlanTempus.Application.Features.Accounts.Models;
|
||||
|
||||
namespace PlanTempus.Application.Features.Accounts.Pages;
|
||||
|
||||
public class PaymentModel : PageModel
|
||||
{
|
||||
public PlanInfo SelectedPlan { get; private set; } = PlanCatalog.Pro;
|
||||
|
||||
public void OnGet(string plan = "pro")
|
||||
{
|
||||
SelectedPlan = PlanCatalog.GetPlan(plan);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
@page "/pricing"
|
||||
@model PlanTempus.Application.Features.Accounts.Pages.PricingModel
|
||||
@{
|
||||
ViewData["Title"] = "Vælg abonnement";
|
||||
Layout = "/Features/_Shared/Pages/_AuthLayout.cshtml";
|
||||
}
|
||||
|
||||
<swp-pricing-page>
|
||||
<swp-pricing-header>
|
||||
<swp-auth-logo>
|
||||
<i class="ph ph-calendar-check"></i>
|
||||
<span>PlanTempus</span>
|
||||
</swp-auth-logo>
|
||||
|
||||
<swp-pricing-title>Vælg dit abonnement</swp-pricing-title>
|
||||
<swp-pricing-subtitle>Start med 14 dages gratis prøveperiode. Ingen binding.</swp-pricing-subtitle>
|
||||
</swp-pricing-header>
|
||||
|
||||
<swp-pricing-grid>
|
||||
@foreach (var plan in Model.Plans)
|
||||
{
|
||||
var cardClass = plan.Key switch
|
||||
{
|
||||
"pro" => "popular",
|
||||
"enterprise" => "enterprise",
|
||||
_ => ""
|
||||
};
|
||||
|
||||
var actionUrl = plan.RequiresPayment
|
||||
? $"/payment?plan={plan.Key}"
|
||||
: $"/signup?plan={plan.Key}";
|
||||
|
||||
var buttonText = plan.Key switch
|
||||
{
|
||||
"basis" => "Kom i gang gratis",
|
||||
"enterprise" => "Kontakt salg",
|
||||
_ => $"Vælg {plan.Name}"
|
||||
};
|
||||
|
||||
var buttonClass = plan.IsContactSales ? "outline" : "primary";
|
||||
|
||||
<swp-plan-card class="@cardClass">
|
||||
<swp-plan-badge class="@plan.BadgeClass">
|
||||
<i class="ph @plan.BadgeIcon"></i>
|
||||
@plan.BadgeText
|
||||
</swp-plan-badge>
|
||||
<swp-plan-name>@plan.Name</swp-plan-name>
|
||||
<swp-plan-users>@plan.UserRange</swp-plan-users>
|
||||
<swp-plan-price>
|
||||
@if (plan.PricePerMonth.HasValue)
|
||||
{
|
||||
<swp-plan-price-amount>@plan.PriceDisplay</swp-plan-price-amount>
|
||||
<swp-plan-price-period>kr/md</swp-plan-price-period>
|
||||
}
|
||||
else
|
||||
{
|
||||
<swp-plan-price-amount class="contact">Kontakt os</swp-plan-price-amount>
|
||||
}
|
||||
</swp-plan-price>
|
||||
<swp-plan-features>
|
||||
@foreach (var feature in plan.Features)
|
||||
{
|
||||
<swp-plan-feature>
|
||||
<i class="ph ph-check-circle"></i>
|
||||
@feature
|
||||
</swp-plan-feature>
|
||||
}
|
||||
</swp-plan-features>
|
||||
<swp-plan-action>
|
||||
<a href="@actionUrl" class="swp-btn @buttonClass full-width">
|
||||
@buttonText
|
||||
</a>
|
||||
</swp-plan-action>
|
||||
</swp-plan-card>
|
||||
}
|
||||
</swp-pricing-grid>
|
||||
|
||||
<swp-pricing-footer>
|
||||
<swp-pricing-footer-text>
|
||||
Har du allerede en konto? <a href="/login">Log ind</a>
|
||||
</swp-pricing-footer-text>
|
||||
</swp-pricing-footer>
|
||||
</swp-pricing-page>
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using PlanTempus.Application.Features.Accounts.Models;
|
||||
|
||||
namespace PlanTempus.Application.Features.Accounts.Pages;
|
||||
|
||||
public class PricingModel : PageModel
|
||||
{
|
||||
public IEnumerable<PlanInfo> Plans { get; private set; } = Enumerable.Empty<PlanInfo>();
|
||||
|
||||
public void OnGet()
|
||||
{
|
||||
Plans = PlanCatalog.GetAllPlans();
|
||||
}
|
||||
}
|
||||
283
PlanTempus.Application/Features/Accounts/Pages/Signup.cshtml
Normal file
283
PlanTempus.Application/Features/Accounts/Pages/Signup.cshtml
Normal file
|
|
@ -0,0 +1,283 @@
|
|||
@page "/signup"
|
||||
@model PlanTempus.Application.Features.Accounts.Pages.SignupModel
|
||||
@{
|
||||
ViewData["Title"] = Model.SelectedPlan.IsContactSales ? "Kontakt salg" : "Opret konto";
|
||||
Layout = "/Features/_Shared/Pages/_AuthLayout.cshtml";
|
||||
|
||||
var plan = Model.SelectedPlan;
|
||||
var badgeClass = plan.IsContactSales ? plan.BadgeClass : (plan.IsFree ? plan.BadgeClass : "selected");
|
||||
var badgeIcon = plan.IsContactSales ? plan.BadgeIcon : (plan.IsFree ? plan.BadgeIcon : "ph-check");
|
||||
var badgeText = plan.IsContactSales ? plan.BadgeText : (plan.IsFree ? plan.BadgeText : "Valgt");
|
||||
}
|
||||
|
||||
<swp-auth-layout>
|
||||
<!-- Selected Plan Panel -->
|
||||
<swp-auth-plan-panel>
|
||||
<swp-auth-logo>
|
||||
<i class="ph ph-calendar-check"></i>
|
||||
<span>PlanTempus</span>
|
||||
</swp-auth-logo>
|
||||
|
||||
<swp-selected-plan-header>@(plan.IsContactSales ? "Enterprise løsning" : "Dit valgte abonnement")</swp-selected-plan-header>
|
||||
|
||||
<swp-plan-card class="selected">
|
||||
<swp-plan-badge class="@badgeClass">
|
||||
<i class="ph @badgeIcon"></i>
|
||||
@badgeText
|
||||
</swp-plan-badge>
|
||||
<swp-plan-name>@plan.Name</swp-plan-name>
|
||||
<swp-plan-users>@plan.UserRange</swp-plan-users>
|
||||
@if (plan.PricePerMonth.HasValue)
|
||||
{
|
||||
<swp-plan-price>
|
||||
<swp-plan-price-amount>@plan.PriceDisplay</swp-plan-price-amount>
|
||||
<swp-plan-price-period>kr/md</swp-plan-price-period>
|
||||
</swp-plan-price>
|
||||
}
|
||||
<swp-plan-features>
|
||||
@foreach (var feature in plan.Features)
|
||||
{
|
||||
<swp-plan-feature>
|
||||
<i class="ph ph-check-circle"></i>
|
||||
@feature
|
||||
</swp-plan-feature>
|
||||
}
|
||||
</swp-plan-features>
|
||||
</swp-plan-card>
|
||||
|
||||
<swp-change-plan-link>
|
||||
<a href="/pricing">
|
||||
<i class="ph ph-arrows-clockwise"></i>
|
||||
Skift abonnement
|
||||
</a>
|
||||
</swp-change-plan-link>
|
||||
</swp-auth-plan-panel>
|
||||
|
||||
<!-- Form Panel -->
|
||||
<swp-auth-form-panel>
|
||||
<swp-auth-form-container>
|
||||
@if (plan.IsContactSales)
|
||||
{
|
||||
<!-- Enterprise Contact Form -->
|
||||
<swp-auth-header>
|
||||
<swp-auth-title>Kontakt vores salgsteam</swp-auth-title>
|
||||
<swp-auth-description>Vi vender tilbage inden for 24 timer</swp-auth-description>
|
||||
</swp-auth-header>
|
||||
|
||||
<swp-auth-form>
|
||||
<swp-form-group>
|
||||
<swp-form-label>Virksomhedsnavn</swp-form-label>
|
||||
<swp-form-input>
|
||||
<input type="text"
|
||||
name="companyName"
|
||||
placeholder="F.eks. Salon Group ApS"
|
||||
autocomplete="organization" />
|
||||
</swp-form-input>
|
||||
</swp-form-group>
|
||||
|
||||
<swp-form-group>
|
||||
<swp-form-label>Antal ansatte</swp-form-label>
|
||||
<swp-form-input>
|
||||
<select name="employeeCount">
|
||||
<option value="">Vælg antal</option>
|
||||
<option value="8-15">8-15 ansatte</option>
|
||||
<option value="16-30">16-30 ansatte</option>
|
||||
<option value="31-50">31-50 ansatte</option>
|
||||
<option value="50+">Mere end 50 ansatte</option>
|
||||
</select>
|
||||
</swp-form-input>
|
||||
</swp-form-group>
|
||||
|
||||
<swp-form-group>
|
||||
<swp-form-label>Kontaktperson</swp-form-label>
|
||||
<swp-form-input>
|
||||
<input type="text"
|
||||
name="contactName"
|
||||
placeholder="Dit fulde navn"
|
||||
autocomplete="name" />
|
||||
</swp-form-input>
|
||||
</swp-form-group>
|
||||
|
||||
<swp-form-row>
|
||||
<swp-form-group>
|
||||
<swp-form-label>Email</swp-form-label>
|
||||
<swp-form-input>
|
||||
<input type="email"
|
||||
name="email"
|
||||
placeholder="din@email.dk"
|
||||
autocomplete="email" />
|
||||
</swp-form-input>
|
||||
</swp-form-group>
|
||||
|
||||
<swp-form-group>
|
||||
<swp-form-label>Telefon</swp-form-label>
|
||||
<swp-form-input>
|
||||
<input type="tel"
|
||||
name="phone"
|
||||
placeholder="+45 12 34 56 78"
|
||||
autocomplete="tel" />
|
||||
</swp-form-input>
|
||||
</swp-form-group>
|
||||
</swp-form-row>
|
||||
|
||||
<swp-form-group>
|
||||
<swp-form-label>Besked <span class="optional">(valgfrit)</span></swp-form-label>
|
||||
<swp-form-input>
|
||||
<textarea name="message"
|
||||
rows="3"
|
||||
placeholder="Fortæl os om jeres behov..."></textarea>
|
||||
</swp-form-input>
|
||||
</swp-form-group>
|
||||
|
||||
<swp-btn class="primary full-width lg">
|
||||
<span>Send forespørgsel</span>
|
||||
<i class="ph ph-paper-plane-tilt"></i>
|
||||
</swp-btn>
|
||||
</swp-auth-form>
|
||||
|
||||
<swp-auth-footer>
|
||||
<swp-auth-footer-text>
|
||||
Eller ring til os på <a href="tel:+4570123456">70 12 34 56</a>
|
||||
</swp-auth-footer-text>
|
||||
</swp-auth-footer>
|
||||
}
|
||||
else
|
||||
{
|
||||
<!-- Standard Signup Form -->
|
||||
<swp-auth-header>
|
||||
<swp-auth-title>Opret din konto</swp-auth-title>
|
||||
<swp-auth-description>
|
||||
@(plan.IsFree ? "Kom i gang gratis - ingen kreditkort påkrævet" : "Start din gratis 14-dages prøveperiode")
|
||||
</swp-auth-description>
|
||||
</swp-auth-header>
|
||||
|
||||
<!-- User Info (already known) -->
|
||||
<swp-user-info-card>
|
||||
<swp-user-avatar>MJ</swp-user-avatar>
|
||||
<swp-user-details>
|
||||
<swp-user-name>Maria Jensen</swp-user-name>
|
||||
<swp-user-email>maria@example.dk</swp-user-email>
|
||||
</swp-user-details>
|
||||
<swp-user-verified>
|
||||
<i class="ph ph-check-circle"></i>
|
||||
</swp-user-verified>
|
||||
</swp-user-info-card>
|
||||
|
||||
<swp-auth-form>
|
||||
<swp-form-group>
|
||||
<swp-form-label>Virksomhedsnavn</swp-form-label>
|
||||
<swp-form-input>
|
||||
<input type="text"
|
||||
name="companyName"
|
||||
placeholder="F.eks. Salon Copenhagen"
|
||||
autocomplete="organization" />
|
||||
</swp-form-input>
|
||||
</swp-form-group>
|
||||
|
||||
<swp-form-group>
|
||||
<swp-form-label>Vælg adgangskode</swp-form-label>
|
||||
<swp-form-input class="has-icon">
|
||||
<input type="password"
|
||||
name="password"
|
||||
id="password"
|
||||
placeholder="Mindst 8 tegn"
|
||||
autocomplete="new-password" />
|
||||
<span class="input-icon" id="togglePassword">
|
||||
<i class="ph ph-eye"></i>
|
||||
</span>
|
||||
</swp-form-input>
|
||||
<swp-password-strength>
|
||||
<swp-strength-bar>
|
||||
<swp-strength-fill id="strengthFill"></swp-strength-fill>
|
||||
</swp-strength-bar>
|
||||
<swp-strength-text id="strengthText"></swp-strength-text>
|
||||
</swp-password-strength>
|
||||
</swp-form-group>
|
||||
|
||||
<swp-form-checkbox>
|
||||
<input type="checkbox" name="acceptTerms" id="acceptTerms" />
|
||||
<span>
|
||||
Jeg accepterer <a href="/terms">vilkår og betingelser</a>
|
||||
samt <a href="/privacy">privatlivspolitikken</a>
|
||||
</span>
|
||||
</swp-form-checkbox>
|
||||
|
||||
<swp-btn class="primary full-width lg">
|
||||
<span>Opret konto</span>
|
||||
<i class="ph ph-arrow-right"></i>
|
||||
</swp-btn>
|
||||
</swp-auth-form>
|
||||
|
||||
<swp-auth-footer>
|
||||
<swp-auth-footer-text>
|
||||
Har du allerede en konto? <a href="/login">Log ind</a>
|
||||
</swp-auth-footer-text>
|
||||
</swp-auth-footer>
|
||||
}
|
||||
</swp-auth-form-container>
|
||||
</swp-auth-form-panel>
|
||||
</swp-auth-layout>
|
||||
|
||||
@if (!Model.SelectedPlan.IsContactSales)
|
||||
{
|
||||
@section Scripts {
|
||||
<script>
|
||||
// Toggle password visibility
|
||||
const togglePassword = document.getElementById('togglePassword');
|
||||
const passwordInput = document.getElementById('password');
|
||||
const toggleIcon = togglePassword.querySelector('i');
|
||||
|
||||
togglePassword.addEventListener('click', function() {
|
||||
const type = passwordInput.getAttribute('type') === 'password' ? 'text' : 'password';
|
||||
passwordInput.setAttribute('type', type);
|
||||
toggleIcon.classList.toggle('ph-eye');
|
||||
toggleIcon.classList.toggle('ph-eye-slash');
|
||||
});
|
||||
|
||||
// Password strength indicator
|
||||
const strengthFill = document.getElementById('strengthFill');
|
||||
const strengthText = document.getElementById('strengthText');
|
||||
|
||||
passwordInput.addEventListener('input', function() {
|
||||
const password = this.value;
|
||||
const strength = calculateStrength(password);
|
||||
|
||||
strengthFill.className = '';
|
||||
strengthText.className = '';
|
||||
|
||||
if (password.length === 0) {
|
||||
strengthText.textContent = '';
|
||||
return;
|
||||
}
|
||||
|
||||
if (strength < 2) {
|
||||
strengthFill.classList.add('weak');
|
||||
strengthText.classList.add('weak');
|
||||
strengthText.textContent = 'Svag';
|
||||
} else if (strength < 3) {
|
||||
strengthFill.classList.add('fair');
|
||||
strengthText.classList.add('fair');
|
||||
strengthText.textContent = 'Middel';
|
||||
} else if (strength < 4) {
|
||||
strengthFill.classList.add('good');
|
||||
strengthText.classList.add('good');
|
||||
strengthText.textContent = 'God';
|
||||
} else {
|
||||
strengthFill.classList.add('strong');
|
||||
strengthText.classList.add('strong');
|
||||
strengthText.textContent = 'Stærk';
|
||||
}
|
||||
});
|
||||
|
||||
function calculateStrength(password) {
|
||||
let strength = 0;
|
||||
if (password.length >= 8) strength++;
|
||||
if (password.length >= 12) strength++;
|
||||
if (/[a-z]/.test(password) && /[A-Z]/.test(password)) strength++;
|
||||
if (/\d/.test(password)) strength++;
|
||||
if (/[^a-zA-Z0-9]/.test(password)) strength++;
|
||||
return strength;
|
||||
}
|
||||
</script>
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using PlanTempus.Application.Features.Accounts.Models;
|
||||
|
||||
namespace PlanTempus.Application.Features.Accounts.Pages;
|
||||
|
||||
public class SignupModel : PageModel
|
||||
{
|
||||
public PlanInfo SelectedPlan { get; private set; } = PlanCatalog.Pro;
|
||||
|
||||
public void OnGet(string plan = "pro")
|
||||
{
|
||||
SelectedPlan = PlanCatalog.GetPlan(plan);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue