feat(settings): support dynamic number of SMS template variables
This commit is contained in:
@@ -7,7 +7,9 @@ const SMS_TEMPLATE_DEFS = [
|
||||
envKey: 'SMS_TEMPLATE_ACCOUNT_CREATED',
|
||||
slots: [
|
||||
{ key: 'username', label: 'نام کاربری', defaultName: 'user' },
|
||||
{ key: 'password', label: 'رمز عبور', defaultName: 'password' }
|
||||
{ key: 'password', label: 'رمز عبور', defaultName: 'password' },
|
||||
{ key: 'fullName', label: 'نام کاربر', defaultName: 'name' },
|
||||
{ key: 'phoneNumber', label: 'شماره همراه', defaultName: 'mobile' }
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -15,7 +17,10 @@ const SMS_TEMPLATE_DEFS = [
|
||||
label: 'ثبتنام در کلاس',
|
||||
envKey: 'SMS_TEMPLATE_CLASS_REGISTERED',
|
||||
slots: [
|
||||
{ key: 'className', label: 'نام کلاس', defaultName: 'className' }
|
||||
{ key: 'className', label: 'نام کلاس', defaultName: 'className' },
|
||||
{ key: 'courseName', label: 'نام دوره', defaultName: 'courseName' },
|
||||
{ key: 'fullName', label: 'نام کارآموز', defaultName: 'fullName' },
|
||||
{ key: 'phoneNumber', label: 'شماره همراه', defaultName: 'mobile' }
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -24,8 +29,11 @@ const SMS_TEMPLATE_DEFS = [
|
||||
envKey: 'SMS_TEMPLATE_CLASS_REMINDER',
|
||||
slots: [
|
||||
{ key: 'className', label: 'نام کلاس', defaultName: 'className' },
|
||||
{ key: 'courseName', label: 'نام دوره', defaultName: 'courseName' },
|
||||
{ key: 'time', label: 'ساعت', defaultName: 'time' },
|
||||
{ key: 'place', label: 'مکان', defaultName: 'place' }
|
||||
{ key: 'place', label: 'مکان', defaultName: 'place' },
|
||||
{ key: 'fullName', label: 'نام کاربر', defaultName: 'fullName' },
|
||||
{ key: 'phoneNumber', label: 'شماره همراه', defaultName: 'mobile' }
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -35,7 +43,8 @@ const SMS_TEMPLATE_DEFS = [
|
||||
slots: [
|
||||
{ key: 'fullName', label: 'نام کارآموز', defaultName: 'FULLNAME' },
|
||||
{ key: 'amount', label: 'مبلغ', defaultName: 'PAYMENT_PRICE' },
|
||||
{ key: 'course', label: 'نام دوره', defaultName: 'COURSE' }
|
||||
{ key: 'course', label: 'نام دوره', defaultName: 'COURSE' },
|
||||
{ key: 'phoneNumber', label: 'شماره همراه', defaultName: 'MOBILE' }
|
||||
]
|
||||
}
|
||||
];
|
||||
@@ -63,37 +72,53 @@ const sanitizeVariableName = (value) => {
|
||||
return name;
|
||||
};
|
||||
|
||||
const defaultVariableMap = (def) => {
|
||||
const map = {};
|
||||
(def.slots || []).forEach((slot) => {
|
||||
map[slot.key] = slot.defaultName;
|
||||
});
|
||||
return map;
|
||||
const defaultVariablesList = (def) => {
|
||||
return (def?.slots || []).map((slot) => ({
|
||||
slot: slot.key,
|
||||
name: slot.defaultName
|
||||
}));
|
||||
};
|
||||
|
||||
const emptyTemplateEntry = (def) => ({
|
||||
templateId: '',
|
||||
variables: defaultVariableMap(def)
|
||||
variables: defaultVariablesList(def)
|
||||
});
|
||||
|
||||
const normalizeStoredEntry = (raw) => {
|
||||
const normalizeStoredEntry = (raw, def) => {
|
||||
if (raw == null || raw === '') {
|
||||
return { templateId: '', variables: {} };
|
||||
return {
|
||||
templateId: '',
|
||||
variables: def ? defaultVariablesList(def) : []
|
||||
};
|
||||
}
|
||||
if (typeof raw === 'string' || typeof raw === 'number') {
|
||||
return { templateId: String(raw), variables: {} };
|
||||
return {
|
||||
templateId: String(raw),
|
||||
variables: def ? defaultVariablesList(def) : []
|
||||
};
|
||||
}
|
||||
if (typeof raw !== 'object') {
|
||||
return { templateId: '', variables: {} };
|
||||
return {
|
||||
templateId: '',
|
||||
variables: def ? defaultVariablesList(def) : []
|
||||
};
|
||||
}
|
||||
|
||||
let variables = {};
|
||||
if (raw.variables && typeof raw.variables === 'object' && !Array.isArray(raw.variables)) {
|
||||
variables = { ...raw.variables };
|
||||
} else if (Array.isArray(raw.variables)) {
|
||||
raw.variables.forEach((item) => {
|
||||
if (item?.slot) variables[item.slot] = item.name;
|
||||
});
|
||||
let variables = [];
|
||||
if (Array.isArray(raw.variables)) {
|
||||
variables = raw.variables
|
||||
.filter((item) => item && typeof item === 'object' && item.slot)
|
||||
.map((item) => ({
|
||||
slot: String(item.slot).trim(),
|
||||
name: String(item.name || '').trim()
|
||||
}));
|
||||
} else if (raw.variables && typeof raw.variables === 'object') {
|
||||
variables = Object.entries(raw.variables).map(([slot, name]) => ({
|
||||
slot: String(slot).trim(),
|
||||
name: String(name || '').trim()
|
||||
}));
|
||||
} else if (def) {
|
||||
variables = defaultVariablesList(def);
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -102,21 +127,51 @@ const normalizeStoredEntry = (raw) => {
|
||||
};
|
||||
};
|
||||
|
||||
const resolveVariableMap = (def, storedVariables = {}) => {
|
||||
const map = {};
|
||||
(def.slots || []).forEach((slot) => {
|
||||
const sanitized = sanitizeVariableName(storedVariables[slot.key]);
|
||||
map[slot.key] = sanitized || slot.defaultName;
|
||||
});
|
||||
return map;
|
||||
const resolveVariablesList = (def, storedVariables) => {
|
||||
if (!storedVariables) {
|
||||
return defaultVariablesList(def);
|
||||
}
|
||||
|
||||
let list = [];
|
||||
if (Array.isArray(storedVariables)) {
|
||||
list = storedVariables;
|
||||
} else if (typeof storedVariables === 'object') {
|
||||
list = Object.entries(storedVariables).map(([slot, name]) => ({ slot, name }));
|
||||
}
|
||||
|
||||
return list
|
||||
.map((item) => {
|
||||
const slot = String(item.slot || '').trim();
|
||||
if (!slot) return null;
|
||||
const slotDef = (def?.slots || []).find((s) => s.key === slot);
|
||||
const rawName = item.name !== undefined ? item.name : slotDef?.defaultName || '';
|
||||
const sanitized = sanitizeVariableName(rawName);
|
||||
return {
|
||||
slot,
|
||||
name: sanitized || slotDef?.defaultName || slot
|
||||
};
|
||||
})
|
||||
.filter(Boolean);
|
||||
};
|
||||
|
||||
const buildSmsParameters = (variableMap, valuesBySlot) => {
|
||||
return Object.entries(valuesBySlot)
|
||||
.map(([slot, value]) => {
|
||||
const name = String(variableMap?.[slot] || '').trim();
|
||||
const buildSmsParameters = (variables, valuesBySlot = {}) => {
|
||||
let list = [];
|
||||
if (Array.isArray(variables)) {
|
||||
list = variables;
|
||||
} else if (variables && typeof variables === 'object') {
|
||||
list = Object.entries(variables).map(([slot, name]) => ({ slot, name }));
|
||||
}
|
||||
|
||||
return list
|
||||
.map((item) => {
|
||||
const name = sanitizeVariableName(item?.name);
|
||||
if (!name) return null;
|
||||
return { name, value: String(value ?? '') };
|
||||
const slot = item?.slot;
|
||||
const value = slot ? valuesBySlot?.[slot] : '';
|
||||
return {
|
||||
name,
|
||||
value: String(value ?? '')
|
||||
};
|
||||
})
|
||||
.filter(Boolean);
|
||||
};
|
||||
@@ -127,9 +182,9 @@ module.exports = {
|
||||
envFallbackFor,
|
||||
sanitizeTemplateId,
|
||||
sanitizeVariableName,
|
||||
defaultVariableMap,
|
||||
defaultVariablesList,
|
||||
emptyTemplateEntry,
|
||||
normalizeStoredEntry,
|
||||
resolveVariableMap,
|
||||
resolveVariablesList,
|
||||
buildSmsParameters
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user