Files
ps_shop/templates/cart.templ
T
2026-05-16 00:20:34 +02:00

152 lines
9.8 KiB
Plaintext

package templates
import (
"fmt"
"git.ma-al.com/goc_marek/ps_shop/internal/viewmodel"
)
templ CartPage(data viewmodel.CartPageData, cssPath string, jsPath string) {
@Layout("Cart", cssPath, jsPath, data.Menu, data.Locale, data.Cart.TotalItems) {
<main class="min-h-screen bg-[#fdfbf7]">
<div class="site-container flex flex-col gap-8 py-6 sm:py-8 lg:py-10">
<header class="border-b border-stone-200 pb-6">
<div class="flex flex-col gap-6 lg:flex-row lg:items-end lg:justify-between">
<div class="max-w-3xl">
<p class="text-[0.72rem] font-semibold uppercase tracking-[0.26em] text-stone-400">Cart overview</p>
<h1 class="mt-4 text-3xl font-medium text-stone-800 sm:text-[2.5rem]">Everything ready for checkout.</h1>
<p class="mt-4 max-w-2xl text-sm leading-7 text-stone-500">Review quantities, adjust line items, and confirm the final order state before checkout continues in PrestaShop.</p>
</div>
<div class="grid gap-3 sm:grid-cols-2 lg:min-w-[20rem]">
<div class="border border-stone-200 bg-white px-5 py-4 shadow-[0_12px_30px_rgba(20,33,61,0.05)]">
<p class="text-[0.68rem] uppercase tracking-[0.28em] text-stone-500">Line items</p>
<p class="mt-2 text-3xl font-semibold text-stone-900">{ fmt.Sprintf("%d", len(data.Cart.Items)) }</p>
</div>
<div class="border border-stone-200 bg-[#fff7e7] px-5 py-4 shadow-[0_12px_30px_rgba(20,33,61,0.05)]">
<p class="text-[0.68rem] uppercase tracking-[0.28em] text-stone-500">Units total</p>
<p class="mt-2 text-3xl font-semibold text-stone-900">{ fmt.Sprintf("%d", data.Cart.TotalItems) }</p>
</div>
</div>
</div>
<div class="mt-6 flex flex-wrap items-center gap-3 text-sm text-stone-500">
if data.Customer != nil {
<span class="border border-stone-200 bg-white px-4 py-2">{ fmt.Sprintf("%s %s", data.Customer.FirstName, data.Customer.LastName) }</span>
} else {
<span class="border border-stone-200 bg-white px-4 py-2">Guest session</span>
}
<span class="border border-stone-200 bg-white px-4 py-2">{ "Subtotal " + moneyWithCurrency(data.Cart.SubtotalTaxIncl, cartCurrencySign(data), cartCurrencyCode(data)) }</span>
</div>
</header>
<section class="grid gap-8 xl:grid-cols-[minmax(0,1.55fr)_24rem]">
<div class="border border-stone-200 bg-white p-5 shadow-[0_18px_42px_rgba(20,33,61,0.06)] lg:p-6">
if len(data.Cart.Items) == 0 {
<div class="border border-dashed border-stone-300 bg-[#fcfbf8] p-12 text-center">
<p class="text-sm uppercase tracking-[0.28em] text-stone-400">Empty</p>
<p class="mt-4 text-3xl font-semibold text-stone-900">Your cart is empty.</p>
<p class="mx-auto mt-3 max-w-md text-sm leading-7 text-stone-500">Browse categories or return to a product page to add items and build a full order before checkout.</p>
</div>
} else {
<div class="mb-4 hidden grid-cols-[minmax(0,1fr)_11rem] gap-4 px-4 text-[0.68rem] uppercase tracking-[0.28em] text-stone-500 md:grid">
<div>Product</div>
<div class="text-right">Summary</div>
</div>
<div class="space-y-4">
for _, item := range data.Cart.Items {
<article class="border border-stone-200 bg-[#fffdfa] p-5 transition hover:border-amber-400/60 md:p-6">
<div class="flex flex-col gap-5 md:flex-row md:items-start md:justify-between">
if item.ImageURL != "" {
<div class="flex overflow-hidden border border-stone-200 bg-white md:w-32 md:shrink-0 md:items-center md:justify-center">
<img class="block h-32 w-full object-contain" src={ item.ImageURL } alt={ item.Name }/>
</div>
}
<div class="min-w-0 flex-1">
<div class="flex flex-wrap items-center gap-2">
<p class="text-[0.68rem] uppercase tracking-[0.3em] text-stone-400">Product</p>
if cartItemAttributeLabel(item) != "" {
<span class="border border-amber-200 bg-[#fff7e7] px-2.5 py-1 text-[0.65rem] uppercase tracking-[0.16em] text-amber-700">{ cartItemAttributeLabel(item) }</span>
}
</div>
if item.URL != "" {
<a class="mt-3 block truncate text-2xl font-semibold text-stone-900 underline-offset-4 transition hover:text-amber-600 hover:underline" href={ item.URL }>{ item.Name }</a>
} else {
<h2 class="mt-3 text-2xl font-semibold text-stone-900">{ item.Name }</h2>
}
<div class="mt-4 flex flex-wrap gap-2 text-xs text-stone-500">
<span class="border border-stone-200 bg-white px-3 py-1.5">{ fmt.Sprintf("Qty %d", item.Quantity) }</span>
<span class="border border-stone-200 bg-white px-3 py-1.5">{ "Net " + moneyWithCurrency(item.UnitPrice, item.CurrencySign, item.CurrencyCode) }</span>
<span class="border border-stone-200 bg-white px-3 py-1.5">{ taxLabel(item.TaxRate) }</span>
</div>
</div>
<div class="border border-stone-200 bg-white px-4 py-4 text-left md:min-w-[11rem] md:text-right">
<p class="text-[0.68rem] uppercase tracking-[0.24em] text-stone-500">Line total</p>
<p class="mt-2 text-2xl font-semibold text-stone-900">{ moneyWithCurrency(item.LineTotalTaxIncl, item.CurrencySign, item.CurrencyCode) }</p>
<p class="mt-1 text-xs uppercase tracking-[0.2em] text-stone-500">{ conversionRateLabel(item.ConversionRate, item.CurrencyCode) }</p>
</div>
</div>
<div class="mt-6 flex flex-col gap-3 border-t border-stone-200 pt-5 md:flex-row md:items-center md:justify-between">
<form class="flex flex-wrap items-center gap-3" method="post" action={ localizedCartPath(data.Locale) }>
<input type="hidden" name="action" value="update"/>
<input type="hidden" name="id_product" value={ fmt.Sprintf("%d", item.ProductID) }/>
<input type="hidden" name="id_product_attribute" value={ fmt.Sprintf("%d", item.ProductAttributeID) }/>
<input type="hidden" name="id_customization" value={ fmt.Sprintf("%d", item.CustomizationID) }/>
<label class="text-[0.75rem] uppercase tracking-[0.24em] text-stone-400" for={ fmt.Sprintf("qty-%d-%d", item.ProductID, item.ProductAttributeID) }>Quantity</label>
<div class="flex items-center border border-stone-300 bg-white">
<input class="w-20 bg-transparent px-4 py-2.5 text-center text-sm text-stone-900 outline-none ring-0" id={ fmt.Sprintf("qty-%d-%d", item.ProductID, item.ProductAttributeID) } type="number" min="1" name="qty" value={ fmt.Sprintf("%d", item.Quantity) }/>
</div>
<button class="border border-amber-500 bg-amber-500 px-4 py-2.5 text-xs font-semibold uppercase tracking-[0.22em] text-white transition hover:bg-amber-600" type="submit">
Update line
</button>
</form>
<form method="post" action={ localizedCartPath(data.Locale) }>
<input type="hidden" name="action" value="delete"/>
<input type="hidden" name="id_product" value={ fmt.Sprintf("%d", item.ProductID) }/>
<input type="hidden" name="id_product_attribute" value={ fmt.Sprintf("%d", item.ProductAttributeID) }/>
<input type="hidden" name="id_customization" value={ fmt.Sprintf("%d", item.CustomizationID) }/>
<button class="border border-stone-300 bg-white px-4 py-2.5 text-xs font-semibold uppercase tracking-[0.22em] text-stone-700 transition hover:border-rose-300 hover:bg-rose-50 hover:text-rose-700" type="submit">
Remove
</button>
</form>
</div>
</article>
}
</div>
}
</div>
<aside class="xl:sticky xl:top-28 xl:self-start">
<div class="border border-stone-200 bg-white p-8 shadow-[0_18px_42px_rgba(20,33,61,0.06)]">
<p class="text-[0.72rem] font-semibold uppercase tracking-[0.22em] text-stone-400">Summary</p>
<p class="mt-3 text-sm leading-7 text-stone-500">A compact snapshot of the current order before checkout moves to the native PrestaShop flow.</p>
<div class="mt-8 space-y-3">
<div class="flex items-center justify-between border border-stone-200 bg-[#fcfbf8] px-4 py-3 text-sm text-stone-700">
<span>Total items</span>
<span class="font-semibold text-stone-900">{ fmt.Sprintf("%d", data.Cart.TotalItems) }</span>
</div>
<div class="flex items-center justify-between border border-stone-200 bg-[#fcfbf8] px-4 py-3 text-sm text-stone-700">
<span>Unique lines</span>
<span class="font-semibold text-stone-900">{ fmt.Sprintf("%d", len(data.Cart.Items)) }</span>
</div>
<div class="flex items-center justify-between border border-stone-200 bg-[#fcfbf8] px-4 py-3 text-sm text-stone-700">
<span>Subtotal net</span>
<span class="font-semibold text-stone-900">{ moneyWithCurrency(data.Cart.Subtotal, cartCurrencySign(data), cartCurrencyCode(data)) }</span>
</div>
<div class="flex items-center justify-between border border-amber-200 bg-[#fff7e7] px-5 py-4 text-lg font-semibold text-stone-900">
<span>Subtotal gross</span>
<span>{ moneyWithCurrency(data.Cart.SubtotalTaxIncl, cartCurrencySign(data), cartCurrencyCode(data)) }</span>
</div>
</div>
<a class="mt-8 inline-flex w-full items-center justify-center bg-amber-500 px-5 py-3.5 text-sm font-semibold uppercase tracking-[0.22em] text-white transition hover:bg-amber-600" href={ data.ShopBaseURL + "/order" }>
Checkout in PrestaShop
</a>
<a class="mt-3 inline-flex w-full items-center justify-center border border-stone-300 px-5 py-3 text-xs font-semibold uppercase tracking-[0.24em] text-stone-700 transition hover:border-amber-500 hover:text-amber-600" href="/">
Continue browsing
</a>
</div>
</aside>
</section>
</div>
</main>
}
}