fix(campaigns/wizard): template dropdowns now show non-suffixed templates + refresh

Two issues with the per-language template dropdowns:

1. Strict filter — only -fr / -en templates appeared. Anyone naming a
   template gift-email-test or gift-email-es (no recognized language
   suffix) saw nothing show up in either dropdown.

2. Loaded once on mount — creating a template in another tab and
   switching back to a wizard already open kept showing the stale list.

Fix:
- Templates without a -fr / -en suffix are added to BOTH dropdowns
  with a "· sans suffixe de langue" tag so they're discoverable but
  visually distinct from the recommended ones.
- Sort: matching-suffix templates first, then alphabetical.
- @popup-show triggers a refresh on every dropdown open.
- Visible "refresh" icon in the dropdown's append slot for manual
  triggering without having to close/reopen the popup.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
louispaulb 2026-05-22 09:51:29 -04:00
parent 5330fecf43
commit 1c5241df69

View File

@ -74,13 +74,25 @@
<q-select v-model="params.template_fr" :options="frTemplateOptions"
label="🇫🇷 Template français" outlined dense
class="col-12 col-md-6" emit-value map-options
:loading="loadingTemplates">
<q-tooltip>Template envoyé aux destinataires marqués FR. Tous les templates avec suffixe -fr sont listés.</q-tooltip>
:loading="loadingTemplates"
@popup-show="loadTemplateLists">
<template v-slot:append>
<q-btn flat dense round icon="refresh" size="sm" @click.stop="loadTemplateLists">
<q-tooltip>Rafraîchir la liste des templates</q-tooltip>
</q-btn>
</template>
<q-tooltip>Template envoyé aux destinataires marqués FR. Les templates -fr apparaissent en premier ; tu peux quand même choisir n'importe quel autre template.</q-tooltip>
</q-select>
<q-select v-model="params.template_en" :options="enTemplateOptions"
label="🇺🇸 Template anglais" outlined dense
class="col-12 col-md-6" emit-value map-options
:loading="loadingTemplates">
:loading="loadingTemplates"
@popup-show="loadTemplateLists">
<template v-slot:append>
<q-btn flat dense round icon="refresh" size="sm" @click.stop="loadTemplateLists">
<q-tooltip>Rafraîchir la liste des templates</q-tooltip>
</q-btn>
</template>
<q-tooltip>Template envoyé aux destinataires marqués EN.</q-tooltip>
</q-select>
</div>
@ -489,23 +501,48 @@ const params = ref({
template_en: 'gift-email-en',
})
// Template dropdowns (populated from hub on mount). Filter by language suffix:
// names ending in -fr go to FR list, -en to EN list, others ignored.
// Template dropdowns. Lists EVERY editable gift-email-* template in both
// dropdowns, but sorts so the language-matching ones (-fr / -en suffix)
// appear at the top operator instinct will pick those first while still
// allowing a non-conventionally-named template to be chosen for testing
// or one-off campaigns.
//
// Refreshed on mount AND every time the dropdown popup opens (q-select
// @popup-show), so creating a new template in another tab and switching
// back picks it up without needing a page reload.
const loadingTemplates = ref(false)
const frTemplateOptions = ref([{ label: 'gift-email-fr (défaut)', value: 'gift-email-fr' }])
const enTemplateOptions = ref([{ label: 'gift-email-en (défaut)', value: 'gift-email-en' }])
const frTemplateOptions = ref([{ label: 'gift-email-fr', value: 'gift-email-fr' }])
const enTemplateOptions = ref([{ label: 'gift-email-en', value: 'gift-email-en' }])
async function loadTemplateLists () {
loadingTemplates.value = true
try {
const tpls = await listTemplates()
const buildOption = (t, preferred) => ({
label: preferred ? `${t.name}` : `${t.name} · sans suffixe de langue`,
value: t.name,
size: t.size || 0,
})
const fr = [], en = []
for (const t of tpls) {
const n = t.name || t
if (typeof n !== 'string') continue
const label = `${n}${t.size ? ` (${Math.round(t.size / 1024)} KB)` : ''}`
if (n.endsWith('-fr')) fr.push({ label, value: n })
else if (n.endsWith('-en')) en.push({ label, value: n })
if (!t?.name || typeof t.name !== 'string') continue
if (t.name.endsWith('-fr')) fr.push(buildOption(t, true))
else if (t.name.endsWith('-en')) en.push(buildOption(t, true))
// Templates without -fr/-en suffix (e.g. gift-email-test) are pushed
// to BOTH lists as fallback choices the operator can still pick
// them for either language if they're testing a draft.
else {
fr.push(buildOption(t, false))
en.push(buildOption(t, false))
}
}
// Sort: preferred (no "sans suffixe" tag) first, then alphabetical
const byPriority = (a, b) => {
const aPref = !a.label.includes('sans suffixe')
const bPref = !b.label.includes('sans suffixe')
if (aPref !== bPref) return aPref ? -1 : 1
return a.value.localeCompare(b.value)
}
fr.sort(byPriority); en.sort(byPriority)
if (fr.length) frTemplateOptions.value = fr
if (en.length) enTemplateOptions.value = en
} catch (e) {