From 84cd291dc2e942793fadf97c8f1c7f2f6f4225d2 Mon Sep 17 00:00:00 2001 From: Kavehhn174 Date: Sat, 15 Aug 2026 22:55:54 +0330 Subject: [PATCH] fix(settings): keep extra SMS variables after save Avoid Vue's reserved slot field on the variable dropdown so newly added rows survive save. --- src/views/settings/SettingsView.vue | 67 ++++++++++++++++------------- 1 file changed, 38 insertions(+), 29 deletions(-) diff --git a/src/views/settings/SettingsView.vue b/src/views/settings/SettingsView.vue index 18d3852..7b0fa7f 100644 --- a/src/views/settings/SettingsView.vue +++ b/src/views/settings/SettingsView.vue @@ -95,7 +95,7 @@ v-model="variable.slot" :options="getAvailableSlots(template.key)" optionLabel="label" - optionValue="slot" + optionValue="value" placeholder="انتخاب مقدار داده" class="w-full text-sm" @change="onSlotChange(template.key, vIdx)" @@ -283,30 +283,30 @@ const importResult = ref(null); const TEMPLATE_SLOT_DEFS = { accountCreated: [ - { slot: 'username', label: 'نام کاربری', defaultName: 'user' }, - { slot: 'password', label: 'رمز عبور', defaultName: 'password' }, - { slot: 'fullName', label: 'نام و نام خانوادگی', defaultName: 'name' }, - { slot: 'phoneNumber', label: 'شماره همراه', defaultName: 'mobile' } + { value: 'username', label: 'نام کاربری', defaultName: 'user' }, + { value: 'password', label: 'رمز عبور', defaultName: 'password' }, + { value: 'fullName', label: 'نام و نام خانوادگی', defaultName: 'name' }, + { value: 'phoneNumber', label: 'شماره همراه', defaultName: 'mobile' } ], classRegistered: [ - { slot: 'className', label: 'نام کلاس', defaultName: 'className' }, - { slot: 'courseName', label: 'نام دوره', defaultName: 'courseName' }, - { slot: 'fullName', label: 'نام کارآموز', defaultName: 'fullName' }, - { slot: 'phoneNumber', label: 'شماره همراه', defaultName: 'mobile' } + { value: 'className', label: 'نام کلاس', defaultName: 'className' }, + { value: 'courseName', label: 'نام دوره', defaultName: 'courseName' }, + { value: 'fullName', label: 'نام کارآموز', defaultName: 'fullName' }, + { value: 'phoneNumber', label: 'شماره همراه', defaultName: 'mobile' } ], classReminder: [ - { slot: 'className', label: 'نام کلاس', defaultName: 'className' }, - { slot: 'time', label: 'ساعت برگزاری', defaultName: 'time' }, - { slot: 'place', label: 'مکان برگزاری', defaultName: 'place' }, - { slot: 'courseName', label: 'نام دوره', defaultName: 'courseName' }, - { slot: 'fullName', label: 'نام کاربر', defaultName: 'fullName' }, - { slot: 'phoneNumber', label: 'شماره همراه', defaultName: 'mobile' } + { value: 'className', label: 'نام کلاس', defaultName: 'className' }, + { value: 'time', label: 'ساعت برگزاری', defaultName: 'time' }, + { value: 'place', label: 'مکان برگزاری', defaultName: 'place' }, + { value: 'courseName', label: 'نام دوره', defaultName: 'courseName' }, + { value: 'fullName', label: 'نام کاربر', defaultName: 'fullName' }, + { value: 'phoneNumber', label: 'شماره همراه', defaultName: 'mobile' } ], invoiceCreated: [ - { slot: 'amount', label: 'مبلغ صورتحساب (تومان)', defaultName: 'PAYMENT_PRICE' }, - { slot: 'fullName', label: 'نام کارآموز', defaultName: 'FULLNAME' }, - { slot: 'course', label: 'نام دوره / کلاس', defaultName: 'COURSE' }, - { slot: 'phoneNumber', label: 'شماره همراه', defaultName: 'MOBILE' } + { value: 'amount', label: 'مبلغ صورتحساب (تومان)', defaultName: 'PAYMENT_PRICE' }, + { value: 'fullName', label: 'نام کارآموز', defaultName: 'FULLNAME' }, + { value: 'course', label: 'نام دوره / کلاس', defaultName: 'COURSE' }, + { value: 'phoneNumber', label: 'شماره همراه', defaultName: 'MOBILE' } ] }; @@ -316,7 +316,7 @@ const getAvailableSlots = (templateKey) => { const getSlotDefaultName = (templateKey, slotKey) => { const slots = getAvailableSlots(templateKey); - const found = slots.find((s) => s.slot === slotKey); + const found = slots.find((s) => s.value === slotKey); return found?.defaultName || ''; }; @@ -341,15 +341,18 @@ const onSlotChange = (templateKey, vIdx) => { const addVariable = (templateKey) => { const form = templateForm.value[templateKey]; if (!form) return; + if (!Array.isArray(form.variables)) { + form.variables = []; + } const availableSlots = getAvailableSlots(templateKey); - const existingSlots = new Set((form.variables || []).map((v) => v.slot)); - const unusedSlot = availableSlots.find((s) => !existingSlots.has(s.slot)); - const selectedSlot = unusedSlot || availableSlots[0] || { slot: 'amount', defaultName: 'PAYMENT_PRICE' }; + const existingSlots = new Set(form.variables.map((v) => v.slot)); + const unusedSlot = availableSlots.find((s) => !existingSlots.has(s.value)); + const selectedSlot = unusedSlot || availableSlots[0] || { value: 'amount', defaultName: 'PAYMENT_PRICE' }; form.variables.push({ id: nextVarId(), - slot: selectedSlot.slot, + slot: selectedSlot.value, name: selectedSlot.defaultName || '' }); }; @@ -448,16 +451,19 @@ const confirmImport = () => { const emptyFormEntry = (template) => { const slots = getAvailableSlots(template?.key); let vars = []; - if (Array.isArray(template?.variables) && template.variables.length > 0) { - vars = template.variables.map((variable) => ({ + const incomingVars = Array.isArray(template?.variables) + ? template.variables + : Object.values(template?.variables || {}); + if (incomingVars.length > 0) { + vars = incomingVars.map((variable) => ({ id: nextVarId(), - slot: variable.slot || slots[0]?.slot || 'amount', + slot: variable.slot || slots[0]?.value || 'amount', name: variable.name || getSlotDefaultName(template?.key, variable.slot) || '' })); } else if (!template?.variables) { vars = slots.map((s) => ({ id: nextVarId(), - slot: s.slot, + slot: s.value, name: s.defaultName })); } @@ -497,9 +503,12 @@ const saveSmsTemplates = async () => { const smsTemplatesPayload = {}; smsTemplates.value.forEach((template) => { const entry = templateForm.value[template.key] || emptyFormEntry(template); + const rawVariables = Array.isArray(entry.variables) + ? entry.variables + : Object.values(entry.variables || {}); smsTemplatesPayload[template.key] = { templateId: String(entry.templateId || '').trim(), - variables: (entry.variables || []) + variables: rawVariables .filter((v) => v && v.slot) .map((v) => { const raw = String(v.name || '').trim().replace(/^#+|#+$/g, '');