Files
PowderCoatingLogix/src/PowderCoating.Web/Views/SetupWizard/Step8.cshtml
T
spouliot 4ec55e7290 Restore all zeroed views + add bulk gift certificate creation
The HTML entity sweep script had a bug where it wrote empty files for any
view that contained no target Unicode characters, zeroing out 215 view files.
All views restored from the pre-sweep commit (cefdf3e).

Bulk gift certificate feature:
- BulkCreateGiftCertificateDto with Quantity (1-500), Amount, Reason, Expiry, Notes
- GenerateBulkGiftCertificatePdfAsync on IPdfService / PdfService: one Letter page
  per cert, reusing the same purple/gold branded ComposeGiftCertificateContent helper
- GiftCertificatesController: BulkCreate GET/POST, BulkResult GET, BulkDownloadPdf POST
- Views: BulkCreate.cshtml (form with live total preview), BulkResult.cshtml (table +
  Download All PDF button that POSTs cert IDs to avoid URL length limits)
- gift-certificate-bulk.js: live preview + spinner/disable on submit
- Index.cshtml: Bulk Create button added alongside New Certificate

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 20:09:22 -04:00

118 lines
5.4 KiB
Plaintext

@using PowderCoating.Application.DTOs.Wizard
@model WizardPricingTiersStepDto
@{
ViewData["Title"] = "Setup Wizard — Pricing Tiers";
var progress = ViewBag.Progress as WizardProgressDto ?? new WizardProgressDto();
int step = ViewBag.Step as int? ?? 8;
}
@section Styles { @await Html.PartialAsync("_WizardStyles") }
<div class="wizard-layout">
@await Html.PartialAsync("_WizardProgress", progress)
<div class="wizard-content">
<div class="wizard-step-header">
<span class="wizard-step-badge">Step @step of @WizardProgressDto.TotalSteps</span>
<h2><i class="bi bi-percent me-2"></i>Pricing Tiers</h2>
<p class="text-secondary">Create discount tiers for your commercial customers. Once set up, you can assign a tier to any customer so their quotes automatically apply the discount.</p>
</div>
<form asp-action="PostStep8" method="post">
@Html.AntiForgeryToken()
<input type="hidden" name="TiersJson" id="tiersJson" value="@(Model.TiersJson ?? "[]")" />
<div class="wizard-card">
<h5 class="wizard-card-title">Pricing Tiers</h5>
<p class="text-secondary small mb-3">
Common examples: <em>Gold (10% off)</em>, <em>Silver (5% off)</em>, <em>Wholesale (15% off)</em>.
Customers without a tier are billed at standard rates.
</p>
<div id="tiersList"></div>
<button type="button" class="btn btn-outline-primary btn-sm mt-2" onclick="addTier()">
<i class="bi bi-plus-circle me-1"></i>Add Pricing Tier
</button>
<div class="alert alert-info alert-permanent d-flex gap-2 mt-3 mb-0" role="alert">
<i class="bi bi-info-circle flex-shrink-0 mt-1"></i>
<div class="small">
You can skip this step and configure pricing tiers later from <strong>Settings &rarr; Pricing Tiers</strong>.
</div>
</div>
</div>
@await Html.PartialAsync("_WizardFooter", step)
</form>
</div>
</div>
@section Scripts {
<script>
var tiers = JSON.parse(document.getElementById('tiersJson').value || '[]');
function renderTiers() {
var container = document.getElementById('tiersList');
if (tiers.length === 0) {
container.innerHTML = '<p class="text-secondary small py-2">No tiers added yet. You can skip this step and set up pricing tiers later from Settings &rarr; Pricing Tiers.</p>';
} else {
container.innerHTML = tiers.map(function (t, idx) {
return `<div class="wz-item-row">
<div class="row g-2 align-items-end">
<div class="col-md-4">
<label class="form-label small fw-semibold mb-1">Tier Name <span class="text-danger">*</span></label>
<input class="form-control form-control-sm" value="${escHtml(t.tierName)}" onchange="updateTier(${idx},'tierName',this.value)" placeholder="e.g. Gold, Wholesale" />
</div>
<div class="col-md-4">
<label class="form-label small fw-semibold mb-1">Description</label>
<input class="form-control form-control-sm" value="${escHtml(t.description)}" onchange="updateTier(${idx},'description',this.value)" placeholder="e.g. High-volume commercial accounts" />
</div>
<div class="col-md-2">
<label class="form-label small fw-semibold mb-1">Discount (%)</label>
<div class="input-group input-group-sm">
<input class="form-control form-control-sm" type="number" min="0" max="100" step="0.1" value="${t.discountPercent || 0}" onchange="updateTierNum(${idx},'discountPercent',this.value)" />
<span class="input-group-text">%</span>
</div>
</div>
<div class="col-md-2 text-end">
<button type="button" class="btn btn-outline-danger btn-sm" onclick="removeTier(${idx})" title="Remove">
<i class="bi bi-trash"></i>
</button>
</div>
</div>
</div>`;
}).join('');
}
document.getElementById('tiersJson').value = JSON.stringify(tiers);
}
function addTier() {
tiers.push({ tierName: '', description: '', discountPercent: 0 });
renderTiers();
var inputs = document.querySelectorAll('.wz-item-row:last-child input');
if (inputs.length) inputs[0].focus();
}
function updateTier(idx, field, value) {
tiers[idx][field] = value;
document.getElementById('tiersJson').value = JSON.stringify(tiers);
}
function updateTierNum(idx, field, value) {
tiers[idx][field] = value === '' ? 0 : parseFloat(value);
document.getElementById('tiersJson').value = JSON.stringify(tiers);
}
function removeTier(idx) {
tiers.splice(idx, 1);
renderTiers();
}
function escHtml(str) {
return (str || '').toString().replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');
}
renderTiers();
</script>
}