cake-order-tracker/server/templates/order.templ
bronkuu 5f156ab6a0 blocked dates page and warning for special-cake orders
Add blocked_date table (migration 5), model, and store CRUD methods.
Add management page at /blocked with add/delete functionality.
Add nav link 'Terminy zablokowane' with event_busy icon.
Pass blocked dates to order form as JSON data attribute.
On form submit, if the order has special cakes and the date is
blocked, show a confirm() dialog warning the user.
2026-06-15 18:54:48 +02:00

209 lines
7.8 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package templates
import (
"strconv"
"git.bronku.xyz/bronku/cake-order-tracker/models"
)
templ OrderPage(order models.Order, catalogue []models.Cake, allTags []models.Tag, blockedDates []models.BlockedDate) {
@Layout(OrderTitle(order), templ.NopComponent, OrderForm(order, catalogue, allTags, blockedDates))
}
templ OrderForm(order models.Order, catalogue []models.Cake, allTags []models.Tag, blockedDates []models.BlockedDate) {
<form method="post" class="split-pane" onsubmit="return confirmBlockedDate(this)" data-blocked-dates={ blockedDatesJSON(blockedDates) }>
<input type="hidden" name="id" value={ strconv.Itoa(order.ID) }/>
<div class="order-left">
<section class="card">
<header>
<h2>
<span class="material-symbols-outlined">person_add</span>
Dane klienta
</h2>
</header>
<div>
<div class="form-grid">
<div class="form-group">
<label>Imię *</label>
<input class="form-input" type="text" name="name" value={ order.Name } placeholder="Jan"/>
</div>
<div class="form-group">
<label>Nazwisko *</label>
<input class="form-input" type="text" name="surname" value={ order.Surname } placeholder="Kowalski"/>
</div>
<div class="form-group">
<label>Telefon</label>
<input class="form-input" type="tel" name="phone" value={ order.Phone } placeholder="+48 123 456 789"/>
</div>
<div class="form-group">
<label>Lokalizacja</label>
<div class="toggle-group">
<input type="hidden" name="location" value={ order.Location }/>
<button type="button" class={ "toggle-btn", templ.KV("active", order.Location == "Kartuzy") } onclick="setLocation(this, 'Kartuzy')">Kartuzy</button>
<button type="button" class={ "toggle-btn", templ.KV("active", order.Location == "Somonino") } onclick="setLocation(this, 'Somonino')">Somonino</button>
</div>
</div>
<div class="form-group">
<label>Data dostawy *</label>
<input class="form-input" type="date" name="date" value={ order.Date.Format("2006-01-02") }/>
</div>
<div class="form-group">
<label>Zaliczka</label>
<input class="form-input" type="number" name="paid" min="0" step="0.01" value={ order.Paid.String() } oninput={ templ.JSFuncCall("updatePrepaid") }/>
</div>
<div class="form-group" style="grid-column:span 2">
<label>Uwagi</label>
<input class="form-input" type="text" placeholder="Alergie, specjalne życzenia..."/>
</div>
</div>
</div>
</section>
<section class="card">
<header>
<h2>
<span class="material-symbols-outlined">cake_add</span>
Torty specjalne
</h2>
</header>
<div style="padding:1rem;text-align:center">
<button type="button" class="btn outline" onclick="openSpecialCakeOverlay()">
<span class="material-symbols-outlined">add</span>
Dodaj tort specjalny
</button>
</div>
</section>
<section class="card" style="flex:1;min-height:12.5rem">
<header>
<h2>
<span class="material-symbols-outlined">inventory_2</span>
Katalog produktów
</h2>
<div class="search-wrapper">
<span class="material-symbols-outlined search-icon">search</span>
<input class="search-input" type="text" placeholder="Filtruj produkty..." oninput="filterCatalogue(this)"/>
</div>
</header>
if len(allTags) > 0 {
<div class="tag-row">
for _, t := range allTags {
<button type="button" class="tag-chip" data-tag={ t.Name } onclick="toggleCatalogueTagFilter(this)">{ t.Name }</button>
}
</div>
}
<div class="catalogue-scroll">
<ul id="catalogue-grid">
for _, c := range catalogue {
<li data-name={ c.Name } data-tags={ tagNames(c.Tags) }>
<div>
<div class="icon cake">
<span class="material-symbols-outlined">cake</span>
</div>
<div style="min-width:0">
<div class="name">{ c.Name }</div>
<div class="price">{ c.Price.String() } PLN</div>
</div>
</div>
<div class="actions">
<button type="button" class="qty minus" onclick={ templ.JSFuncCall("changeCake", c.ID, c.Name, c.Price.String(), -1) }>
<span class="material-symbols-outlined">remove</span>
</button>
<span class="value" id={ "qty-" + strconv.Itoa(c.ID) }>0</span>
<button type="button" class="qty plus" onclick={ templ.JSFuncCall("changeCake", c.ID, c.Name, c.Price.String(), 1) }>
<span class="material-symbols-outlined">add</span>
</button>
</div>
</li>
}
</ul>
</div>
</section>
</div>
<aside class="order-aside">
<section class="card grow">
<header>
<h2>
<span class="material-symbols-outlined">receipt_long</span>
Podsumowanie
</h2>
</header>
<ul id="basket-items">
for _, c := range order.Cakes {
<li data-cake-id={ strconv.Itoa(c.ID) }>
<div>
<div class="name">{ c.Name }</div>
<div class="detail">{ c.Price.String() } PLN × <span class="qty">{ strconv.Itoa(c.Amount) }</span></div>
</div>
<div class="price">{ c.Total().String() } PLN</div>
<button type="button" class="remove" onclick="removeCake(this)">
<span class="material-symbols-outlined">close</span>
</button>
<input type="hidden" name={ "cake[" + strconv.Itoa(c.ID) + "]" } value={ strconv.Itoa(c.Amount) }/>
</li>
}
for _, s := range order.SpecialCakes {
<li data-special-id={ strconv.Itoa(s.ID) }>
<div>
<div class="name">{ s.Name }</div>
<div class="detail">{ specialCakeDetail(s) }</div>
if len(s.Tags) > 0 {
<div class="tag-group">
for _, t := range s.Tags {
<span class="tag-chip sm">{ t.Name }</span>
}
</div>
}
</div>
<div class="price">{ s.Price.String() } PLN</div>
<div class="basket-actions">
<button type="button" class="action-btn" onclick="editSpecialCake(this)" title="Edytuj">
<span class="material-symbols-outlined" style="font-size:1rem">edit</span>
</button>
<button type="button" class="remove" onclick="removeSpecialCake(this)" title="Usuń">
<span class="material-symbols-outlined">close</span>
</button>
</div>
<input type="hidden" name="special_name[]" value={ s.Name }/>
<input type="hidden" name="special_price[]" value={ s.Price.String() }/>
<input type="hidden" name="special_size[]" value={ s.Size }/>
<input type="hidden" name="special_shape[]" value={ s.Shape }/>
<input type="hidden" name="special_flavour[]" value={ s.Flavour }/>
<input type="hidden" name="special_notes[]" value={ s.Notes }/>
<input type="hidden" name="special_tags[]" value={ tagIDsComma(s.Tags) }/>
</li>
}
</ul>
<div class="summary-totals">
<div class="total-row">
<span>Subtotal</span>
<span id="subtotal-price">{ order.Subtotal().String() } PLN</span>
</div>
<div class="total-row">
<span>Zaliczka</span>
<span id="paid-amount">{ order.Paid.String() } PLN</span>
</div>
<div class="total-row grand">
<span>Do zapłaty</span>
<span id="total-price">{ order.Total().String() } PLN</span>
</div>
<button type="submit" class="btn-finalize">
<span class="material-symbols-outlined">check_circle</span>
Finalizuj zamówienie
</button>
</div>
</section>
</aside>
</form>
@SpecialCakeOverlay(allTags)
@templ.Raw(orderScript(order))
<script>
function setLocation(btn, value) {
var group = btn.closest('.toggle-group');
group.querySelectorAll('.toggle-btn').forEach(function(b) { b.classList.remove('active'); });
btn.classList.add('active');
group.querySelector('input[type=hidden]').value = value;
}
</script>
}