feat: implementacion de dashboards por rol, soporte de clases virtuales concurrentes en importador de sheets y cartelera del dia

This commit is contained in:
2026-09-18 23:04:48 -03:00
parent 47b50ede7e
commit 1080acd43a
240 changed files with 8354 additions and 8886 deletions
+84
View File
@@ -0,0 +1,84 @@
const nunjucks = require('nunjucks');
/**
* Creates a proxy-based form mock compatible with WTForms syntax used in Jinja2 / Nunjucks templates.
* Supports:
* - form.hidden_tag()
* - form.<field_name>(class="...", id="...", placeholder="...")
* - form.<field_name>.label(class="...")
* - form.<field_name>.errors -> []
*/
function createFormMock(initialData = {}, optionsMap = {}) {
const hidden_tag = () => new nunjucks.runtime.SafeString('<input type="hidden" name="csrf_token" value="mock-csrf-token">');
return new Proxy({ hidden_tag }, {
get(target, prop) {
if (prop in target) return target[prop];
if (typeof prop === 'symbol' || prop === 'inspect' || prop === 'toString') return undefined;
const fieldFn = function(attrs = {}) {
let attrPairs = [];
for (const [k, v] of Object.entries(attrs)) {
if (v !== undefined && v !== null && v !== false) {
attrPairs.push(`${k}="${String(v).replace(/"/g, '&quot;')}"`);
}
}
const attrStr = attrPairs.length ? ' ' + attrPairs.join(' ') : '';
const val = initialData[prop] !== undefined ? initialData[prop] : '';
// Select dropdown
if (optionsMap[prop]) {
const opts = optionsMap[prop].map(o => {
const optVal = o.value !== undefined ? o.value : (o.id !== undefined ? o.id : o);
const optText = o.text !== undefined ? o.text : (o.name !== undefined ? o.name : (o.label !== undefined ? o.label : optVal));
const selected = String(optVal) === String(val) ? ' selected' : '';
return ` <option value="${optVal}"${selected}>${optText}</option>`;
}).join('\n');
return new nunjucks.runtime.SafeString(`<select name="${prop}"${attrStr}>\n${opts}\n</select>`);
}
// Textarea
if (prop === 'description' || prop === 'notes') {
return new nunjucks.runtime.SafeString(`<textarea name="${prop}"${attrStr}>${val}</textarea>`);
}
// Checkbox / switch
if (prop === 'is_active') {
const checked = (val === false || val === 'false' || val === 0) ? '' : ' checked';
return new nunjucks.runtime.SafeString(`<input type="checkbox" name="${prop}" value="true"${checked}${attrStr}>`);
}
// Number or datetime or text input
let inputType = 'text';
if (prop === 'capacity' || prop === 'expected_attendees' || prop === 'floors') {
inputType = 'number';
} else if (prop === 'start_time' || prop === 'end_time') {
inputType = 'datetime-local';
}
return new nunjucks.runtime.SafeString(`<input type="${inputType}" name="${prop}" value="${val}"${attrStr}>`);
};
fieldFn.label = function(attrs = {}) {
let attrPairs = [];
for (const [k, v] of Object.entries(attrs)) {
if (v !== undefined && v !== null && v !== false) {
attrPairs.push(`${k}="${String(v).replace(/"/g, '&quot;')}"`);
}
}
const attrStr = attrPairs.length ? ' ' + attrPairs.join(' ') : '';
const labelText = prop.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase());
return new nunjucks.runtime.SafeString(`<label for="${prop}"${attrStr}>${labelText}</label>`);
};
fieldFn.errors = [];
fieldFn.data = initialData[prop] || '';
return fieldFn;
}
});
}
module.exports = {
createFormMock
};