152 lines
9.8 KiB
Plaintext
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>
|
|
}
|
|
}
|