feat(promo): enforce active + max_uses, validate endpoint, codes hidden from public (v1.6.1-aio.12) #45

Merged
padreug merged 3 commits from feat/promo-codes into main 2026-09-13 16:54:51 +00:00
3 changed files with 31 additions and 4 deletions
Showing only changes of commit 07519bec1b - Show all commits

feat(admin): max uses column + used count in the promo editor

The Quasar editor gains a "Max uses" input per code (blank = unlimited,
normalised to null on save) and shows "Used n / max" from the derived
count. The public buy page's Clear button now also clears the promo field.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ByAwHU4pRnyE58YocQvAas
Padreug 2026-09-10 12:19:44 +02:00

View file

@ -94,6 +94,7 @@ window.PageEventsDisplay = {
this.formDialog.data.email = '' this.formDialog.data.email = ''
this.formDialog.data.refund = '' this.formDialog.data.refund = ''
this.formDialog.data.nostr_identifier = '' this.formDialog.data.nostr_identifier = ''
this.formDialog.data.promo_code = ''
this.formDialog.data.payment_method = this.formDialog.data.payment_method =
this.paymentMethods[0] || 'lightning' this.paymentMethods[0] || 'lightning'
}, },

View file

@ -526,7 +526,9 @@ window.PageEvents = {
.filter(code => code.code?.trim() !== '') .filter(code => code.code?.trim() !== '')
.map(code => ({ .map(code => ({
...code, ...code,
code: code.code.trim().toUpperCase() code: code.code.trim().toUpperCase(),
// blank / 0 = unlimited; used_count is derived server-side
max_uses: code.max_uses ? Number(code.max_uses) : null
})) }))
} }
const methods = data.extra?.payment_methods || [] const methods = data.extra?.payment_methods || []

View file

@ -729,12 +729,22 @@
class="row q-col-gutter-sm q-mt-md" class="row q-col-gutter-sm q-mt-md"
> >
<q-input <q-input
class="col-8" class="col-6"
filled filled
dense dense
v-model.trim="formDialog.data.extra.promo_codes[index].code" v-model.trim="formDialog.data.extra.promo_codes[index].code"
type="text" type="text"
label="Promo Code" label="Promo Code"
:hint="
formDialog.data.extra.promo_codes[index].used_count
? 'Used ' +
formDialog.data.extra.promo_codes[index].used_count +
(formDialog.data.extra.promo_codes[index].max_uses
? ' / ' +
formDialog.data.extra.promo_codes[index].max_uses
: '')
: ''
"
> >
<template v-slot:before> <template v-slot:before>
<q-checkbox <q-checkbox
@ -755,7 +765,7 @@
</template> </template>
</q-input> </q-input>
<q-input <q-input
class="col-4" class="col-3"
filled filled
dense dense
v-model.number=" v-model.number="
@ -765,6 +775,19 @@
label="Discount (%)" label="Discount (%)"
min="0" min="0"
max="100" max="100"
></q-input>
<q-input
class="col-3"
filled
dense
v-model.number="
formDialog.data.extra.promo_codes[index].max_uses
"
type="number"
label="Max uses"
placeholder="∞"
min="1"
hint="Blank = unlimited"
> >
<template v-slot:after> <template v-slot:after>
<q-btn <q-btn
@ -783,7 +806,8 @@
formDialog.data.extra.promo_codes.push({ formDialog.data.extra.promo_codes.push({
code: '', code: '',
discount_percent: 0, discount_percent: 0,
active: true active: true,
max_uses: null
}) })
" "
>Add Promo Code</q-btn >Add Promo Code</q-btn