feat(loyalty): translatable categories + mandatory on earn points
Some checks failed
Some checks failed
- Add name_translations JSON column to StoreTransactionCategory
(migration loyalty_008). Stores {"en": "Men", "fr": "Hommes", ...}.
Model has get_translated_name(lang) helper.
- Admin CRUD form now has FR/DE/LB translation inputs alongside the
default name.
- Points earn: category_id is now mandatory when the store has
active categories configured. Returns CATEGORY_REQUIRED error.
- Stamps: category remains optional (quick tap workflow).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -231,21 +231,38 @@
|
||||
</div>
|
||||
|
||||
<!-- Add category inline form -->
|
||||
<div x-show="showAddCategory" class="mb-4 p-3 border border-purple-200 dark:border-purple-800 rounded-lg bg-purple-50 dark:bg-purple-900/20">
|
||||
<div class="flex items-end gap-3">
|
||||
<div class="flex-1">
|
||||
<label class="block text-xs font-medium text-gray-600 dark:text-gray-400 mb-1">{{ _('loyalty.common.name') }}</label>
|
||||
<input type="text" x-model="newCategoryName" maxlength="100"
|
||||
<div x-show="showAddCategory" class="mb-4 p-4 border border-purple-200 dark:border-purple-800 rounded-lg bg-purple-50 dark:bg-purple-900/20">
|
||||
<div class="grid gap-3 md:grid-cols-2 mb-3">
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-gray-600 dark:text-gray-400 mb-1">Name (default)</label>
|
||||
<input type="text" x-model="newCategoryName" maxlength="100" placeholder="e.g. Men"
|
||||
class="w-full px-3 py-2 text-sm border border-gray-300 dark:border-gray-600 rounded-lg dark:bg-gray-700 dark:text-gray-300">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-gray-600 dark:text-gray-400 mb-1">French (FR)</label>
|
||||
<input type="text" x-model="newCategoryTranslations.fr" maxlength="100" placeholder="e.g. Hommes"
|
||||
class="w-full px-3 py-2 text-sm border border-gray-300 dark:border-gray-600 rounded-lg dark:bg-gray-700 dark:text-gray-300">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-gray-600 dark:text-gray-400 mb-1">German (DE)</label>
|
||||
<input type="text" x-model="newCategoryTranslations.de" maxlength="100" placeholder="e.g. Herren"
|
||||
class="w-full px-3 py-2 text-sm border border-gray-300 dark:border-gray-600 rounded-lg dark:bg-gray-700 dark:text-gray-300">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-gray-600 dark:text-gray-400 mb-1">Luxembourgish (LB)</label>
|
||||
<input type="text" x-model="newCategoryTranslations.lb" maxlength="100" placeholder="e.g. Hären"
|
||||
class="w-full px-3 py-2 text-sm border border-gray-300 dark:border-gray-600 rounded-lg dark:bg-gray-700 dark:text-gray-300">
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-end gap-3">
|
||||
<button @click="showAddCategory = false; newCategoryName = ''; newCategoryTranslations = {fr:'',de:'',lb:''}" type="button"
|
||||
class="px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 dark:bg-gray-800 dark:text-gray-300 dark:border-gray-600">
|
||||
{{ _('loyalty.common.cancel') }}
|
||||
</button>
|
||||
<button @click="createCategory()" :disabled="!newCategoryName"
|
||||
class="px-4 py-2 text-sm font-medium text-white bg-purple-600 rounded-lg hover:bg-purple-700 disabled:opacity-50">
|
||||
{{ _('loyalty.common.save') }}
|
||||
</button>
|
||||
<button @click="showAddCategory = false; newCategoryName = ''" type="button"
|
||||
class="px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 dark:bg-gray-800 dark:text-gray-300 dark:border-gray-600">
|
||||
{{ _('loyalty.common.cancel') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user