Initial commit
This commit is contained in:
@@ -0,0 +1,532 @@
|
||||
@model PowderCoating.Application.DTOs.Registration.RegisterCompanyDto
|
||||
@using PowderCoating.Core.Entities
|
||||
|
||||
@{
|
||||
var trialsEnabled = (bool)(ViewBag.TrialsEnabled ?? true);
|
||||
var trialDays = (int)(ViewBag.TrialPeriodDays ?? 7);
|
||||
ViewData["Title"] = trialsEnabled ? $"Start {trialDays}-Day Free Trial" : "Create Your Account";
|
||||
Layout = "/Views/Shared/_AuthLayout.cshtml";
|
||||
var planConfigs = ViewBag.PlanConfigs as List<SubscriptionPlanConfig> ?? new List<SubscriptionPlanConfig>();
|
||||
}
|
||||
|
||||
@section Styles {
|
||||
<style>
|
||||
body { background: #f1f5f9; }
|
||||
|
||||
.reg-header {
|
||||
background: linear-gradient(135deg, #1a1a2e, #16213e, #0f3460);
|
||||
color: white;
|
||||
padding: 1.25rem 2rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.reg-header .brand {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.6rem;
|
||||
font-size: 1.15rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.reg-header .brand i {
|
||||
color: #4fc3f7;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.reg-header .signin-link {
|
||||
color: rgba(255,255,255,0.8);
|
||||
font-size: 0.9rem;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.reg-header .signin-link:hover {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.reg-body {
|
||||
max-width: 900px;
|
||||
margin: 2.5rem auto;
|
||||
padding: 0 1rem 3rem;
|
||||
}
|
||||
|
||||
.section-heading {
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
color: #1e293b;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
/* Billing toggle */
|
||||
.billing-toggle {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
background: #e2e8f0;
|
||||
border-radius: 2rem;
|
||||
padding: 0.25rem;
|
||||
gap: 0.25rem;
|
||||
margin-bottom: 1.25rem;
|
||||
}
|
||||
|
||||
.billing-toggle button {
|
||||
border: none;
|
||||
background: transparent;
|
||||
border-radius: 2rem;
|
||||
padding: 0.375rem 1rem;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
color: #64748b;
|
||||
cursor: pointer;
|
||||
transition: background 0.15s, color 0.15s;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.billing-toggle button.active {
|
||||
background: white;
|
||||
color: #1e293b;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.12);
|
||||
}
|
||||
|
||||
.annual-savings-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.3rem;
|
||||
background: #dcfce7;
|
||||
color: #16a34a;
|
||||
font-size: 0.72rem;
|
||||
font-weight: 700;
|
||||
padding: 0.2rem 0.55rem;
|
||||
border-radius: 2rem;
|
||||
border: 1px solid #bbf7d0;
|
||||
margin-left: 0.4rem;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* Plan Cards */
|
||||
.plan-cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 1rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
@@media (max-width: 860px) {
|
||||
.plan-cards { grid-template-columns: repeat(2, 1fr); }
|
||||
}
|
||||
|
||||
@@media (max-width: 500px) {
|
||||
.plan-cards { grid-template-columns: 1fr; }
|
||||
}
|
||||
|
||||
.plan-card {
|
||||
background: white;
|
||||
border: 2px solid #e2e8f0;
|
||||
border-radius: 0.875rem;
|
||||
padding: 1.5rem;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
transition: border-color 0.15s, box-shadow 0.15s;
|
||||
}
|
||||
|
||||
.plan-card:hover {
|
||||
border-color: #a5b4fc;
|
||||
box-shadow: 0 4px 12px rgba(79,70,229,0.1);
|
||||
}
|
||||
|
||||
.plan-card.selected {
|
||||
border-color: #4f46e5;
|
||||
box-shadow: 0 4px 16px rgba(79,70,229,0.18);
|
||||
}
|
||||
|
||||
.plan-card .check-badge {
|
||||
position: absolute;
|
||||
top: 0.875rem;
|
||||
right: 0.875rem;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 50%;
|
||||
background: #4f46e5;
|
||||
color: white;
|
||||
display: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.plan-card.selected .check-badge {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.plan-card input[type="radio"] {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.plan-name {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 700;
|
||||
color: #1e293b;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.plan-price {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
color: #4f46e5;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.plan-price .period {
|
||||
font-size: 0.85rem;
|
||||
font-weight: 400;
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
.plan-limits {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.plan-limits li {
|
||||
font-size: 0.8rem;
|
||||
color: #475569;
|
||||
padding: 0.2rem 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.plan-limits li i {
|
||||
color: #4f46e5;
|
||||
font-size: 0.7rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* Form sections */
|
||||
.form-section {
|
||||
background: white;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 0.875rem;
|
||||
padding: 1.75rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.form-section .section-label {
|
||||
font-size: 0.95rem;
|
||||
font-weight: 700;
|
||||
color: #1e293b;
|
||||
margin-bottom: 1.25rem;
|
||||
padding-bottom: 0.75rem;
|
||||
border-bottom: 1px solid #f1f5f9;
|
||||
}
|
||||
|
||||
.submit-section {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.submit-section .terms {
|
||||
font-size: 0.8rem;
|
||||
color: #94a3b8;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.btn-submit {
|
||||
background: #4f46e5;
|
||||
border: none;
|
||||
color: white;
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
padding: 0.875rem 2rem;
|
||||
border-radius: 0.625rem;
|
||||
width: 100%;
|
||||
cursor: pointer;
|
||||
transition: background 0.15s;
|
||||
}
|
||||
|
||||
.btn-submit:hover {
|
||||
background: #4338ca;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.trial-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
background: #ecfdf5;
|
||||
color: #059669;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 600;
|
||||
padding: 0.375rem 0.75rem;
|
||||
border-radius: 2rem;
|
||||
margin-bottom: 2.5rem;
|
||||
border: 1px solid #a7f3d0;
|
||||
}
|
||||
</style>
|
||||
}
|
||||
|
||||
<div class="reg-header">
|
||||
<div class="brand">
|
||||
<img src="/images/pcl-logo.png" alt="Powder Coating Logix" style="height:40px; vertical-align:middle; margin-right:0.5rem;" />
|
||||
Powder Coating Logix
|
||||
</div>
|
||||
<a asp-area="Identity" asp-page="/Account/Login" class="signin-link">
|
||||
Already have an account? Sign in →
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="reg-body">
|
||||
<div class="text-center mb-4">
|
||||
<h2 class="fw-bold mb-2" style="color:#1e293b;">Create your account</h2>
|
||||
@if (trialsEnabled)
|
||||
{
|
||||
<span class="trial-badge">
|
||||
<i class="bi bi-check-circle-fill"></i>
|
||||
@trialDays-day free trial — no credit card required
|
||||
</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="trial-badge" style="background:#eff6ff;color:#1d4ed8;border-color:#bfdbfe;">
|
||||
<i class="bi bi-credit-card-fill"></i>
|
||||
Credit card required at signup
|
||||
</span>
|
||||
}
|
||||
</div>
|
||||
|
||||
@if (TempData["Error"] != null)
|
||||
{
|
||||
<div class="alert alert-permanent alert-danger d-flex gap-2 mb-3" role="alert">
|
||||
<i class="bi bi-exclamation-triangle-fill flex-shrink-0 mt-1"></i>
|
||||
<div>@TempData["Error"]</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (!ViewData.ModelState.IsValid && ViewData.ModelState.ErrorCount > 0)
|
||||
{
|
||||
<div class="alert alert-danger mb-3">
|
||||
<i class="bi bi-exclamation-triangle-fill me-2"></i>
|
||||
<strong>Please fix the errors below:</strong>
|
||||
<div asp-validation-summary="All" class="mt-1 mb-0"></div>
|
||||
</div>
|
||||
}
|
||||
|
||||
|
||||
<form asp-action="Create" asp-controller="Registration" method="post" id="registrationForm">
|
||||
@Html.AntiForgeryToken()
|
||||
|
||||
<!-- SECTION 1: Choose Your Plan -->
|
||||
<p class="section-heading">Choose Your Plan</p>
|
||||
<input type="hidden" name="Plan" id="selectedPlan" value="@Model.Plan" />
|
||||
<input type="hidden" name="IsAnnual" id="isAnnualField" value="false" />
|
||||
|
||||
@if (planConfigs.Any())
|
||||
{
|
||||
<div class="text-center">
|
||||
<div class="billing-toggle">
|
||||
<button type="button" id="btnMonthly" class="active" onclick="setBilling('monthly')">Monthly</button>
|
||||
<button type="button" id="btnAnnual" onclick="setBilling('annual')">
|
||||
Annual
|
||||
<span class="annual-savings-badge"><i class="bi bi-tag-fill"></i>2 months free</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="plan-cards" id="planCards">
|
||||
@if (planConfigs.Any())
|
||||
{
|
||||
foreach (var plan in planConfigs)
|
||||
{
|
||||
var isSelected = plan.Plan == Model.Plan;
|
||||
var monthlyPrice = plan.MonthlyPrice;
|
||||
var annualMonthly = plan.AnnualPrice > 0 ? plan.AnnualPrice / 12m : (decimal?)null;
|
||||
<div class="plan-card @(isSelected ? "selected" : "")" onclick="selectPlan(this, '@plan.Plan')">
|
||||
<div class="check-badge"><i class="bi bi-check"></i></div>
|
||||
<div class="plan-name">@plan.DisplayName</div>
|
||||
<div class="plan-price" id="price-@plan.Plan">
|
||||
<span class="price-monthly">$@monthlyPrice.ToString("0.##")<span class="period">/mo</span></span>
|
||||
@if (annualMonthly.HasValue)
|
||||
{
|
||||
<span class="price-annual" style="display:none;">$@annualMonthly.Value.ToString("0.##")<span class="period">/mo</span></span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="price-annual" style="display:none;">$@monthlyPrice.ToString("0.##")<span class="period">/mo</span></span>
|
||||
}
|
||||
</div>
|
||||
@if (annualMonthly.HasValue)
|
||||
{
|
||||
<div class="annual-billed-note" style="display:none; font-size:0.75rem; color:#94a3b8; margin-bottom:0.5rem;">
|
||||
$@plan.AnnualPrice.ToString("0.##") billed annually
|
||||
</div>
|
||||
}
|
||||
<ul class="plan-limits">
|
||||
<li>
|
||||
<i class="bi bi-check2"></i>
|
||||
@(plan.MaxUsers == -1 ? "Unlimited" : plan.MaxUsers.ToString()) user@(plan.MaxUsers != 1 ? "s" : "")
|
||||
</li>
|
||||
<li>
|
||||
<i class="bi bi-check2"></i>
|
||||
@(plan.MaxActiveJobs == -1 ? "Unlimited" : plan.MaxActiveJobs.ToString()) active job@(plan.MaxActiveJobs != 1 ? "s" : "")
|
||||
</li>
|
||||
<li>
|
||||
<i class="bi bi-check2"></i>
|
||||
@(plan.MaxCustomers == -1 ? "Unlimited" : plan.MaxCustomers.ToString()) customer@(plan.MaxCustomers != 1 ? "s" : "")
|
||||
</li>
|
||||
<li>
|
||||
<i class="bi bi-check2"></i>
|
||||
@(plan.MaxQuotes == -1 ? "Unlimited" : plan.MaxQuotes.ToString()) quote@(plan.MaxQuotes != 1 ? "s" : "")/mo
|
||||
</li>
|
||||
<li>
|
||||
<i class="bi bi-check2"></i>
|
||||
@(plan.MaxCatalogItems == -1 ? "Unlimited" : plan.MaxCatalogItems.ToString()) catalog items
|
||||
</li>
|
||||
<li>
|
||||
<i class="bi bi-check2"></i>
|
||||
@(plan.MaxJobPhotos == -1 ? "Unlimited" : plan.MaxJobPhotos == 0 ? "No" : plan.MaxJobPhotos.ToString()) photo@(plan.MaxJobPhotos != 1 ? "s" : "")/job
|
||||
</li>
|
||||
<li>
|
||||
<i class="bi bi-check2"></i>
|
||||
@(plan.MaxQuotePhotos == -1 ? "Unlimited" : plan.MaxQuotePhotos == 0 ? "No" : plan.MaxQuotePhotos.ToString()) photo@(plan.MaxQuotePhotos != 1 ? "s" : "")/quote
|
||||
</li>
|
||||
@if (plan.MaxAiPhotoQuotesPerMonth != 0)
|
||||
{
|
||||
<li>
|
||||
<i class="bi bi-check2"></i>
|
||||
@(plan.MaxAiPhotoQuotesPerMonth == -1 ? "Unlimited" : plan.MaxAiPhotoQuotesPerMonth.ToString()) AI quotes/mo
|
||||
</li>
|
||||
}
|
||||
@if (plan.AllowOnlinePayments)
|
||||
{
|
||||
<li>
|
||||
<i class="bi bi-check2"></i>
|
||||
Online payments
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="alert alert-warning mt-2" role="alert">
|
||||
<i class="bi bi-exclamation-triangle-fill me-2"></i>
|
||||
No subscription plans are currently available. Please contact a system administrator.
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<!-- SECTION 2: Company Details -->
|
||||
<div class="form-section">
|
||||
<div class="section-label"><i class="bi bi-building me-2 text-primary"></i>Company Details</div>
|
||||
<div class="row g-3">
|
||||
<div class="col-md-8">
|
||||
<label asp-for="CompanyName" class="form-label fw-medium">Company Name <span class="text-danger">*</span></label>
|
||||
<input asp-for="CompanyName" class="form-control" placeholder="Acme Powder Coating" />
|
||||
<span asp-validation-for="CompanyName" class="text-danger small"></span>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label asp-for="CompanyPhone" class="form-label fw-medium">Phone <span class="text-muted fw-normal">(optional)</span></label>
|
||||
<input asp-for="CompanyPhone" class="form-control" placeholder="(555) 000-0000" />
|
||||
<span asp-validation-for="CompanyPhone" class="text-danger small"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- SECTION 3: Your Account -->
|
||||
<div class="form-section">
|
||||
<div class="section-label"><i class="bi bi-person me-2 text-primary"></i>Your Account</div>
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<label asp-for="FirstName" class="form-label fw-medium">First Name <span class="text-danger">*</span></label>
|
||||
<input asp-for="FirstName" class="form-control" placeholder="Jane" />
|
||||
<span asp-validation-for="FirstName" class="text-danger small"></span>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label asp-for="LastName" class="form-label fw-medium">Last Name <span class="text-danger">*</span></label>
|
||||
<input asp-for="LastName" class="form-control" placeholder="Smith" />
|
||||
<span asp-validation-for="LastName" class="text-danger small"></span>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<label asp-for="Email" class="form-label fw-medium">Email <span class="text-danger">*</span></label>
|
||||
<input asp-for="Email" class="form-control" placeholder="jane@acmecoating.com" type="email" />
|
||||
<span asp-validation-for="Email" class="text-danger small"></span>
|
||||
<div class="form-text">
|
||||
<i class="bi bi-envelope-check me-1 text-success"></i>
|
||||
A temporary password will be emailed to this address. You'll set a permanent password on your first login.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Submit -->
|
||||
@if (planConfigs.Any())
|
||||
{
|
||||
<div class="submit-section">
|
||||
<p class="terms">By creating an account you agree to our <a asp-controller="Home" asp-action="TermsOfService" target="_blank">Terms of Service</a> and <a asp-controller="Home" asp-action="Privacy" target="_blank">Privacy Policy</a>.</p>
|
||||
@if (trialsEnabled)
|
||||
{
|
||||
<button type="submit" id="submitBtn" class="btn btn-submit">
|
||||
<i class="bi bi-rocket-takeoff me-2" id="submitIcon"></i>
|
||||
<span id="submitText">Create Account & Start @trialDays-Day Trial</span>
|
||||
</button>
|
||||
}
|
||||
else
|
||||
{
|
||||
<button type="submit" id="submitBtn" class="btn btn-submit">
|
||||
<i class="bi bi-lock me-2" id="submitIcon"></i>
|
||||
<span id="submitText">Continue to Payment →</span>
|
||||
</button>
|
||||
<p class="text-muted small mt-2 mb-0">
|
||||
<i class="bi bi-shield-check me-1"></i>
|
||||
Secure payment powered by Stripe. You'll be charged after reviewing your plan.
|
||||
</p>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@section Scripts {
|
||||
<partial name="_ValidationScriptsPartial" />
|
||||
<script>
|
||||
function selectPlan(card, planValue) {
|
||||
document.querySelectorAll('.plan-card').forEach(c => c.classList.remove('selected'));
|
||||
card.classList.add('selected');
|
||||
document.getElementById('selectedPlan').value = planValue;
|
||||
}
|
||||
|
||||
function setBilling(period) {
|
||||
var isAnnual = period === 'annual';
|
||||
document.getElementById('isAnnualField').value = isAnnual ? 'true' : 'false';
|
||||
|
||||
document.getElementById('btnMonthly').classList.toggle('active', !isAnnual);
|
||||
document.getElementById('btnAnnual').classList.toggle('active', isAnnual);
|
||||
|
||||
document.querySelectorAll('.price-monthly').forEach(el => el.style.display = isAnnual ? 'none' : '');
|
||||
document.querySelectorAll('.price-annual').forEach(el => el.style.display = isAnnual ? '' : 'none');
|
||||
document.querySelectorAll('.annual-billed-note').forEach(el => el.style.display = isAnnual ? '' : 'none');
|
||||
}
|
||||
|
||||
// Prevent double-submit: disable button after first valid submission
|
||||
var submittingText = '@Html.Raw(trialsEnabled ? "Creating your account\u2026" : "Redirecting to payment\u2026")';
|
||||
document.getElementById('registrationForm').addEventListener('submit', function (e) {
|
||||
var btn = document.getElementById('submitBtn');
|
||||
var icon = document.getElementById('submitIcon');
|
||||
var text = document.getElementById('submitText');
|
||||
|
||||
// Only disable if client-side validation passes
|
||||
if ($(this).valid && !$(this).valid()) return;
|
||||
|
||||
btn.disabled = true;
|
||||
icon.className = 'spinner-border spinner-border-sm me-2';
|
||||
text.textContent = submittingText;
|
||||
});
|
||||
</script>
|
||||
}
|
||||
@@ -0,0 +1,341 @@
|
||||
@{
|
||||
ViewData["Title"] = "Welcome to Powder Coating Logix";
|
||||
var firstName = (ViewBag.FirstName as string) ?? "there";
|
||||
var isOnTrial = (bool)(ViewBag.IsOnTrial ?? false);
|
||||
var trialEndDate = ViewBag.TrialEndDate as DateTime?;
|
||||
var trialEnd = trialEndDate?.ToString("MMMM d, yyyy") ?? DateTime.UtcNow.AddDays(7).ToString("MMMM d, yyyy");
|
||||
}
|
||||
|
||||
@section Styles {
|
||||
<style>
|
||||
.welcome-hero {
|
||||
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
|
||||
border-radius: 1rem;
|
||||
color: white;
|
||||
padding: 2.5rem 2rem;
|
||||
margin-bottom: 2rem;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.welcome-hero::after {
|
||||
content: '\f1e3';
|
||||
font-family: 'bootstrap-icons';
|
||||
position: absolute;
|
||||
right: -1rem;
|
||||
top: -1rem;
|
||||
font-size: 10rem;
|
||||
color: rgba(255,255,255,0.04);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.welcome-hero h1 {
|
||||
font-size: 1.75rem;
|
||||
font-weight: 700;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.welcome-hero .subtitle {
|
||||
color: rgba(255,255,255,0.7);
|
||||
font-size: 1rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.trial-pill {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
background: rgba(79, 195, 247, 0.15);
|
||||
border: 1px solid rgba(79, 195, 247, 0.4);
|
||||
color: #4fc3f7;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 500;
|
||||
padding: 0.375rem 0.875rem;
|
||||
border-radius: 2rem;
|
||||
}
|
||||
|
||||
/* Info cards */
|
||||
.info-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 1rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
@@media (max-width: 576px) {
|
||||
.info-grid { grid-template-columns: 1fr; }
|
||||
}
|
||||
|
||||
.info-tile {
|
||||
background: var(--bs-body-bg);
|
||||
border: 1px solid var(--bs-border-color);
|
||||
border-radius: 0.875rem;
|
||||
padding: 1.25rem;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 0.875rem;
|
||||
}
|
||||
|
||||
.info-tile .tile-icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 0.625rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 1.1rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.info-tile .tile-text h6 {
|
||||
font-weight: 600;
|
||||
font-size: 0.875rem;
|
||||
margin-bottom: 0.2rem;
|
||||
color: var(--bs-emphasis-color);
|
||||
}
|
||||
|
||||
.info-tile .tile-text p {
|
||||
font-size: 0.8rem;
|
||||
color: var(--bs-secondary-color);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Screenshot rotator */
|
||||
.screenshot-rotator {
|
||||
margin-bottom: 2rem;
|
||||
max-width: 50%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.rotator-label {
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.07em;
|
||||
color: var(--bs-secondary-color);
|
||||
margin-bottom: 0.875rem;
|
||||
}
|
||||
|
||||
.rotator-track {
|
||||
position: relative;
|
||||
border-radius: 0.875rem;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 4px 24px rgba(0,0,0,0.12);
|
||||
background: #0f172a;
|
||||
aspect-ratio: 16/9;
|
||||
}
|
||||
|
||||
.rotator-track img {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
opacity: 0;
|
||||
transition: opacity 0.6s ease;
|
||||
}
|
||||
|
||||
.rotator-track img.active {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.rotator-nav {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 0.75rem;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.rotator-nav button {
|
||||
pointer-events: all;
|
||||
background: rgba(0,0,0,0.45);
|
||||
border: none;
|
||||
color: white;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 50%;
|
||||
font-size: 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
transition: background 0.15s;
|
||||
backdrop-filter: blur(4px);
|
||||
}
|
||||
|
||||
.rotator-nav button:hover {
|
||||
background: rgba(0,0,0,0.7);
|
||||
}
|
||||
|
||||
.rotator-dots {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 0.4rem;
|
||||
margin-top: 0.75rem;
|
||||
}
|
||||
|
||||
.rotator-dots button {
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
border-radius: 50%;
|
||||
border: none;
|
||||
background: var(--bs-border-color);
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s, transform 0.2s;
|
||||
}
|
||||
|
||||
.rotator-dots button.active {
|
||||
background: #4f46e5;
|
||||
transform: scale(1.3);
|
||||
}
|
||||
|
||||
.rotator-caption {
|
||||
text-align: center;
|
||||
font-size: 0.8rem;
|
||||
color: var(--bs-secondary-color);
|
||||
margin-top: 0.5rem;
|
||||
min-height: 1.2em;
|
||||
}
|
||||
</style>
|
||||
}
|
||||
|
||||
<!-- Welcome Hero -->
|
||||
<div class="welcome-hero">
|
||||
<div class="mb-3">
|
||||
<i class="bi bi-check-circle-fill me-2" style="color:#4fc3f7;font-size:1.5rem;"></i>
|
||||
<span style="color:rgba(255,255,255,0.8);font-size:0.95rem;">Account created successfully</span>
|
||||
</div>
|
||||
<h1>Welcome, @firstName!</h1>
|
||||
<p class="subtitle">
|
||||
Your account is created and ready — but <strong style="color:white;">it still needs to be configured
|
||||
before it's ready to use.</strong> Run the Setup Wizard to get your shop up and running.
|
||||
We <strong style="color:#4fc3f7;">strongly recommend</strong> completing it before doing anything else.
|
||||
</p>
|
||||
<div class="d-flex flex-wrap align-items-center gap-3 mt-4">
|
||||
<form asp-controller="SetupWizard" asp-action="Launch" method="post">
|
||||
@Html.AntiForgeryToken()
|
||||
<button type="submit" class="btn btn-lg fw-semibold px-4 py-2" style="background:#4fc3f7;color:#0f3460;border:none;">
|
||||
<i class="bi bi-rocket-takeoff me-2"></i>Start Setup Wizard
|
||||
</button>
|
||||
</form>
|
||||
@if (isOnTrial)
|
||||
{
|
||||
<span class="trial-pill">
|
||||
<i class="bi bi-calendar-check"></i>
|
||||
Free trial — ends @trialEnd
|
||||
</span>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Info tiles -->
|
||||
<div class="info-grid">
|
||||
<div class="info-tile">
|
||||
<div class="tile-icon" style="background:#ecfdf5;color:#059669;">
|
||||
<i class="bi bi-list-check"></i>
|
||||
</div>
|
||||
<div class="tile-text">
|
||||
<h6>Lookups Pre-Seeded</h6>
|
||||
<p>Job statuses, priorities, quote statuses, appointment types, and inventory categories are ready to use — and fully customizable.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-tile">
|
||||
<div class="tile-icon" style="background:#eff6ff;color:#2563eb;">
|
||||
<i class="bi bi-shield-check"></i>
|
||||
</div>
|
||||
<div class="tile-text">
|
||||
<h6>You're the Admin</h6>
|
||||
<p>Your account has full admin access. You can invite team members and control their permissions from Company Settings.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Screenshot rotator -->
|
||||
<div class="screenshot-rotator">
|
||||
<p class="rotator-label"><i class="bi bi-grid-1x2 me-1"></i>A quick look around</p>
|
||||
<div class="rotator-track" id="rotatorTrack">
|
||||
<img src="/images/welcome/Dashboard.png" alt="Dashboard" class="active" data-caption="Dashboard — live KPIs, alerts, and daily tips at a glance" />
|
||||
<img src="/images/welcome/Jobs.png" alt="Jobs" data-caption="Jobs — track every job from intake through delivery across 16 statuses" />
|
||||
<img src="/images/welcome/JobBoard.png" alt="Job Board" data-caption="Job Board — drag-and-drop priority view of all active work" />
|
||||
<img src="/images/welcome/Quotes.png" alt="Quotes" data-caption="Quotes — multi-item pricing engine with AI photo quoting" />
|
||||
<img src="/images/welcome/Schedule.png" alt="Schedule" data-caption="Schedule — calendar view for appointments and job deadlines" />
|
||||
<img src="/images/welcome/ShopDisplay.png" alt="Shop Display" data-caption="Shop Display — full-screen board for the shop floor" />
|
||||
<img src="/images/welcome/SetupWizard.png" alt="Setup Wizard" data-caption="Setup Wizard — 10-step guided configuration for your shop" />
|
||||
<img src="/images/welcome/CompanySettings.png" alt="Company Settings" data-caption="Company Settings — pricing rates, branding, notifications, and more" />
|
||||
<img src="/images/welcome/DailyBoard.png" alt="Daily Board" data-caption="Daily Board — at-a-glance view of today's work" />
|
||||
<img src="/images/welcome/QBMigrationWizard.png" alt="QB Migration" data-caption="QuickBooks Migration Wizard — import your existing customers and data" />
|
||||
<img src="/images/welcome/Tools.png" alt="Tools" data-caption="Tools — equipment management and maintenance scheduling" />
|
||||
<img src="/images/welcome/Help.png" alt="Help Center" data-caption="Help Center — built-in documentation and AI assistant" />
|
||||
<div class="rotator-nav">
|
||||
<button id="rotatorPrev" aria-label="Previous"><i class="bi bi-chevron-left"></i></button>
|
||||
<button id="rotatorNext" aria-label="Next"><i class="bi bi-chevron-right"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rotator-dots" id="rotatorDots"></div>
|
||||
<p class="rotator-caption" id="rotatorCaption"></p>
|
||||
</div>
|
||||
|
||||
<!-- Footer actions -->
|
||||
<div class="d-flex align-items-center justify-content-between flex-wrap gap-3">
|
||||
<div class="text-secondary" style="font-size:0.875rem;">
|
||||
<i class="bi bi-info-circle me-1"></i>
|
||||
You can re-run the setup wizard anytime from <a asp-controller="CompanySettings" asp-action="Index">Company Settings</a>.
|
||||
</div>
|
||||
<div class="d-flex gap-2">
|
||||
<a asp-controller="Billing" asp-action="Index" class="btn btn-outline-secondary">
|
||||
<i class="bi bi-credit-card me-1"></i>Set Up Billing
|
||||
</a>
|
||||
<a asp-controller="Dashboard" asp-action="Index" class="btn btn-primary px-4">
|
||||
<i class="bi bi-house me-1"></i>Go to Dashboard
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@section Scripts {
|
||||
<script>
|
||||
(function () {
|
||||
var imgs = Array.from(document.querySelectorAll('#rotatorTrack img'));
|
||||
var dotsEl = document.getElementById('rotatorDots');
|
||||
var caption = document.getElementById('rotatorCaption');
|
||||
var current = 0;
|
||||
var timer;
|
||||
|
||||
// Build dots
|
||||
imgs.forEach(function (_, i) {
|
||||
var btn = document.createElement('button');
|
||||
btn.setAttribute('aria-label', 'Go to slide ' + (i + 1));
|
||||
btn.addEventListener('click', function () { go(i); resetTimer(); });
|
||||
dotsEl.appendChild(btn);
|
||||
});
|
||||
|
||||
function go(index) {
|
||||
imgs[current].classList.remove('active');
|
||||
dotsEl.children[current].classList.remove('active');
|
||||
current = (index + imgs.length) % imgs.length;
|
||||
imgs[current].classList.add('active');
|
||||
dotsEl.children[current].classList.add('active');
|
||||
caption.textContent = imgs[current].dataset.caption || '';
|
||||
}
|
||||
|
||||
function resetTimer() {
|
||||
clearInterval(timer);
|
||||
timer = setInterval(function () { go(current + 1); }, 3000);
|
||||
}
|
||||
|
||||
document.getElementById('rotatorPrev').addEventListener('click', function () { go(current - 1); resetTimer(); });
|
||||
document.getElementById('rotatorNext').addEventListener('click', function () { go(current + 1); resetTimer(); });
|
||||
|
||||
// Pause on hover
|
||||
document.getElementById('rotatorTrack').addEventListener('mouseenter', function () { clearInterval(timer); });
|
||||
document.getElementById('rotatorTrack').addEventListener('mouseleave', resetTimer);
|
||||
|
||||
go(0);
|
||||
resetTimer();
|
||||
})();
|
||||
</script>
|
||||
}
|
||||
Reference in New Issue
Block a user