more simpler + torty sectino
This commit is contained in:
parent
a74c276cd3
commit
3b184c7c6f
10 changed files with 375 additions and 152 deletions
|
|
@ -96,6 +96,21 @@ type CakeCount struct {
|
|||
Amount int
|
||||
}
|
||||
|
||||
type SpecialCakeWithOrder struct {
|
||||
ID int
|
||||
OrderID int
|
||||
Name string
|
||||
Price Price
|
||||
Size string
|
||||
Shape string
|
||||
Flavour string
|
||||
Notes string
|
||||
Tags []Tag
|
||||
ClientName string
|
||||
ClientSurname string
|
||||
OrderDate time.Time
|
||||
}
|
||||
|
||||
type BlockedDate struct {
|
||||
ID int
|
||||
Date string
|
||||
|
|
|
|||
|
|
@ -65,6 +65,10 @@ func (h *Server) orders(r *http.Request) (templ.Component, int, error) {
|
|||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
specialCakes, err := h.s.GetSpecialCakesInRange(first, last)
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
|
||||
firstStr := first.Format(config.DateFormat)
|
||||
lastStr := last.Format(config.DateFormat)
|
||||
|
|
@ -74,11 +78,11 @@ func (h *Server) orders(r *http.Request) (templ.Component, int, error) {
|
|||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
return templates.MainContent("Panel główny", templates.OrdersMain(counts, cakeCounts, orders, firstStr, lastStr, specialFilter, today, tomorrow)), http.StatusOK, nil
|
||||
return templates.MainContent("Panel główny", templates.OrdersMain(counts, cakeCounts, orders, specialCakes, firstStr, lastStr, specialFilter, today, tomorrow)), http.StatusOK, nil
|
||||
}
|
||||
|
||||
if r.Header.Get("HX-Request") == "true" {
|
||||
return templates.OrdersContent(orders, cakeCounts, firstStr, lastStr, specialFilter), http.StatusOK, nil
|
||||
return templates.OrdersContent(orders, cakeCounts, specialCakes, firstStr, lastStr, specialFilter), http.StatusOK, nil
|
||||
}
|
||||
|
||||
counts, err := h.s.GetOrderCounts()
|
||||
|
|
@ -86,7 +90,7 @@ func (h *Server) orders(r *http.Request) (templ.Component, int, error) {
|
|||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
|
||||
return templates.OrdersPage(firstStr, lastStr, today, tomorrow, specialFilter, counts, cakeCounts, orders), http.StatusOK, nil
|
||||
return templates.OrdersPage(firstStr, lastStr, today, tomorrow, specialFilter, counts, cakeCounts, specialCakes, orders), http.StatusOK, nil
|
||||
}
|
||||
|
||||
func (h *Server) cakes(r *http.Request) (templ.Component, int, error) {
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@
|
|||
--space-lg: 1.5rem;
|
||||
--space-xl: 2rem;
|
||||
|
||||
--sidebar-w: 17.5rem;
|
||||
--topnav-h: 3.5rem;
|
||||
|
||||
--radius-sm: 0.25rem;
|
||||
|
|
|
|||
|
|
@ -749,3 +749,53 @@ textarea + label {
|
|||
.hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.link-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--primary);
|
||||
font-weight: 600;
|
||||
font-size: inherit;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.link-btn:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.overlay-panel--view {
|
||||
width: 24rem;
|
||||
}
|
||||
|
||||
.view-field {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.125rem;
|
||||
padding: var(--space-sm) 0;
|
||||
border-bottom: 1px solid var(--outline-dim);
|
||||
}
|
||||
|
||||
.view-field:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.view-field > label {
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
color: var(--on-surface-dim);
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
|
||||
.view-field > span,
|
||||
.view-field > div {
|
||||
font-size: 0.875rem;
|
||||
color: var(--on-surface);
|
||||
}
|
||||
|
||||
#sc-view-tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--space-xs);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,32 +1,52 @@
|
|||
body {
|
||||
display: grid;
|
||||
grid-template-columns: var(--sidebar-w) 1fr;
|
||||
grid-template-rows: var(--topnav-h) 1fr;
|
||||
grid-template-areas:
|
||||
"sidebar topnav"
|
||||
"sidebar main";
|
||||
height: 100dvh;
|
||||
}
|
||||
|
||||
aside {
|
||||
grid-area: sidebar;
|
||||
background: var(--surface-white);
|
||||
border-right: 1px solid var(--outline-dim);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: var(--space-md);
|
||||
gap: var(--space-sm);
|
||||
overflow: hidden;
|
||||
z-index: 40;
|
||||
}
|
||||
|
||||
aside > .cta {
|
||||
width: 100%;
|
||||
height: 2.5rem;
|
||||
.topnav {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-md);
|
||||
padding: 0 var(--space-lg);
|
||||
border-bottom: 1px solid var(--outline-dim);
|
||||
background: var(--surface);
|
||||
z-index: 30;
|
||||
}
|
||||
|
||||
.topnav > h1 {
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.topnav > nav {
|
||||
display: flex;
|
||||
gap: var(--space-xs);
|
||||
}
|
||||
|
||||
.topnav > nav > a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: var(--space-sm);
|
||||
padding: var(--space-sm) var(--space-md);
|
||||
border-radius: var(--radius-md);
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
color: var(--on-surface-dim);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.topnav > nav > a.active {
|
||||
background: var(--primary-container);
|
||||
color: var(--primary);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.topnav > .cta {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-sm);
|
||||
height: 2.25rem;
|
||||
padding: 0 var(--space-md);
|
||||
background: var(--primary);
|
||||
color: var(--on-primary);
|
||||
border: none;
|
||||
|
|
@ -35,74 +55,10 @@ aside > .cta {
|
|||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
aside > nav {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-xs);
|
||||
}
|
||||
|
||||
aside > nav > a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-sm);
|
||||
padding: var(--space-sm) var(--space-md);
|
||||
border-radius: var(--radius-md);
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
text-decoration: none;
|
||||
color: var(--on-surface-dim);
|
||||
}
|
||||
|
||||
aside > nav > a.active {
|
||||
background: var(--primary-container);
|
||||
color: var(--primary);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.topnav {
|
||||
grid-area: topnav;
|
||||
border-bottom: 1px solid var(--outline-dim);
|
||||
background: var(--surface);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-lg);
|
||||
padding: 0 var(--space-lg);
|
||||
flex-shrink: 0;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 30;
|
||||
}
|
||||
|
||||
.topnav > h1 {
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.topnav > .search {
|
||||
position: relative;
|
||||
width: 15rem;
|
||||
}
|
||||
|
||||
.topnav > .search input {
|
||||
height: 2rem;
|
||||
padding-left: 2rem;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.topnav > .search .material-symbols-outlined {
|
||||
position: absolute;
|
||||
left: var(--space-sm);
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
font-size: 1.25rem;
|
||||
color: var(--on-surface-dim);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
main {
|
||||
grid-area: main;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
|
|
@ -120,52 +76,38 @@ main {
|
|||
|
||||
#orders-results {
|
||||
grid-column: 1 / -1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: var(--space-md);
|
||||
}
|
||||
|
||||
@media (max-width: 64em) {
|
||||
.topnav > .search {
|
||||
width: 10rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 48em) {
|
||||
aside {
|
||||
width: var(--sidebar-w);
|
||||
padding: var(--space-xs);
|
||||
}
|
||||
|
||||
aside > .cta {
|
||||
width: 2.5rem;
|
||||
height: 2.5rem;
|
||||
padding: 0;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
aside > .cta span:not(.material-symbols-outlined) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
aside > nav > a {
|
||||
justify-content: center;
|
||||
padding: var(--space-sm);
|
||||
}
|
||||
|
||||
aside > nav > a span:not(.material-symbols-outlined) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.topnav {
|
||||
padding: 0 var(--space-sm);
|
||||
gap: var(--space-xs);
|
||||
}
|
||||
|
||||
.topnav > .search {
|
||||
.topnav > nav > a span:not(.material-symbols-outlined) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.topnav > .cta span:not(.material-symbols-outlined) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.topnav > .cta {
|
||||
width: 2.25rem;
|
||||
height: 2.25rem;
|
||||
padding: 0;
|
||||
border-radius: 50%;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
padding: var(--space-sm);
|
||||
}
|
||||
|
||||
.topnav > h1 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -329,6 +329,47 @@ function setActiveLink() {
|
|||
}
|
||||
}
|
||||
|
||||
function viewSpecialCake(btn) {
|
||||
var tr = btn.closest('tr');
|
||||
document.getElementById('sc-view-title').textContent = tr.getAttribute('data-sc-name');
|
||||
document.getElementById('sc-view-name').textContent = tr.getAttribute('data-sc-name');
|
||||
document.getElementById('sc-view-price').textContent = tr.getAttribute('data-sc-price') + ' PLN';
|
||||
document.getElementById('sc-view-size').textContent = tr.getAttribute('data-sc-size') || '—';
|
||||
var shapeVal = tr.getAttribute('data-sc-shape');
|
||||
var shapeText = '';
|
||||
if (shapeVal === 'round') shapeText = 'Okrągły';
|
||||
else if (shapeVal === 'square') shapeText = 'Kwadrat';
|
||||
else shapeText = shapeVal || '—';
|
||||
document.getElementById('sc-view-shape').textContent = shapeText;
|
||||
document.getElementById('sc-view-flavour').textContent = tr.getAttribute('data-sc-flavour') || '—';
|
||||
document.getElementById('sc-view-notes').textContent = tr.getAttribute('data-sc-notes') || '—';
|
||||
document.getElementById('sc-view-client').textContent = tr.getAttribute('data-sc-client');
|
||||
document.getElementById('sc-view-date').textContent = tr.getAttribute('data-sc-date');
|
||||
var tagsStr = tr.getAttribute('data-sc-tags');
|
||||
var tagsContainer = document.getElementById('sc-view-tags');
|
||||
tagsContainer.innerHTML = '';
|
||||
if (tagsStr) {
|
||||
var tagNames = tagsStr.split(',');
|
||||
for (var i = 0; i < tagNames.length; i++) {
|
||||
if (tagNames[i].trim()) {
|
||||
var tag = document.createElement('span');
|
||||
tag.className = 'tag-chip sm';
|
||||
tag.textContent = tagNames[i].trim();
|
||||
tagsContainer.appendChild(tag);
|
||||
}
|
||||
}
|
||||
document.getElementById('sc-view-tags-field').classList.remove('hide');
|
||||
} else {
|
||||
document.getElementById('sc-view-tags-field').classList.add('hide');
|
||||
}
|
||||
document.getElementById('sc-view-order-link').href = '/order/' + tr.getAttribute('data-sc-order-id');
|
||||
document.getElementById('sc-view-overlay').classList.add('open');
|
||||
}
|
||||
|
||||
function closeViewSpecialCake() {
|
||||
document.getElementById('sc-view-overlay').classList.remove('open');
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
setActiveLink();
|
||||
initOrderPage();
|
||||
|
|
|
|||
|
|
@ -14,11 +14,26 @@ templ Layout(title string, main templ.Component) {
|
|||
<script src="/static/order.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<aside>
|
||||
@Nav()
|
||||
</aside>
|
||||
<header class="topnav">
|
||||
<h1>{ title }</h1>
|
||||
<nav>
|
||||
<a href="/orders" hx-get="/orders" hx-target="#main" hx-swap="outerHTML" hx-push-url="true">
|
||||
<span class="material-symbols-outlined">dashboard</span>
|
||||
<span>Panel główny</span>
|
||||
</a>
|
||||
<a href="/cakes" hx-get="/cakes" hx-target="#main" hx-swap="outerHTML" hx-push-url="true">
|
||||
<span class="material-symbols-outlined">inventory_2</span>
|
||||
<span>Katalog</span>
|
||||
</a>
|
||||
<a href="/blocked" hx-get="/blocked" hx-target="#main" hx-swap="outerHTML" hx-push-url="true">
|
||||
<span class="material-symbols-outlined">event_busy</span>
|
||||
<span>Terminy zablokowane</span>
|
||||
</a>
|
||||
</nav>
|
||||
<a href="/order" class="cta" hx-get="/order" hx-target="#main" hx-swap="outerHTML" hx-push-url="true">
|
||||
<span class="material-symbols-outlined">add</span>
|
||||
<span>Nowe zamówienie</span>
|
||||
</a>
|
||||
</header>
|
||||
<main id="main">
|
||||
<div class="main-content">
|
||||
|
|
@ -32,6 +47,24 @@ templ Layout(title string, main templ.Component) {
|
|||
templ MainContent(title string, main templ.Component) {
|
||||
<header class="topnav" hx-swap-oob="true">
|
||||
<h1>{ title }</h1>
|
||||
<nav>
|
||||
<a href="/orders" hx-get="/orders" hx-target="#main" hx-swap="outerHTML" hx-push-url="true">
|
||||
<span class="material-symbols-outlined">dashboard</span>
|
||||
<span>Panel główny</span>
|
||||
</a>
|
||||
<a href="/cakes" hx-get="/cakes" hx-target="#main" hx-swap="outerHTML" hx-push-url="true">
|
||||
<span class="material-symbols-outlined">inventory_2</span>
|
||||
<span>Katalog</span>
|
||||
</a>
|
||||
<a href="/blocked" hx-get="/blocked" hx-target="#main" hx-swap="outerHTML" hx-push-url="true">
|
||||
<span class="material-symbols-outlined">event_busy</span>
|
||||
<span>Terminy zablokowane</span>
|
||||
</a>
|
||||
</nav>
|
||||
<a href="/order" class="cta" hx-get="/order" hx-target="#main" hx-swap="outerHTML" hx-push-url="true">
|
||||
<span class="material-symbols-outlined">add</span>
|
||||
<span>Nowe zamówienie</span>
|
||||
</a>
|
||||
</header>
|
||||
<main id="main">
|
||||
<title hx-swap-oob="true">{ title } — Zamówienia ciast</title>
|
||||
|
|
|
|||
|
|
@ -1,22 +0,0 @@
|
|||
package templates
|
||||
|
||||
templ Nav() {
|
||||
<a href="/order" class="cta" hx-get="/order" hx-target="#main" hx-swap="outerHTML" hx-push-url="true">
|
||||
<span class="material-symbols-outlined">add</span>
|
||||
<span>Nowe zamówienie</span>
|
||||
</a>
|
||||
<nav>
|
||||
<a href="/orders" hx-get="/orders" hx-target="#main" hx-swap="outerHTML" hx-push-url="true">
|
||||
<span class="material-symbols-outlined">dashboard</span>
|
||||
<span>Panel główny</span>
|
||||
</a>
|
||||
<a href="/cakes" hx-get="/cakes" hx-target="#main" hx-swap="outerHTML" hx-push-url="true">
|
||||
<span class="material-symbols-outlined">inventory_2</span>
|
||||
<span>Katalog</span>
|
||||
</a>
|
||||
<a href="/blocked" hx-get="/blocked" hx-target="#main" hx-swap="outerHTML" hx-push-url="true">
|
||||
<span class="material-symbols-outlined">event_busy</span>
|
||||
<span>Terminy zablokowane</span>
|
||||
</a>
|
||||
</nav>
|
||||
}
|
||||
|
|
@ -6,8 +6,8 @@ import (
|
|||
"git.bronku.xyz/bronku/cake-order-tracker/models"
|
||||
)
|
||||
|
||||
templ OrdersPage(first, last, today, tomorrow, special string, counts models.OrderCounts, cakeCounts []models.CakeCount, orders []models.Order) {
|
||||
@Layout("Panel główny", OrdersMain(counts, cakeCounts, orders, first, last, special, today, tomorrow))
|
||||
templ OrdersPage(first, last, today, tomorrow, special string, counts models.OrderCounts, cakeCounts []models.CakeCount, specialCakes []models.SpecialCakeWithOrder, orders []models.Order) {
|
||||
@Layout("Panel główny", OrdersMain(counts, cakeCounts, orders, specialCakes, first, last, special, today, tomorrow))
|
||||
}
|
||||
|
||||
templ DateForm(first, last, today, tomorrow, special string) {
|
||||
|
|
@ -27,7 +27,7 @@ templ DateForm(first, last, today, tomorrow, special string) {
|
|||
</div>
|
||||
}
|
||||
|
||||
templ OrdersMain(counts models.OrderCounts, cakeCounts []models.CakeCount, orders []models.Order, first, last, special, today, tomorrow string) {
|
||||
templ OrdersMain(counts models.OrderCounts, cakeCounts []models.CakeCount, orders []models.Order, specialCakes []models.SpecialCakeWithOrder, first, last, special, today, tomorrow string) {
|
||||
@DateForm(first, last, today, tomorrow, special)
|
||||
<div class="metric">
|
||||
<span class="label">
|
||||
|
|
@ -46,11 +46,12 @@ templ OrdersMain(counts models.OrderCounts, cakeCounts []models.CakeCount, order
|
|||
<span class="change">Do zrobienia</span>
|
||||
</div>
|
||||
<div id="orders-results">
|
||||
@OrdersContent(orders, cakeCounts, first, last, special)
|
||||
@OrdersContent(orders, cakeCounts, specialCakes, first, last, special)
|
||||
</div>
|
||||
@SpecialCakeViewOverlay()
|
||||
}
|
||||
|
||||
templ OrdersContent(orders []models.Order, cakeCounts []models.CakeCount, first, last, special string) {
|
||||
templ OrdersContent(orders []models.Order, cakeCounts []models.CakeCount, specialCakes []models.SpecialCakeWithOrder, first, last, special string) {
|
||||
<section class="card" id="orders-card">
|
||||
<header>
|
||||
<h2>
|
||||
|
|
@ -90,6 +91,7 @@ templ OrdersContent(orders []models.Order, cakeCounts []models.CakeCount, first,
|
|||
</table>
|
||||
</section>
|
||||
@CakeBreakdown(cakeCounts)
|
||||
@SpecialCakesTable(specialCakes)
|
||||
}
|
||||
|
||||
templ OrderRow(order models.Order) {
|
||||
|
|
@ -156,6 +158,125 @@ templ OrderRow(order models.Order) {
|
|||
</tr>
|
||||
}
|
||||
|
||||
templ SpecialCakesTable(specialCakes []models.SpecialCakeWithOrder) {
|
||||
<section class="card" id="special-cakes-card">
|
||||
<header>
|
||||
<h2>
|
||||
<span class="material-symbols-outlined">cake</span>
|
||||
Torty specjalne
|
||||
</h2>
|
||||
</header>
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Nazwa</th>
|
||||
<th>Klient</th>
|
||||
<th>Data odbioru</th>
|
||||
<th class="text-right">Cena</th>
|
||||
<th class="text-center"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
for _, sc := range specialCakes {
|
||||
<tr data-sc-id={ strconv.Itoa(sc.ID) }
|
||||
data-sc-name={ sc.Name }
|
||||
data-sc-price={ sc.Price.String() }
|
||||
data-sc-size={ sc.Size }
|
||||
data-sc-shape={ sc.Shape }
|
||||
data-sc-flavour={ sc.Flavour }
|
||||
data-sc-notes={ sc.Notes }
|
||||
data-sc-tags={ tagNames(sc.Tags) }
|
||||
data-sc-order-id={ strconv.Itoa(sc.OrderID) }
|
||||
data-sc-client={ sc.ClientName + " " + sc.ClientSurname }
|
||||
data-sc-date={ sc.OrderDate.Format("2006-01-02") }>
|
||||
<td>
|
||||
<button type="button" class="link-btn" onclick="viewSpecialCake(this)">{ sc.Name }</button>
|
||||
</td>
|
||||
<td>{ sc.ClientName } { sc.ClientSurname }</td>
|
||||
<td class="text-muted">{ sc.OrderDate.Format("2006-01-02") }</td>
|
||||
<td class="text-right">{ sc.Price.String() } PLN</td>
|
||||
<td class="text-center">
|
||||
<a href={ templ.URL("/order/" + strconv.Itoa(sc.OrderID)) } class="btn-icon" title="Zobacz zamówienie">
|
||||
<span class="material-symbols-outlined">receipt_long</span>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
if len(specialCakes) == 0 {
|
||||
<tr>
|
||||
<td colspan="5" class="empty-state">Brak tortów specjalnych w tym okresie</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
}
|
||||
|
||||
templ SpecialCakeViewOverlay() {
|
||||
<div id="sc-view-overlay" class="overlay">
|
||||
<div class="overlay-backdrop" onclick="closeViewSpecialCake()"></div>
|
||||
<div class="overlay-panel overlay-panel--view">
|
||||
<header>
|
||||
<h2>
|
||||
<span class="material-symbols-outlined">cake</span>
|
||||
<span id="sc-view-title">Tort specjalny</span>
|
||||
</h2>
|
||||
<button type="button" class="close-btn" onclick="closeViewSpecialCake()">
|
||||
<span class="material-symbols-outlined">close</span>
|
||||
</button>
|
||||
</header>
|
||||
<div class="overlay-body">
|
||||
<div class="view-field">
|
||||
<label>Nazwa</label>
|
||||
<span id="sc-view-name"></span>
|
||||
</div>
|
||||
<div class="view-field">
|
||||
<label>Cena</label>
|
||||
<span id="sc-view-price"></span>
|
||||
</div>
|
||||
<div class="view-field">
|
||||
<label>Wielkość</label>
|
||||
<span id="sc-view-size"></span>
|
||||
</div>
|
||||
<div class="view-field">
|
||||
<label>Kształt</label>
|
||||
<span id="sc-view-shape"></span>
|
||||
</div>
|
||||
<div class="view-field">
|
||||
<label>Smak</label>
|
||||
<span id="sc-view-flavour"></span>
|
||||
</div>
|
||||
<div class="view-field">
|
||||
<label>Notatki</label>
|
||||
<span id="sc-view-notes"></span>
|
||||
</div>
|
||||
<div class="view-field" id="sc-view-tags-field">
|
||||
<label>Tagi</label>
|
||||
<div id="sc-view-tags"></div>
|
||||
</div>
|
||||
<div class="view-field">
|
||||
<label>Klient</label>
|
||||
<span id="sc-view-client"></span>
|
||||
</div>
|
||||
<div class="view-field">
|
||||
<label>Data odbioru</label>
|
||||
<span id="sc-view-date"></span>
|
||||
</div>
|
||||
</div>
|
||||
<footer>
|
||||
<a href="" id="sc-view-order-link" class="btn btn-outline">
|
||||
<span class="material-symbols-outlined">receipt_long</span>
|
||||
Zobacz zamówienie
|
||||
</a>
|
||||
<button type="button" class="btn btn-primary" onclick="closeViewSpecialCake()">
|
||||
<span class="material-symbols-outlined">close</span>
|
||||
Zamknij
|
||||
</button>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
templ CakeBreakdown(cakeCounts []models.CakeCount) {
|
||||
<section class="card" id="breakdown-card">
|
||||
<header>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@ package store
|
|||
import (
|
||||
"database/sql"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"git.bronku.xyz/bronku/cake-order-tracker/config"
|
||||
"git.bronku.xyz/bronku/cake-order-tracker/models"
|
||||
)
|
||||
|
||||
|
|
@ -67,6 +69,44 @@ func (s *Store) saveSpecialCakeTags(tx *sql.Tx, specialCakeID int, tagIDs []int)
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Store) GetSpecialCakesInRange(from, to time.Time) ([]models.SpecialCakeWithOrder, error) {
|
||||
start, end := dateRangeParams(from, to)
|
||||
rows, err := s.db.Query(`
|
||||
SELECT sc.id, sc.customer_order, sc.name, sc.price, sc.size, sc.shape, sc.flavour, sc.notes,
|
||||
co.name, co.surname, co.delivery_date
|
||||
FROM special_cake sc
|
||||
JOIN customer_order co ON sc.customer_order = co.id
|
||||
WHERE co.status != 'picked_up' AND co.delivery_date >= ? AND co.delivery_date <= ?
|
||||
ORDER BY co.delivery_date
|
||||
`, start, end)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var out []models.SpecialCakeWithOrder
|
||||
for rows.Next() {
|
||||
var sw models.SpecialCakeWithOrder
|
||||
var price int
|
||||
var deliveryDate string
|
||||
if err := rows.Scan(&sw.ID, &sw.OrderID, &sw.Name, &price, &sw.Size, &sw.Shape, &sw.Flavour, &sw.Notes,
|
||||
&sw.ClientName, &sw.ClientSurname, &deliveryDate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sw.Price = models.Price(price)
|
||||
sw.OrderDate, err = time.Parse(config.DateTimeFormat, deliveryDate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sw.Tags, err = s.GetSpecialCakeTags(sw.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out = append(out, sw)
|
||||
}
|
||||
return out, rows.Err()
|
||||
}
|
||||
|
||||
func (s *Store) SaveSpecialCakes(tx *sql.Tx, orderID int, cakes []models.SpecialCake) error {
|
||||
if _, err := tx.Exec("delete from special_cake where customer_order = ?;", orderID); err != nil {
|
||||
return err
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue