Replace literal Unicode special chars with HTML entities across all 233 views
Sweeps em dashes, en dashes, multiplication signs, ellipses, and curly quotes to their HTML entity equivalents (— – × … ‘ ’) in all .cshtml files, skipping <script> blocks. Prevents encoding corruption from AI tools and Windows encoding mismatches that caused recurring symbol bugs. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,222 +0,0 @@
|
||||
@{
|
||||
ViewData["Title"] = "Tools";
|
||||
ViewData["PageIcon"] = "bi-wrench-adjustable";
|
||||
ViewData["PageHelpTitle"] = "Tools";
|
||||
ViewData["PageHelpContent"] = "Use the wizard to import or export your data. Choose a direction, then a format, then select the data to import or download. Supports CSV for bulk operations and QuickBooks Desktop or Online formats for QB sync.";
|
||||
}
|
||||
|
||||
<div class="container-fluid">
|
||||
@Html.AntiForgeryToken()
|
||||
|
||||
@if (TempData["ErrorMessage"] != null)
|
||||
{
|
||||
<div class="alert alert-danger alert-dismissible fade show" role="alert">
|
||||
<i class="bi bi-exclamation-triangle"></i> @TempData["ErrorMessage"]
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
}
|
||||
|
||||
<!-- Data Tools -->
|
||||
<h5 class="text-muted fw-semibold mb-3"><i class="bi bi-database me-2"></i>Data Tools</h5>
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header d-flex align-items-center gap-3 py-2">
|
||||
<button id="wizardBackBtn" class="btn btn-sm btn-outline-secondary d-none" onclick="wizardBack()">
|
||||
<i class="bi bi-arrow-left me-1"></i>Back
|
||||
</button>
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<span class="badge rounded-pill bg-primary" id="bc-1-badge">1</span>
|
||||
<span class="small fw-semibold" id="bc-1-label">Direction</span>
|
||||
<i class="bi bi-chevron-right text-muted small"></i>
|
||||
<span class="badge rounded-pill bg-secondary" id="bc-2-badge">2</span>
|
||||
<span class="small text-muted" id="bc-2-label">Format</span>
|
||||
<i class="bi bi-chevron-right text-muted small"></i>
|
||||
<span class="badge rounded-pill bg-secondary" id="bc-3-badge">3</span>
|
||||
<span class="small text-muted" id="bc-3-label">Select</span>
|
||||
<i class="bi bi-chevron-right text-muted small"></i>
|
||||
<span class="badge rounded-pill bg-secondary" id="bc-4-badge">4</span>
|
||||
<span class="small text-muted" id="bc-4-label">Import</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body p-4">
|
||||
|
||||
<!-- ═══ STEP 1: Direction ═══ -->
|
||||
<div id="wizard-step-1">
|
||||
<h5 class="text-center text-muted mb-4">What would you like to do?</h5>
|
||||
<div class="row g-4 justify-content-center">
|
||||
<div class="col-sm-5">
|
||||
<div class="card border-2 border-primary h-100" role="button" onclick="wizardSetDirection('import')"
|
||||
style="cursor:pointer; transition: transform .1s" onmouseover="this.style.transform='scale(1.02)'" onmouseout="this.style.transform=''">
|
||||
<div class="card-body text-center py-5">
|
||||
<i class="bi bi-upload text-primary" style="font-size:3rem"></i>
|
||||
<h4 class="mt-3">Import</h4>
|
||||
<p class="text-muted mb-0">Bring data into the system from a file</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-5">
|
||||
<div class="card border-2 border-success h-100" role="button" onclick="wizardSetDirection('export')"
|
||||
style="cursor:pointer; transition: transform .1s" onmouseover="this.style.transform='scale(1.02)'" onmouseout="this.style.transform=''">
|
||||
<div class="card-body text-center py-5">
|
||||
<i class="bi bi-download text-success" style="font-size:3rem"></i>
|
||||
<h4 class="mt-3">Export</h4>
|
||||
<p class="text-muted mb-0">Download your data to a file</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ═══ STEP 2: Format ═══ -->
|
||||
<div id="wizard-step-2" class="d-none">
|
||||
<h5 class="text-center text-muted mb-4" id="step2-heading">Select a format:</h5>
|
||||
<div class="row g-4 justify-content-center">
|
||||
<div class="col-sm-4">
|
||||
<div class="card border-2 h-100" role="button" onclick="wizardSetFormat('csv')"
|
||||
style="cursor:pointer; transition: transform .1s" onmouseover="this.style.transform='scale(1.02)'" onmouseout="this.style.transform=''">
|
||||
<div class="card-body text-center py-4">
|
||||
<i class="bi bi-file-earmark-spreadsheet text-secondary" style="font-size:2.5rem"></i>
|
||||
<h5 class="mt-3">CSV</h5>
|
||||
<p class="text-muted small mb-1">Spreadsheet-compatible</p>
|
||||
<span class="badge bg-secondary">.csv</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<div class="card border-2 h-100" role="button" onclick="wizardSetFormat('qb-desktop')"
|
||||
style="cursor:pointer; transition: transform .1s" onmouseover="this.style.transform='scale(1.02)'" onmouseout="this.style.transform=''">
|
||||
<div class="card-body text-center py-4">
|
||||
<i class="bi bi-pc-display text-dark" style="font-size:2.5rem"></i>
|
||||
<h5 class="mt-3">QuickBooks Desktop</h5>
|
||||
<p class="text-muted small mb-1">IIF interchange format</p>
|
||||
<span class="badge bg-dark">.iif</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<div class="card border-2 h-100" role="button" onclick="wizardSetFormat('qb-online')"
|
||||
style="cursor:pointer; transition: transform .1s" onmouseover="this.style.transform='scale(1.02)'" onmouseout="this.style.transform=''">
|
||||
<div class="card-body text-center py-4">
|
||||
<i class="bi bi-cloud text-info" style="font-size:2.5rem"></i>
|
||||
<h5 class="mt-3">QuickBooks Online</h5>
|
||||
<p class="text-muted small mb-1">Excel / CSV format</p>
|
||||
<span class="badge bg-info text-dark">.xlsx / .csv</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Account data for JS (catalog/inventory dropdowns) -->
|
||||
@{
|
||||
var jsonOpts = new System.Text.Json.JsonSerializerOptions { PropertyNamingPolicy = System.Text.Json.JsonNamingPolicy.CamelCase };
|
||||
IEnumerable<Microsoft.AspNetCore.Mvc.Rendering.SelectListItem> revAccts = ViewBag.RevenueAccounts;
|
||||
IEnumerable<Microsoft.AspNetCore.Mvc.Rendering.SelectListItem> cogsAccts = ViewBag.CogsAccounts;
|
||||
IEnumerable<Microsoft.AspNetCore.Mvc.Rendering.SelectListItem> invAccts = ViewBag.InventoryAccounts;
|
||||
}
|
||||
<script id="toolsAccountData" type="application/json">
|
||||
{
|
||||
"revenueAccounts": @Html.Raw(System.Text.Json.JsonSerializer.Serialize(revAccts.Select(x => new { value = x.Value, text = x.Text }), jsonOpts)),
|
||||
"cogsAccounts": @Html.Raw(System.Text.Json.JsonSerializer.Serialize(cogsAccts.Select(x => new { value = x.Value, text = x.Text }), jsonOpts)),
|
||||
"inventoryAccounts":@Html.Raw(System.Text.Json.JsonSerializer.Serialize(invAccts.Select(x => new { value = x.Value, text = x.Text }), jsonOpts))
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- ═══ STEP 3: Select what to import/export ═══ -->
|
||||
<div id="wizard-step-3" class="d-none">
|
||||
<h5 class="text-center text-muted mb-4" id="step3-heading">What would you like to import?</h5>
|
||||
<div id="step3-grid" class="row g-3 justify-content-center"></div>
|
||||
</div>
|
||||
|
||||
<!-- ═══ STEP 4: Upload / Download ═══ -->
|
||||
<div id="wizard-step-4" class="d-none">
|
||||
<div id="step4-content"></div>
|
||||
</div>
|
||||
|
||||
<!-- (old panels removed — content is now JS-rendered in step3-grid / step4-content) -->
|
||||
</div><!-- end card-body -->
|
||||
</div><!-- end wizard card -->
|
||||
</div><!-- end container-fluid -->
|
||||
|
||||
|
||||
<!-- Randomizer Wheel Modal (Easter Egg!) -->
|
||||
<div class="modal fade" id="randomizerModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-gradient" style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);">
|
||||
<h5 class="modal-title text-white">
|
||||
<i class="bi bi-shuffle me-2"></i>Decision Maker Wheel
|
||||
</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body text-center">
|
||||
<div class="mb-3">
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="btn btn-sm btn-outline-primary active" onclick="setWheelPreset('decisions')">
|
||||
<i class="bi bi-question-circle me-1"></i>Decisions
|
||||
</button>
|
||||
<button type="button" class="btn btn-sm btn-outline-primary" onclick="setWheelPreset('lunch')">
|
||||
<i class="bi bi-egg-fried me-1"></i>Lunch
|
||||
</button>
|
||||
<button type="button" class="btn btn-sm btn-outline-primary" onclick="setWheelPreset('tasks')">
|
||||
<i class="bi bi-list-check me-1"></i>Tasks
|
||||
</button>
|
||||
<button type="button" class="btn btn-sm btn-outline-primary" onclick="setWheelPreset('colors')">
|
||||
<i class="bi bi-palette me-1"></i>Colors
|
||||
</button>
|
||||
<button type="button" class="btn btn-sm btn-outline-success" onclick="loadShopWorkers()">
|
||||
<i class="bi bi-person-badge me-1"></i>Shop Workers
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="position-relative d-inline-block">
|
||||
<!-- Pointer Arrow -->
|
||||
<div style="position: absolute; top: -15px; left: 50%; transform: translateX(-50%); z-index: 10;">
|
||||
<i class="bi bi-caret-down-fill text-danger" style="font-size: 2rem; filter: drop-shadow(0 2px 4px rgba(0,0,0,0.3));"></i>
|
||||
</div>
|
||||
<canvas id="wheelCanvas" width="500" height="500" style="max-width: 100%; border-radius: 50%; box-shadow: 0 8px 16px rgba(0,0,0,0.2);"></canvas>
|
||||
</div>
|
||||
|
||||
<div class="mt-4">
|
||||
<button id="spinBtn" class="btn btn-lg btn-primary" onclick="spinWheel()">
|
||||
<i class="bi bi-arrow-clockwise me-2"></i>Spin the Wheel!
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div id="result" class="mt-3" style="min-height: 60px;"></div>
|
||||
|
||||
<div class="mt-4">
|
||||
<button class="btn btn-sm btn-outline-secondary" type="button" data-bs-toggle="collapse" data-bs-target="#customOptions">
|
||||
<i class="bi bi-gear me-1"></i>Custom Options
|
||||
</button>
|
||||
<div class="collapse mt-3" id="customOptions">
|
||||
<div class="card card-body">
|
||||
<label class="form-label small">Enter custom options (one per line):</label>
|
||||
<textarea id="customOptionsInput" class="form-control form-control-sm" rows="4" placeholder="Option 1 Option 2 Option 3 ..."></textarea>
|
||||
<button class="btn btn-sm btn-primary mt-2" onclick="setCustomOptions()">
|
||||
<i class="bi bi-check-circle me-1"></i>Apply Custom Options
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<small class="text-muted me-auto">
|
||||
<i class="bi bi-lightbulb me-1"></i>Easter egg unlocked! 🎉
|
||||
</small>
|
||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@section Scripts {
|
||||
<script src="~/js/tools-import.js" asp-append-version="true"></script>
|
||||
<script src="~/js/randomizer-wheel.js" asp-append-version="true"></script>
|
||||
<script>
|
||||
// ── Easter egg (click the navbar page title) ─────────────────────────
|
||||
document.querySelector('.page-title')?.addEventListener('click', function () {
|
||||
new bootstrap.Modal(document.getElementById('randomizerModal')).show();
|
||||
});
|
||||
</script>
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user