"use strict"; // Pantalla de Modulos del movil (la sirve el router propio, karvan_routes.js). // // Los modulos agrupados como en el lanzador, cada uno una fila que se toca entera con // un interruptor, y Guardar siempre a la vista. La tabla de upstream eran 52 filas // con casillas de 16px, unas 11 pantallas. Va en un fichero propio para no tocar // modules_view.js, que es del dev (docs/FRONTERA_UPSTREAM.md). // // El formulario envia a la misma ruta de upstream (/save-modules) con los mismos // nombres de campo (Form), asi que guardar sigue siendo cosa suya. const { button, div, form, h2, h3, input, label, p, section, span } = require("../server/node_modules/hyperaxe"); const { getConfig } = require('../configs/config-manager.js'); const { iconNode } = require('./mobile_icons'); // clave de i18n de cada modulo (modulesLabel / modulesDescription) const STEMS = { agenda: 'Agenda', ai: 'AI', aiNav: 'AINav', emergencies: 'Emergencies', mailing: 'Mailing', rooms: 'Rooms', phone: 'Phone', logistics: 'Logistics', podcasts: 'Podcasts', campaigns: 'Campaigns', audios: 'Audios', banking: 'Banking', bookmarks: 'Bookmarks', calendars: 'Calendars', chats: 'Chats', cipher: 'Cipher', courts: 'Courts', dev: 'Dev', docs: 'Docs', events: 'Events', favorites: 'Favorites', blogs: 'Blogs', fediverse: 'Fediverse', feed: 'Feed', files: 'Files', forum: 'Forum', games: 'Games', graphos: 'Graphos', housing: 'Housing', images: 'Images', industry: 'Industry', invites: 'Invites', jobs: 'Jobs', karvan: 'Karvan', larp: 'Larp', backup: 'Backup', logs: 'Logs', maps: 'Map', market: 'Market', melody: 'Melody', opinions: 'Opinions', pads: 'Pads', parliament: 'Parliament', pixelia: 'Pixelia', polls: 'Polls', projects: 'Projects', reports: 'Reports', school: 'School', shops: 'Shops', tags: 'Tags', tasks: 'Tasks', torrents: 'Torrents', transfers: 'Transfers', trending: 'Trending', tribes: 'Tribes', videos: 'Videos', votes: 'Votations', wallet: 'Wallet', wiki: 'Wiki' }; // los que no van en el movil (los apaga tambien /save-modules) const MOBILE_UNAVAILABLE = ['ai', 'aiNav', 'dev', 'games', 'logs', 'maps', 'pixelia']; const moduleLabel = (i18n, name) => i18n[`modules${STEMS[name]}Label`] || name; const mobileModulesView = (opts = {}) => { const { template, i18n, LAUNCHER_GROUPS } = require('./main_views'); const config = getConfig().modules || {}; const visible = Object.keys(STEMS) .filter(name => !MOBILE_UNAVAILABLE.includes(name)) .map(name => ({ name, label: moduleLabel(i18n, name), description: i18n[`modules${STEMS[name]}Description`] || '' })) .sort((x, y) => String(x.label).localeCompare(String(y.label), undefined, { sensitivity: 'base' })); const isOn = (m) => config[`${m.name}Mod`] === 'on'; // grupos del lanzador; Industria va con la economia y lo demas, al final const groupOf = {}; (LAUNCHER_GROUPS || []).forEach(g => g.mods.forEach(m => { if (m.mod) groupOf[m.mod.replace(/Mod$/, '')] = g; })); const economy = (LAUNCHER_GROUPS || []).find(g => g.id === 'economy'); if (economy && !groupOf.industry) groupOf.industry = economy; const groups = []; const byId = {}; visible.forEach(mod => { const g = groupOf[mod.name] || { id: 'other', titleKey: 'menuTools' }; if (!byId[g.id]) { byId[g.id] = { g, mods: [] }; groups.push(byId[g.id]); } byId[g.id].mods.push(mod); }); const order = (LAUNCHER_GROUPS || []).map(g => g.id); const rank = (id) => { const i = order.indexOf(id); return i === -1 ? order.length : i; }; groups.sort((x, y) => rank(x.g.id) - rank(y.g.id)); const blocked = opts.blocked && visible.find(m => m.name === opts.blocked.mod); const blockedBox = blocked ? div({ class: 'module-blocked' }, iconNode('module-blocked-ico', blocked.name), p({ class: 'module-blocked-text' }, String(i18n.moduleBlockedText || '{name} is turned off.').replace('{name}', blocked.label)), form({ method: 'POST', action: '/modules/enable' }, input({ type: 'hidden', name: 'mod', value: blocked.name }), input({ type: 'hidden', name: 'returnTo', value: opts.blocked.path || `/${blocked.name}` }), button({ type: 'submit', class: 'create-button' }, String(i18n.moduleBlockedAction || 'Turn on {name}').replace('{name}', blocked.label)) ) ) : null; return template( i18n.modules, section(div({ class: 'tags-header module-header-line' }, h2(i18n.modulesViewTitle), p(String(i18n.modulesOnCount || '{on} of {total} sections on') .replace('{on}', visible.filter(isOn).length).replace('{total}', visible.length)) )), blockedBox, opts.saved ? p({ class: 'module-saved', role: 'status' }, i18n.modulesSaved || 'Saved.') : null, section( form({ action: '/save-modules', method: 'post', class: 'module-switches' }, ...groups.map(({ g, mods }) => div({ class: 'module-group' }, h3({ class: 'module-group-title' }, i18n[g.titleKey] || g.id), ...mods.map(mod => label({ class: 'module-switch', for: `${mod.name}Mod` }, iconNode('module-switch-ico', mod.name), span({ class: 'module-switch-text' }, span({ class: 'module-switch-name' }, mod.label), span({ class: 'module-switch-desc' }, mod.description) ), input({ type: 'checkbox', role: 'switch', id: `${mod.name}Mod`, name: `${mod.name}Form`, value: 'on', class: 'switch-input', checked: isOn(mod) ? true : undefined }) )) )), div({ class: 'module-save-bar' }, button({ type: 'submit', class: 'create-button' }, i18n.saveSettings) ) ) ) ); }; module.exports = { mobileModulesView, MOBILE_UNAVAILABLE, STEMS };