Commit 3c925a16 authored by Ryan Nowak's avatar Ryan Nowak
Browse files

Add part two

parent 3ec0a5f3
......@@ -17,21 +17,30 @@ Sessions
- Fetch specials list from backend
- Display list of pizza names
- Pizza card component (no templates yet)
- Parameters: Pizza object
- Parameters: PizzaSpecial object
Lunch
1. Handling UI events & data binding
- Clickable pizza cards
- Cover `@page`
- Pizza customization
- Price updated based on selections
- Place order button, sends order to the backend
- Confirmation screen
- Make special pizza cards clickable
- Clicking on a special brings up the new customize dialog
- Index needs to handle the hide/show of the dialog
- Index needs to pass in the Pizza object as well as two 'command' delegates
- Using `bind` and `onclick` on the customize dialog to update prices in real time
- explain the difference between `bind` and `bind-value-oninput` on the slider
- cancel button should close the dialog
- confirm button should close the dialog and add to order
- now add the markup for sidebar which will display orders
- add a ConfiguredPizzaItem component
- hook up the order button to do an HTTP POST and clear the order
- (no way to see existing orders yet)
1. DI
- Create a service for interacting with the backend, repository abstraction
- Refactor HttpClient code to use service instead
- Talk to DI scopes
1. Build the order status screen
- Confirmation screen
- Cover `@page`
1. JS interop
- Add order status
- Real status (map location, time to delivery) via polling
......
......@@ -7,7 +7,7 @@
{
@foreach (var special in specials)
{
<li style="background-image: url('@special.ImageUrl')">
<li onclick="@(() => ShowConfigurePizzaDialog(special))" style="background-image: url('@special.ImageUrl')">
<div class="pizza-info">
<span class="title">@special.Name</span>
@special.Description
......@@ -19,11 +19,90 @@
</ul>
</div>
<div class="sidebar">
@if (order.Pizzas.Any())
{
<div class="order-contents">
<h2>Your order</h2>
@foreach (var configuredPizza in order.Pizzas)
{
<ConfiguredPizzaItem Pizza="configuredPizza" OnRemoved="() => RemoveConfiguredPizza(configuredPizza)" />
}
</div>
}
else
{
<div class="empty-cart">Choose a pizza<br>to get started</div>
}
<div class="order-total @(order.Pizzas.Any() ? "" : "hidden")">
Total:
<span class="total-price">@order.GetFormattedTotalPrice()</span>
<button class="btn btn-warning" disabled="@(order.Pizzas.Count == 0)" onclick="@PlaceOrder">
Order >
</button>
</div>
</div>
@if (showingConfigureDialog)
{
<ConfigurePizzaDialog
Pizza="configuringPizza"
OnCancel="CancelConfigurePizzaDialog"
OnConfirm="ConfirmConfigurePizzaDialog"/>
}
@functions {
List<PizzaSpecial> specials;
Pizza configuringPizza;
bool showingConfigureDialog;
Order order = new Order();
protected async override Task OnInitAsync()
{
specials = await HttpClient.GetJsonAsync<List<PizzaSpecial>>("/specials");
}
void ShowConfigurePizzaDialog(PizzaSpecial special)
{
configuringPizza = new Pizza()
{
Special = special,
SpecialId = special.Id,
Size = Pizza.DefaultSize,
Toppings = new List<PizzaTopping>(),
};
showingConfigureDialog = true;
}
void CancelConfigurePizzaDialog()
{
configuringPizza = null;
showingConfigureDialog = false;
StateHasChanged();
}
void ConfirmConfigurePizzaDialog()
{
order.Pizzas.Add(configuringPizza);
configuringPizza = null;
showingConfigureDialog = false;
StateHasChanged();
}
void RemoveConfiguredPizza(Pizza pizza)
{
order.Pizzas.Remove(pizza);
StateHasChanged();
}
async Task PlaceOrder()
{
await HttpClient.PostJsonAsync("/orders", order);
order = new Order();
}
}
@inject HttpClient HttpClient
<div class="dialog-container">
<div class="dialog">
<div class="dialog-title">
<h2>@Pizza.Special.Name</h2>
@Pizza.Special.Description
</div>
<form class="dialog-body">
<div>
<label>Size:</label>
<input type="range" min="@Pizza.MinimumSize" max="@Pizza.MaximumSize" step="1" bind-value-oninput="Pizza.Size" />
<span class="size-label">
@(Pizza.Size)" (£@(Pizza.GetFormattedTotalPrice()))
</span>
</div>
<div>
<label>Extra Toppings:</label>
@if (toppings == null)
{
<select class="custom-select" disabled>
<option>(loading...)</option>
</select>
}
else if (Pizza.Toppings.Count >= 6)
{
<div>(maximum reached)</div>
}
else
{
<select class="custom-select" onchange="@ToppingSelected">
<option value="-1" disabled selected>(select)</option>
@for (var i = 0; i < toppings.Count; i++)
{
<option value="@i">@toppings[i].Name - (£@(toppings[i].GetFormattedPrice()))</option>
}
</select>
}
</div>
<div class="toppings">
@foreach (var topping in Pizza.Toppings)
{
<div class="topping">
@topping.Topping.Name
<span class="topping-price">@topping.Topping.GetFormattedPrice()</span>
<button type="button" class="delete-topping" onclick="@(() => RemoveTopping(topping.Topping))">x</button>
</div>
}
</div>
</form>
<div class="dialog-buttons">
<button class="btn btn-secondary mr-auto" onclick="@OnCancel">Cancel</button>
<span class="mr-center">
Price: <span class="price">@(Pizza.GetFormattedTotalPrice())</span>
</span>
<button class="btn btn-success ml-auto" onclick="@OnConfirm">Order ></button>
</div>
</div>
</div>
@functions {
List<Topping> toppings { get; set; }
[Parameter] Pizza Pizza { get; set; }
[Parameter] Action OnCancel { get; set; }
[Parameter] Action OnConfirm { get; set; }
protected async override Task OnInitAsync()
{
toppings = await HttpClient.GetJsonAsync<List<Topping>>("/toppings");
}
void ToppingSelected(UIChangeEventArgs e)
{
if (int.TryParse((string)e.Value, out var index) && index >= 0)
{
AddTopping(toppings[index]);
}
}
void AddTopping(Topping topping)
{
if (Pizza.Toppings.Find(pt => pt.Topping == topping) == null)
{
Pizza.Toppings.Add(new PizzaTopping() { Topping = topping });
}
}
void RemoveTopping(Topping topping)
{
Pizza.Toppings.RemoveAll(pt => pt.Topping == topping);
StateHasChanged();
}
}
<div class="cart-item">
<a onclick=@OnRemoved class="delete-item">x</a>
<div class="title">@(Pizza.Size)" @Pizza.Special.Name</div>
<ul>
@foreach (var topping in Pizza.Toppings)
{
<li>+ @topping.Topping.Name</li>
}
</ul>
<div class="item-price">
@Pizza.GetFormattedTotalPrice()
</div>
</div>
@functions {
[Parameter] Pizza Pizza { get; set; }
[Parameter] Action OnRemoved { get; set; }
}
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment