now products have different options, like different parameters
This commit is contained in:
@@ -18,38 +18,95 @@
|
||||
{{ ui::csrf_field() }}
|
||||
|
||||
{% if product %}
|
||||
{% set v_name = product.name %}{% set v_price = product.price %}{% set v_currency = product.currency %}{% set v_stock = product.stock %}{% set v_sku = product.sku | default(value="") %}{% set v_desc = product.description | default(value="") %}{% set v_pub = product.published %}
|
||||
{% set v_name = product.name %}{% set v_currency = product.currency %}{% set v_desc = product.description | default(value="") %}{% set v_pub = product.published %}
|
||||
{% else %}
|
||||
{% set v_name = "" %}{% set v_price = "" %}{% set v_currency = "EUR" %}{% set v_stock = 0 %}{% set v_sku = "" %}{% set v_desc = "" %}{% set v_pub = false %}
|
||||
{% set v_name = "" %}{% set v_currency = "EUR" %}{% set v_desc = "" %}{% set v_pub = false %}
|
||||
{% endif %}
|
||||
{% set inp = "w-full rounded-radius border border-outline bg-surface-alt px-3 py-2 text-sm text-on-surface focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary dark:border-outline-dark dark:bg-surface-dark-alt/50 dark:text-on-surface-dark dark:focus-visible:outline-primary-dark" %}
|
||||
{% set sublabel = "text-xs font-medium text-on-surface/70 dark:text-on-surface-dark/70" %}
|
||||
|
||||
<div class="space-y-1.5">
|
||||
<label for="name" class="text-sm font-medium text-on-surface-strong dark:text-on-surface-dark-strong">{{ t(key="name", lang=lang | default(value='sk')) }}</label>
|
||||
{{ ui::input(name="name", id="name", required=true, value=v_name) }}
|
||||
</div>
|
||||
|
||||
<div class="grid gap-5 sm:grid-cols-2">
|
||||
<div class="space-y-1.5">
|
||||
<label for="price" class="text-sm font-medium text-on-surface-strong dark:text-on-surface-dark-strong">{{ t(key="price", lang=lang | default(value='sk')) }}</label>
|
||||
{{ ui::input(name="price", id="price", required=true, value=v_price, placeholder="0.00", attrs='inputmode="decimal"') }}
|
||||
</div>
|
||||
<div class="space-y-1.5">
|
||||
<label for="currency" class="text-sm font-medium text-on-surface-strong dark:text-on-surface-dark-strong">{{ t(key="currency", lang=lang | default(value='sk')) }}</label>
|
||||
{{ ui::input(name="currency", id="currency", value=v_currency, attrs='maxlength="3"', extra="uppercase") }}
|
||||
</div>
|
||||
<div class="space-y-1.5 sm:max-w-[10rem]">
|
||||
<label for="currency" class="text-sm font-medium text-on-surface-strong dark:text-on-surface-dark-strong">{{ t(key="currency", lang=lang | default(value='sk')) }}</label>
|
||||
{{ ui::input(name="currency", id="currency", value=v_currency, attrs='maxlength="3"', extra="uppercase") }}
|
||||
</div>
|
||||
|
||||
<div class="grid gap-5 sm:grid-cols-2">
|
||||
<div class="space-y-1.5">
|
||||
<label for="stock" class="text-sm font-medium text-on-surface-strong dark:text-on-surface-dark-strong">{{ t(key="stock", lang=lang | default(value='sk')) }}</label>
|
||||
{{ ui::input(name="stock", id="stock", type="number", value=v_stock, attrs='min="0"') }}
|
||||
</div>
|
||||
<div class="space-y-1.5">
|
||||
<label for="sku" class="text-sm font-medium text-on-surface-strong dark:text-on-surface-dark-strong">{{ t(key="sku", lang=lang | default(value='sk')) }}</label>
|
||||
{{ ui::input(name="sku", id="sku", value=v_sku) }}
|
||||
{# --- Variants / options editor ------------------------------------------- #}
|
||||
{# Each product is sold as one or more variants (a free-text label such as #}
|
||||
{# "10cm x 13cm" or "5ml" plus its own price/stock/sku, and optional public & #}
|
||||
{# business sale prices). Rows are managed client-side; names are indexed #}
|
||||
{# (variants[i][...]) and read back by the controller. #}
|
||||
<script id="variants-data" type="application/json">{{ variants | json_encode() | safe }}</script>
|
||||
<div class="space-y-3" x-data="variantEditor(JSON.parse(document.getElementById('variants-data').textContent))">
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-sm font-medium text-on-surface-strong dark:text-on-surface-dark-strong">{{ t(key="variants-options", lang=lang | default(value='sk')) }}</span>
|
||||
<button type="button" @click="add()"
|
||||
class="rounded-radius border border-outline px-3 py-1.5 text-sm font-medium text-on-surface hover:bg-surface-alt dark:border-outline-dark dark:text-on-surface-dark dark:hover:bg-surface-dark-alt/50">
|
||||
+ {{ t(key="add-option", lang=lang | default(value='sk')) }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<template x-for="(row, i) in rows" :key="i">
|
||||
<div class="grid gap-3 rounded-radius border border-outline bg-surface-alt/40 p-3 sm:grid-cols-12 dark:border-outline-dark dark:bg-surface-dark-alt/30">
|
||||
<input type="hidden" :name="`variants[${i}][id]`" :value="row.id">
|
||||
|
||||
<div class="space-y-1 sm:col-span-5">
|
||||
<label class="{{ sublabel }}">{{ t(key="option-label", lang=lang | default(value='sk')) }}</label>
|
||||
<input :name="`variants[${i}][label]`" x-model="row.label" class="{{ inp }}" placeholder="napr. 10cm x 13cm">
|
||||
</div>
|
||||
<div class="space-y-1 sm:col-span-3">
|
||||
<label class="{{ sublabel }}">{{ t(key="sku", lang=lang | default(value='sk')) }}</label>
|
||||
<input :name="`variants[${i}][sku]`" x-model="row.sku" class="{{ inp }}">
|
||||
</div>
|
||||
<div class="space-y-1 sm:col-span-2">
|
||||
<label class="{{ sublabel }}">{{ t(key="stock", lang=lang | default(value='sk')) }}</label>
|
||||
<input type="number" min="0" :name="`variants[${i}][stock]`" x-model="row.stock" class="{{ inp }}">
|
||||
</div>
|
||||
<div class="flex items-end sm:col-span-2">
|
||||
<button type="button" @click="remove(i)"
|
||||
class="ml-auto rounded-radius px-2 py-2 text-sm text-danger hover:bg-danger/10" title="{{ t(key='delete', lang=lang | default(value='sk')) }}">✕</button>
|
||||
</div>
|
||||
|
||||
<div class="space-y-1 sm:col-span-4">
|
||||
<label class="{{ sublabel }}">{{ t(key="price", lang=lang | default(value='sk')) }}</label>
|
||||
<input :name="`variants[${i}][price]`" x-model="row.price" inputmode="decimal" class="{{ inp }}" placeholder="0.00">
|
||||
</div>
|
||||
<div class="space-y-1 sm:col-span-4">
|
||||
<label class="{{ sublabel }}">{{ t(key="sale-price", lang=lang | default(value='sk')) }}</label>
|
||||
<input :name="`variants[${i}][sale]`" x-model="row.sale" inputmode="decimal" class="{{ inp }}" placeholder="—">
|
||||
</div>
|
||||
<div class="space-y-1 sm:col-span-4">
|
||||
<label class="{{ sublabel }}">{{ t(key="business-price", lang=lang | default(value='sk')) }}</label>
|
||||
<input :name="`variants[${i}][business_sale]`" x-model="row.business_sale" inputmode="decimal" class="{{ inp }}" placeholder="—">
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function variantEditor(initial) {
|
||||
const blank = () => ({ id: '', label: '', sku: '', stock: 0, price: '', sale: '', business_sale: '' });
|
||||
return {
|
||||
rows: (initial || []).map(r => ({
|
||||
id: r.id || '',
|
||||
label: r.label || '',
|
||||
sku: r.sku || '',
|
||||
stock: (r.stock === null || r.stock === undefined) ? 0 : r.stock,
|
||||
price: r.price || '',
|
||||
sale: r.sale || '',
|
||||
business_sale: r.business_sale || '',
|
||||
})),
|
||||
init() { if (this.rows.length === 0) this.add(); },
|
||||
add() { this.rows.push(blank()); },
|
||||
remove(i) { this.rows.splice(i, 1); if (this.rows.length === 0) this.add(); },
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="space-y-1.5">
|
||||
<label for="category_id" class="text-sm font-medium text-on-surface-strong dark:text-on-surface-dark-strong">{{ t(key="category", lang=lang | default(value='sk')) }}</label>
|
||||
<div class="relative">
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
<tr>
|
||||
{{ ui::th(label=t(key="product", lang=lang | default(value='sk'))) }}
|
||||
{{ ui::th(label=t(key="price", lang=lang | default(value='sk'))) }}
|
||||
{{ ui::th(label=t(key="sale-price", lang=lang | default(value='sk'))) }}
|
||||
{{ ui::th(label=t(key="variants-options", lang=lang | default(value='sk'))) }}
|
||||
{{ ui::th(label=t(key="effective-price", lang=lang | default(value='sk'))) }}
|
||||
{{ ui::th(label=t(key="stock", lang=lang | default(value='sk'))) }}
|
||||
{{ ui::th(label=t(key="status", lang=lang | default(value='sk'))) }}
|
||||
@@ -106,15 +106,8 @@
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-4 py-3 tabular-nums">{{ product.regular_price }} {{ product.currency }}</td>
|
||||
<td class="px-4 py-3 tabular-nums">
|
||||
{% if product.on_sale %}
|
||||
<span class="font-medium text-danger">{{ product.sale_price }} {{ product.currency }}</span>
|
||||
<span class="ml-1 text-xs text-on-surface/60 dark:text-on-surface-dark/60">(−{{ product.percent_off }}%)</span>
|
||||
{% else %}
|
||||
<span class="text-on-surface/40 dark:text-on-surface-dark/40">—</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="px-4 py-3 tabular-nums">{% if product.has_options %}{{ t(key="from-price", price=product.regular_price, lang=lang | default(value='sk')) }}{% else %}{{ product.regular_price }}{% endif %} {{ product.currency }}</td>
|
||||
<td class="px-4 py-3 tabular-nums">{{ product.variant_count }}</td>
|
||||
<td class="px-4 py-3 tabular-nums">
|
||||
<span id="eff-{{ product.id }}">{{ ui::eff_price(p=product) }}</span>
|
||||
</td>
|
||||
@@ -129,14 +122,6 @@
|
||||
<td class="px-4 py-3">
|
||||
<div class="flex flex-wrap justify-end gap-2">
|
||||
{{ ui::button(variant="outline-secondary", label=t(key="edit", lang=lang | default(value='sk')), href="/admin/catalog/products/" ~ product.id ~ "/edit", size="px-3 py-1.5 text-xs") }}
|
||||
{{ ui::button(variant="outline-secondary", label=t(key="set-discount", lang=lang | default(value='sk')), href="/admin/catalog/products/" ~ product.id ~ "/discount/edit?audience=" ~ audience, size="px-3 py-1.5 text-xs") }}
|
||||
{% if product.on_sale %}
|
||||
<form method="post" action="/admin/catalog/products/{{ product.id }}/discount/remove?audience={{ audience }}"
|
||||
onsubmit="return confirm('{{ t(key="discount-remove-confirm", lang=lang | default(value='sk')) }}')">
|
||||
{{ ui::csrf_field() }}
|
||||
{{ ui::button(variant="outline-danger", label=t(key="remove-discount", lang=lang | default(value='sk')), type="submit", size="px-3 py-1.5 text-xs") }}
|
||||
</form>
|
||||
{% endif %}
|
||||
{{ ui::button(variant="outline-secondary", label=t(key="view", lang=lang | default(value='sk')), href="/shop/" ~ product.slug, size="px-3 py-1.5 text-xs") }}
|
||||
<form method="post" action="/admin/catalog/products/{{ product.id }}/delete"
|
||||
onsubmit="return confirm('{{ t(key="confirm-delete", lang=lang | default(value='sk')) }}')">
|
||||
|
||||
Reference in New Issue
Block a user