fix(settings): keep extra SMS variables after save
Avoid Vue's reserved slot field on the variable dropdown so newly added rows survive save.
This commit is contained in:
@@ -95,7 +95,7 @@
|
|||||||
v-model="variable.slot"
|
v-model="variable.slot"
|
||||||
:options="getAvailableSlots(template.key)"
|
:options="getAvailableSlots(template.key)"
|
||||||
optionLabel="label"
|
optionLabel="label"
|
||||||
optionValue="slot"
|
optionValue="value"
|
||||||
placeholder="انتخاب مقدار داده"
|
placeholder="انتخاب مقدار داده"
|
||||||
class="w-full text-sm"
|
class="w-full text-sm"
|
||||||
@change="onSlotChange(template.key, vIdx)"
|
@change="onSlotChange(template.key, vIdx)"
|
||||||
@@ -283,30 +283,30 @@ const importResult = ref(null);
|
|||||||
|
|
||||||
const TEMPLATE_SLOT_DEFS = {
|
const TEMPLATE_SLOT_DEFS = {
|
||||||
accountCreated: [
|
accountCreated: [
|
||||||
{ slot: 'username', label: 'نام کاربری', defaultName: 'user' },
|
{ value: 'username', label: 'نام کاربری', defaultName: 'user' },
|
||||||
{ slot: 'password', label: 'رمز عبور', defaultName: 'password' },
|
{ value: 'password', label: 'رمز عبور', defaultName: 'password' },
|
||||||
{ slot: 'fullName', label: 'نام و نام خانوادگی', defaultName: 'name' },
|
{ value: 'fullName', label: 'نام و نام خانوادگی', defaultName: 'name' },
|
||||||
{ slot: 'phoneNumber', label: 'شماره همراه', defaultName: 'mobile' }
|
{ value: 'phoneNumber', label: 'شماره همراه', defaultName: 'mobile' }
|
||||||
],
|
],
|
||||||
classRegistered: [
|
classRegistered: [
|
||||||
{ slot: 'className', label: 'نام کلاس', defaultName: 'className' },
|
{ value: 'className', label: 'نام کلاس', defaultName: 'className' },
|
||||||
{ slot: 'courseName', label: 'نام دوره', defaultName: 'courseName' },
|
{ value: 'courseName', label: 'نام دوره', defaultName: 'courseName' },
|
||||||
{ slot: 'fullName', label: 'نام کارآموز', defaultName: 'fullName' },
|
{ value: 'fullName', label: 'نام کارآموز', defaultName: 'fullName' },
|
||||||
{ slot: 'phoneNumber', label: 'شماره همراه', defaultName: 'mobile' }
|
{ value: 'phoneNumber', label: 'شماره همراه', defaultName: 'mobile' }
|
||||||
],
|
],
|
||||||
classReminder: [
|
classReminder: [
|
||||||
{ slot: 'className', label: 'نام کلاس', defaultName: 'className' },
|
{ value: 'className', label: 'نام کلاس', defaultName: 'className' },
|
||||||
{ slot: 'time', label: 'ساعت برگزاری', defaultName: 'time' },
|
{ value: 'time', label: 'ساعت برگزاری', defaultName: 'time' },
|
||||||
{ slot: 'place', label: 'مکان برگزاری', defaultName: 'place' },
|
{ value: 'place', label: 'مکان برگزاری', defaultName: 'place' },
|
||||||
{ slot: 'courseName', label: 'نام دوره', defaultName: 'courseName' },
|
{ value: 'courseName', label: 'نام دوره', defaultName: 'courseName' },
|
||||||
{ slot: 'fullName', label: 'نام کاربر', defaultName: 'fullName' },
|
{ value: 'fullName', label: 'نام کاربر', defaultName: 'fullName' },
|
||||||
{ slot: 'phoneNumber', label: 'شماره همراه', defaultName: 'mobile' }
|
{ value: 'phoneNumber', label: 'شماره همراه', defaultName: 'mobile' }
|
||||||
],
|
],
|
||||||
invoiceCreated: [
|
invoiceCreated: [
|
||||||
{ slot: 'amount', label: 'مبلغ صورتحساب (تومان)', defaultName: 'PAYMENT_PRICE' },
|
{ value: 'amount', label: 'مبلغ صورتحساب (تومان)', defaultName: 'PAYMENT_PRICE' },
|
||||||
{ slot: 'fullName', label: 'نام کارآموز', defaultName: 'FULLNAME' },
|
{ value: 'fullName', label: 'نام کارآموز', defaultName: 'FULLNAME' },
|
||||||
{ slot: 'course', label: 'نام دوره / کلاس', defaultName: 'COURSE' },
|
{ value: 'course', label: 'نام دوره / کلاس', defaultName: 'COURSE' },
|
||||||
{ slot: 'phoneNumber', label: 'شماره همراه', defaultName: 'MOBILE' }
|
{ value: 'phoneNumber', label: 'شماره همراه', defaultName: 'MOBILE' }
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -316,7 +316,7 @@ const getAvailableSlots = (templateKey) => {
|
|||||||
|
|
||||||
const getSlotDefaultName = (templateKey, slotKey) => {
|
const getSlotDefaultName = (templateKey, slotKey) => {
|
||||||
const slots = getAvailableSlots(templateKey);
|
const slots = getAvailableSlots(templateKey);
|
||||||
const found = slots.find((s) => s.slot === slotKey);
|
const found = slots.find((s) => s.value === slotKey);
|
||||||
return found?.defaultName || '';
|
return found?.defaultName || '';
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -341,15 +341,18 @@ const onSlotChange = (templateKey, vIdx) => {
|
|||||||
const addVariable = (templateKey) => {
|
const addVariable = (templateKey) => {
|
||||||
const form = templateForm.value[templateKey];
|
const form = templateForm.value[templateKey];
|
||||||
if (!form) return;
|
if (!form) return;
|
||||||
|
if (!Array.isArray(form.variables)) {
|
||||||
|
form.variables = [];
|
||||||
|
}
|
||||||
const availableSlots = getAvailableSlots(templateKey);
|
const availableSlots = getAvailableSlots(templateKey);
|
||||||
|
|
||||||
const existingSlots = new Set((form.variables || []).map((v) => v.slot));
|
const existingSlots = new Set(form.variables.map((v) => v.slot));
|
||||||
const unusedSlot = availableSlots.find((s) => !existingSlots.has(s.slot));
|
const unusedSlot = availableSlots.find((s) => !existingSlots.has(s.value));
|
||||||
const selectedSlot = unusedSlot || availableSlots[0] || { slot: 'amount', defaultName: 'PAYMENT_PRICE' };
|
const selectedSlot = unusedSlot || availableSlots[0] || { value: 'amount', defaultName: 'PAYMENT_PRICE' };
|
||||||
|
|
||||||
form.variables.push({
|
form.variables.push({
|
||||||
id: nextVarId(),
|
id: nextVarId(),
|
||||||
slot: selectedSlot.slot,
|
slot: selectedSlot.value,
|
||||||
name: selectedSlot.defaultName || ''
|
name: selectedSlot.defaultName || ''
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -448,16 +451,19 @@ const confirmImport = () => {
|
|||||||
const emptyFormEntry = (template) => {
|
const emptyFormEntry = (template) => {
|
||||||
const slots = getAvailableSlots(template?.key);
|
const slots = getAvailableSlots(template?.key);
|
||||||
let vars = [];
|
let vars = [];
|
||||||
if (Array.isArray(template?.variables) && template.variables.length > 0) {
|
const incomingVars = Array.isArray(template?.variables)
|
||||||
vars = template.variables.map((variable) => ({
|
? template.variables
|
||||||
|
: Object.values(template?.variables || {});
|
||||||
|
if (incomingVars.length > 0) {
|
||||||
|
vars = incomingVars.map((variable) => ({
|
||||||
id: nextVarId(),
|
id: nextVarId(),
|
||||||
slot: variable.slot || slots[0]?.slot || 'amount',
|
slot: variable.slot || slots[0]?.value || 'amount',
|
||||||
name: variable.name || getSlotDefaultName(template?.key, variable.slot) || ''
|
name: variable.name || getSlotDefaultName(template?.key, variable.slot) || ''
|
||||||
}));
|
}));
|
||||||
} else if (!template?.variables) {
|
} else if (!template?.variables) {
|
||||||
vars = slots.map((s) => ({
|
vars = slots.map((s) => ({
|
||||||
id: nextVarId(),
|
id: nextVarId(),
|
||||||
slot: s.slot,
|
slot: s.value,
|
||||||
name: s.defaultName
|
name: s.defaultName
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@@ -497,9 +503,12 @@ const saveSmsTemplates = async () => {
|
|||||||
const smsTemplatesPayload = {};
|
const smsTemplatesPayload = {};
|
||||||
smsTemplates.value.forEach((template) => {
|
smsTemplates.value.forEach((template) => {
|
||||||
const entry = templateForm.value[template.key] || emptyFormEntry(template);
|
const entry = templateForm.value[template.key] || emptyFormEntry(template);
|
||||||
|
const rawVariables = Array.isArray(entry.variables)
|
||||||
|
? entry.variables
|
||||||
|
: Object.values(entry.variables || {});
|
||||||
smsTemplatesPayload[template.key] = {
|
smsTemplatesPayload[template.key] = {
|
||||||
templateId: String(entry.templateId || '').trim(),
|
templateId: String(entry.templateId || '').trim(),
|
||||||
variables: (entry.variables || [])
|
variables: rawVariables
|
||||||
.filter((v) => v && v.slot)
|
.filter((v) => v && v.slot)
|
||||||
.map((v) => {
|
.map((v) => {
|
||||||
const raw = String(v.name || '').trim().replace(/^#+|#+$/g, '');
|
const raw = String(v.name || '').trim().replace(/^#+|#+$/g, '');
|
||||||
|
|||||||
Reference in New Issue
Block a user