littleshop/LittleShop/Areas/Admin/Views/VariantCollections/Edit.cshtml
SysAdmin 0dbc49ee89 fix: Critical data loss bug in variant editor - removed overly aggressive column skip logic
Problem: Variant editor was skipping ALL columns with headers starting with 'Property '
(e.g., 'Property 1'), which caused complete data loss during serialization.

When users entered data but didn't rename the default column header, serializeToJSON()
would skip the column entirely, returning an empty array [] to the database.

Fix: Only skip columns with truly empty names, not default 'Property X' names.
Users can now save data even if they haven't renamed column headers.

Files changed:
- wwwroot/js/variant-editor.js: Removed propertyName.startsWith('Property ') check
- Areas/Admin/Views/VariantCollections/Create.cshtml: Updated cache-busting to v=20251113d
- Areas/Admin/Views/VariantCollections/Edit.cshtml: Updated cache-busting to v=20251113d
2025-11-14 00:35:55 +00:00

139 lines
6.1 KiB
Plaintext

@model LittleShop.DTOs.UpdateVariantCollectionDto
@{
ViewData["Title"] = "Edit Variant Collection";
var collectionId = ViewData["CollectionId"];
}
<div class="row mb-4">
<div class="col">
<h1><i class="fas fa-edit"></i> Edit Variant Collection</h1>
</div>
<div class="col-auto">
<a href="@Url.Action("Index")" class="btn btn-secondary">
<i class="fas fa-arrow-left"></i> Back to Collections
</a>
</div>
</div>
<div class="card">
<div class="card-body">
<form method="post" action="@Url.Action("Edit", new { id = collectionId })">
@Html.AntiForgeryToken()
<div asp-validation-summary="All" class="alert alert-danger" role="alert"></div>
<div class="mb-3">
<label for="Name" class="form-label">Collection Name</label>
<input type="text" class="form-control" id="Name" name="Name" value="@Model.Name" maxlength="100" placeholder="e.g., Mens Clothes, Jewelry Sizes">
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="mb-3">
<label for="variant-spreadsheet-editor" class="form-label">
<i class="fas fa-table"></i> Properties Spreadsheet
</label>
<!-- Spreadsheet Editor Container -->
<div id="variant-spreadsheet-editor" style="height: 400px; overflow: auto;" class="border rounded"></div>
<!-- Hidden input to store JSON data -->
<input type="hidden" id="PropertiesJson" name="PropertiesJson" value='@Model.PropertiesJson' />
<div class="form-text mt-2">
<strong><i class="fas fa-info-circle"></i> How to use:</strong>
<ul class="mb-1">
<li><strong>Quick Add buttons:</strong> Click preset buttons (Size, Color, Material, Storage) to add pre-populated columns</li>
<li><strong>Custom button:</strong> Click Custom to add a column with your own name</li>
<li><strong>Double-click headers:</strong> Double-click column headers to rename them</li>
<li><strong>Right-click menu:</strong> Add/remove rows and columns, rename columns, clear values</li>
<li><strong>Keyboard shortcuts:</strong> Tab to move right, Enter to move down, Ctrl+D to delete, Ctrl+Enter to save</li>
</ul>
<small class="text-muted">Changes are automatically saved when you click "Save Changes" below.</small>
</div>
<span asp-validation-for="PropertiesJson" class="text-danger"></span>
</div>
<div class="mb-3">
<div class="form-check">
<input type="checkbox" class="form-check-input" id="IsActive" name="IsActive" value="true" @(Model.IsActive == true ? "checked" : "")>
<label class="form-check-label" for="IsActive">
Active
</label>
</div>
<div class="form-text">Inactive collections cannot be selected when editing products</div>
</div>
<div class="border-top pt-3">
<button type="submit" class="btn btn-primary">
<i class="fas fa-save"></i> Save Changes
</button>
<a href="@Url.Action("Index")" class="btn btn-secondary">Cancel</a>
</div>
</form>
</div>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
<!-- Handsontable Spreadsheet Library -->
<link rel="stylesheet" href="~/lib/handsontable/handsontable.full.min.css?v=20251113c" />
<script src="~/lib/handsontable/handsontable.full.min.js?v=20251113c"></script>
<!-- Hammer.js for Touch Gestures -->
<script src="~/lib/hammerjs/hammer.min.js?v=20251113c"></script>
<!-- Variant Editor Module -->
<script src="~/js/variant-editor.js?v=20251113d"></script>
<!-- Initialize Variant Editor -->
<script>
(function() {
// Get initial JSON data from hidden input
const propertiesJson = document.getElementById('PropertiesJson').value;
// Initialize the spreadsheet editor
const editor = new VariantEditor('variant-spreadsheet-editor', propertiesJson, {
minRows: 5,
minCols: 2,
maxCols: 8
});
// Before form submission, serialize spreadsheet data to JSON
const form = document.querySelector('form');
form.addEventListener('submit', function(e) {
try {
const jsonString = editor.serializeToJSON();
console.log('Serialized variant properties:', jsonString);
// Validation: Ensure we have valid JSON
const parsed = JSON.parse(jsonString);
if (!Array.isArray(parsed)) {
e.preventDefault();
alert('Invalid variant properties data. Please check your spreadsheet.');
return false;
}
// Check for empty property names
const emptyNames = parsed.filter(p => !p.name || p.name.trim() === '');
if (emptyNames.length > 0) {
e.preventDefault();
alert('All property columns must have names. Please click the column headers to set property types.');
return false;
}
return true;
} catch (error) {
console.error('Failed to serialize variant properties:', error);
e.preventDefault();
alert('Failed to save variant properties: ' + error.message);
return false;
}
});
// Keyboard shortcut hint for users
console.log('Variant Editor loaded. Keyboard shortcuts: Ctrl+D (delete), Ctrl+Enter (save)');
})();
</script>
}