Navigation: - Rename Projects to Jobs in NavMenu - Add new icon for multi-material boxes Home page: - Update references from Projects to Jobs Materials pages: - Add Type and Grade columns to index - Shape-specific dimension editing with typed inputs - Error handling with detailed messages Stock pages: - Show Shape, Type, Grade, Size columns - Display QuantityOnHand with badges Shared components: - LengthInput: Add nullable binding mode for optional dimensions - LengthInput: Format on blur for better UX - CutListReport: Update for Job model references Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
141 lines
3.9 KiB
Plaintext
141 lines
3.9 KiB
Plaintext
@using CutList.Core.Formatting
|
|
|
|
<div class="length-input">
|
|
<input type="text"
|
|
class="form-control @(HasError ? "is-invalid" : "")"
|
|
value="@DisplayValue"
|
|
@oninput="OnInputChange"
|
|
@onblur="OnBlur"
|
|
placeholder="@Placeholder" />
|
|
@if (HasError)
|
|
{
|
|
<div class="invalid-feedback">@ErrorMessage</div>
|
|
}
|
|
</div>
|
|
|
|
@code {
|
|
/// <summary>
|
|
/// Non-nullable decimal value binding.
|
|
/// </summary>
|
|
[Parameter]
|
|
public decimal Value { get; set; }
|
|
|
|
[Parameter]
|
|
public EventCallback<decimal> ValueChanged { get; set; }
|
|
|
|
/// <summary>
|
|
/// Nullable decimal value binding (used for optional dimension fields).
|
|
/// Takes precedence over Value if both ValueChanged and NullableValueChanged are set.
|
|
/// </summary>
|
|
[Parameter]
|
|
public decimal? NullableValue { get; set; }
|
|
|
|
[Parameter]
|
|
public EventCallback<decimal?> NullableValueChanged { get; set; }
|
|
|
|
[Parameter]
|
|
public string Placeholder { get; set; } = "e.g., 12' 6\" or 144";
|
|
|
|
private string DisplayValue { get; set; } = string.Empty;
|
|
private bool HasError { get; set; }
|
|
private string ErrorMessage { get; set; } = string.Empty;
|
|
private decimal? _lastValue;
|
|
|
|
private bool IsNullableMode => NullableValueChanged.HasDelegate;
|
|
|
|
private decimal? CurrentValue => IsNullableMode ? NullableValue : Value;
|
|
|
|
protected override void OnParametersSet()
|
|
{
|
|
// Reset display when Value changes externally (e.g., form reset)
|
|
if (CurrentValue != _lastValue)
|
|
{
|
|
_lastValue = CurrentValue;
|
|
if (CurrentValue.HasValue && CurrentValue.Value > 0)
|
|
{
|
|
DisplayValue = ArchUnits.FormatFromInches((double)CurrentValue.Value);
|
|
}
|
|
else
|
|
{
|
|
DisplayValue = string.Empty;
|
|
HasError = false;
|
|
ErrorMessage = string.Empty;
|
|
}
|
|
}
|
|
}
|
|
|
|
private async Task OnInputChange(ChangeEventArgs e)
|
|
{
|
|
var input = e.Value?.ToString() ?? string.Empty;
|
|
DisplayValue = input;
|
|
HasError = false;
|
|
ErrorMessage = string.Empty;
|
|
|
|
if (string.IsNullOrWhiteSpace(input))
|
|
{
|
|
_lastValue = null;
|
|
if (IsNullableMode)
|
|
{
|
|
await NullableValueChanged.InvokeAsync(null);
|
|
}
|
|
else
|
|
{
|
|
await ValueChanged.InvokeAsync(0);
|
|
}
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
// Try to parse as architectural units
|
|
var inches = ArchUnits.ParseToInches(input);
|
|
_lastValue = (decimal)inches;
|
|
|
|
if (IsNullableMode)
|
|
{
|
|
await NullableValueChanged.InvokeAsync(_lastValue);
|
|
}
|
|
else
|
|
{
|
|
await ValueChanged.InvokeAsync(_lastValue.Value);
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
// Try to parse as plain decimal (inches)
|
|
if (decimal.TryParse(input, out var decimalValue))
|
|
{
|
|
_lastValue = decimalValue;
|
|
|
|
if (IsNullableMode)
|
|
{
|
|
await NullableValueChanged.InvokeAsync(decimalValue);
|
|
}
|
|
else
|
|
{
|
|
await ValueChanged.InvokeAsync(decimalValue);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
HasError = true;
|
|
ErrorMessage = "Invalid format. Use feet (12'), inches (6\"), or decimal (144)";
|
|
}
|
|
}
|
|
}
|
|
|
|
private void OnBlur()
|
|
{
|
|
// Format the display value nicely on blur if we have a valid value
|
|
if (!HasError && _lastValue.HasValue && _lastValue.Value > 0)
|
|
{
|
|
DisplayValue = ArchUnits.FormatFromInches((double)_lastValue.Value);
|
|
}
|
|
}
|
|
|
|
public static string FormatLength(decimal inches)
|
|
{
|
|
return ArchUnits.FormatFromInches((double)inches);
|
|
}
|
|
}
|