Repository navigation
Expand file tree
/
Copy pathCookingTime.razor
More file actions
112 lines (91 loc) · 3.23 KB
/
Copy pathCookingTime.razor
File metadata and controls
112 lines (91 loc) · 3.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
@* filepath: Pages/CookingTime.razor *@
@page "/cooking-time"
@inject ICookingTimeCalculator Calculator
@inject IMealFactory MealFactory
<PageTitle>Cooking Time Calculator</PageTitle>
<h1>Cooking Time Calculator</h1>
<EditForm Model="@_model" OnValidSubmit="@HandleSubmit" FormName="cooking-time">
<DataAnnotationsValidator />
<ValidationSummary />
<div>
<label for="meal">Cooking Type:</label>
<InputSelect id="meal" @bind-Value="_model.Meal" TValue="string">
<option value="">Select a meal...</option>
@foreach (var meal in _meals)
{
<option value="@meal.Name">@meal.Name</option>
}
</InputSelect>
<ValidationMessage For="() => _model.Meal" />
</div>
<div>
<label for="weight">Cooking Weight:</label>
<InputNumber id="weight" @bind-Value="_model.Weight" TValue="decimal" />
<ValidationMessage For="() => _model.Weight" />
</div>
<div>
<label>Units:</label>
<InputRadioGroup Name="unit" @bind-Value="_model.Unit">
<label><InputRadio Name="unit" Value="@WeightUnit.Pounds" /> Pounds</label>
<label><InputRadio Name="unit" Value="@WeightUnit.Kilograms" /> Kilograms</label>
</InputRadioGroup>
</div>
<button type="submit">Calculate</button>
<button type="button" @onclick="Reset">Reset</button>
</EditForm>
@if (_result is not null)
{
<section>
<h2>Cooking Time</h2>
<p>@_result.FormattedDuration</p>
<h3>Cooking Instructions</h3>
<p>@_result.Instructions</p>
@if (!_result.IsSuccess)
{
<ul class="validation-errors">
@foreach (var error in _result.ValidationErrors)
{
<li>@error</li>
}
</ul>
}
</section>
}
@code {
private CookingTimeViewModel _model = new();
private IReadOnlyList<IMeal> _meals = Array.Empty<IMeal>();
private CookingResult? _result;
/// <summary>
/// Optional initial model state. Used by component tests to pre-fill the form
/// and avoid flaky bUnit input-binding timing. Production code does not set this.
/// </summary>
[Parameter] public CookingTimeViewModel? InitialModel { get; set; }
protected override void OnInitialized()
{
if (InitialModel is not null)
_model = InitialModel;
_meals = MealFactory.CreateAll()
.OrderBy(m => m.Name, StringComparer.Ordinal)
.ToList();
}
public async Task SubmitAsync() => await HandleSubmit();
private async Task HandleSubmit()
{
_result = await Calculator.CalculateAsync(_model.Meal, _model.Weight, _model.Unit);
}
private void Reset()
{
_model.Meal = "";
_model.Weight = 1M;
_model.Unit = WeightUnit.Pounds;
_result = null;
}
public sealed class CookingTimeViewModel
{
[Required(ErrorMessage = "Please select a meal.")]
public string Meal { get; set; } = "";
[Range(0.01, 999.0, ErrorMessage = "Please enter a weight between 0.01 and 999.")]
public decimal Weight { get; set; } = 1M;
public WeightUnit Unit { get; set; } = WeightUnit.Pounds;
}
}