cake-order-tracker/server/templates/order.templ
bronkuu 5a5372b831 templates, handlers, CSS, JS: special cakes UI, HTMX nav, dashboard overhaul
Special cakes UI: overlay drawer, basket integration, catalogue tag
filter, form parsing, JS save/edit/remove.
HTMX navigation: MainContent component, nav links with hx-get,
handlers return partial on HX-Request.
Dashboard: metrics grid, CakeBreakdown, OrderRow with status select,
CakeCounts/OrderCounts, torty filter, tort badge, results-pane.
Collapsible sidebar: toggle button, localStorage, CSS transitions.
Location field: dropdown replaced with pill toggle.
Inline style cleanup: moved to CSS classes (tag-grid, grow, icon.sm,
header-actions, toggle-group, success-icon, etc.).
Dead CSS removal: pagination, status-chip, badge-pill, login-page.
Helpers: exported CakeTitle/OrderTitle, added tagNames, tagIDsComma,
orderItemsDesc, specialCakeDetail, removed unused helpers.
2026-06-15 18:50:21 +02:00

209 lines
7.6 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) {
@Layout(OrderTitle(order), templ.NopComponent, OrderForm(order, catalogue, allTags))
}
templ OrderForm(order models.Order, catalogue []models.Cake, allTags []models.Tag) {
<form method="post" class="split-pane">
<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>
}