DOING THINGS

This commit is contained in:
Christopher Cookman 2025-12-20 19:49:24 -07:00
parent c5a5e5893b
commit 952fbf5dbc
5 changed files with 251 additions and 87 deletions

45
buttons.json Normal file
View file

@ -0,0 +1,45 @@
{
"COLS": [
"Normal Announcements",
"Emergency Announcements"
],
"ROWS": [
{
"text": "Live Page",
"btnClass": "btn-primary",
"name": "LivePage",
"doubleHeight": true,
"context": {
"context": "custom-emergency.9001.1",
"timeout": 30000,
"cid": "Live Page"
}
},
{
"text": "Emergency Announcement",
"btnClass": "btn-danger",
"name": "EmergencyAnnouncement",
"doubleHeight": true,
"faIcon": "fa-solid fa-octagon",
"context": {
"context": "custom-emergency.9002.1",
"timeout": 30000,
"cid": "Emergency Announcement"
}
},
{},
{
"text": "Weather Alert",
"btnClass": "btn-warning",
"name": "WeatherAlert",
"faIcon": "fa-regular fa-cloud-bolt",
"doubleHeight": false,
"context": {
"context": "custom-emergency.9003.1",
"timeout": 30000,
"cid": "\"Weather Alert\" <9000>",
"dial": "9000"
}
}
]
}

64
index.ejs Normal file
View file

@ -0,0 +1,64 @@
<%
// buttons is provided to this template
const numCols = (buttons && buttons.COLS && buttons.COLS.length) || 1;
const colWidth = (12 / numCols) >= 1 ? Math.floor(12 / numCols) : null;
// chunk the flat ROWS array into logical rows of numCols items
const chunks = [];
for (let i = 0; i < (buttons.ROWS || []).length; i += numCols) {
chunks.push((buttons.ROWS || []).slice(i, i + numCols));
}
%>
<style>
.btn-grid { gap: 0.5rem; }
.btn-grid .cell { display: flex; align-items: stretch; }
.btn-grid .blank-cell { height: 3.75rem; } /* placeholder height */
.btn-grid .double-height { height: 9.5rem; } /* adjust to taste */
.btn-grid .cell > button { width: 100%; white-space: normal; }
</style>
<div class="container">
<!-- column headers -->
<div class="row mb-2">
<% for (let c = 0; c < numCols; c++) { %>
<div class="<%= colWidth ? 'col-' + colWidth : 'col' %>">
<h5><%= buttons.COLS[c] || '' %></h5>
</div>
<% } %>
</div>
<!-- button grid -->
<div class="btn-grid">
<% chunks.forEach(function(row) { %>
<div class="row mb-2">
<% for (let c = 0; c < numCols; c++) {
const cell = row[c];
const isEmpty = !cell || Object.keys(cell).length === 0;
const colClass = '<%= colWidth ? "col-' + colWidth + '" : "col" %>'; // placeholder for layout below
%>
<div class="<%= colWidth ? 'col-' + colWidth : 'col' %> cell">
<% if (isEmpty) { %>
<div class="blank-cell"></div>
<% } else {
// build data attributes from context if present
const ctx = cell.context || {};
const dataAttrs = [];
if (ctx.context) dataAttrs.push('data-context="' + ctx.context + '"');
if (ctx.timeout) dataAttrs.push('data-timeout="' + ctx.timeout + '"');
if (ctx.cid) dataAttrs.push('data-cid="' + ctx.cid + '"');
if (ctx.dial) dataAttrs.push('data-dial="' + ctx.dial + '"');
%>
<button
type="button"
class="btn <%= cell.btnClass || 'btn-secondary' %> <%= cell.doubleHeight ? 'double-height' : '' %>"
name="<%= cell.name || '' %>"
<%= dataAttrs.join(' ') %>
><%= cell.text || '' %></button>
<% } %>
</div>
<% } %>
</div>
<% }); %>
</div>
</div>

View file

@ -3,32 +3,34 @@ const { exec } = require('child_process');
require('dotenv').config();
const contexts = {
"A1": {
context: 'custom-emergency.9001.1',
timeout: 30000,
cid: 'Live Page'
},
"E1": {
context: 'custom-emergency.9002.1',
timeout: 30000,
cid: 'Emergency Live Page'
},
"E2": { // Weather
context: 'custom-emergency.9003.1',
timeout: 30000,
cid: '"Emergency 2" <2100>',
number: process.env.PAGING_ADAPTER_EXT // Direct to page group, no phone needed
}
const phonesCfg = require('./phones.json');
const buttonsCfg = require('./buttons.json');
const contexts = {};
// Generate contexts from buttonsCfg
if (buttonsCfg && buttonsCfg.ROWS) {
buttonsCfg.ROWS.forEach(button => {
if (button.name && button.context) {
contexts[button.name] = {
context: button.context.context,
timeout: button.context.timeout,
cid: button.context.cid,
...(button.context.dial && { dial: button.context.dial })
};
}
});
}
console.log('Generated contexts:', contexts);
function trigCall(pageType, phone) {
// If contexts[pageType] does not exist, return an error
if (!contexts[pageType]) {
throw new Error(`Invalid page type: ${pageType}`);
}
const { context, timeout, cid, number } = contexts[pageType];
const targetNumber = number || phone;
const { context, timeout, cid, dial } = contexts[pageType];
const targetNumber = dial || phone;
if (!targetNumber) {
throw new Error(`Phone number is required for page type: ${pageType}`);
}
@ -90,7 +92,7 @@ function auth(req, res, next) {
}
app.get('/', (req, res) => {
res.render('index', { session: req.session });
res.render('index', { session: req.session, phones: phonesCfg, buttons: require("./buttons.json") });
});
app.post('/trig', async (req, res) => {

6
phones.json Normal file
View file

@ -0,0 +1,6 @@
{
"Front Desk": "2120",
"Cam": "2113",
"Cam 2": "2112",
"Ryan": "2100"
}

View file

@ -1,74 +1,121 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="/assets/css/bootstrap.min.css">
<title>Funny goofy test page!!!!!1!</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="/assets/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/tuta-amb/fontawesome-pro@latest/web/css/all.min.css">
<title>Funny goofy test page!!!!!1!</title>
<style>
.btn-tall { height: 152px; }
.btn-short { height: 76px; }
</style>
</head>
<body>
<div class="position-absolute top-0 start-0 m-3">
<select class="form-select" id="phoneSelect">
<option value="2120">Front Desk</option>
<option value="2113">Cam</option>
<option value="2112">Cam 2</option>
<option value="2100">Ryan</option>
</select>
</div>
<div class="container-fluid d-flex justify-content-center align-items-center min-vh-100">
<div>
<table class="table table-borderless table-sm">
<thead>
<tr>
<th class="text-left"><h3>Normal Announcements</h3></th>
<th class="text-left"><h3>Emergency Announcements</h3></th>
</tr>
</thead>
<tbody>
<tr>
<td class="text-left">
<button class="btn btn-primary mb-1 w-100" name="A1" onclick="triggerAnnouncement(this)" style="height: 76px;">Live Page</button>
</td>
<td class="text-left">
<button class="btn btn-danger mb-1 w-100" name="E1" onclick="triggerAnnouncement(this)" style="height: 76px;">Emergency Live Page</button>
</td>
</tr>
<tr>
<td class="text-left">
<button class="btn btn-success mb-1" name="A2" onclick="triggerAnnouncement(this)">Announcement 2</button>
</td>
<td class="text-left">
<button class="btn btn-warning mb-1" name="E2" onclick="triggerAnnouncement(this)">⛈️ Weather</button>
</td>
</tr>
<tr>
<td class="text-left">
<button class="btn btn-info mb-1" name="A3" onclick="triggerAnnouncement(this)">Announcement 3</button>
</td>
<td class="text-left">
<button class="btn btn-dark mb-1" name="E3" onclick="triggerAnnouncement(this)">Emergency 3</button>
</td>
</tr>
</tbody>
</table>
</div>
<script src="/assets/js/bootstrap.min.js"></script>
<script src="/assets/js/bootstrap.bundle.min.js"></script>
<script src="/assets/js/jquery.min.js"></script>
<script>
function triggerAnnouncement(button) {
const ann = button.getAttribute('name');
const phoneSelect = document.getElementById('phoneSelect');
const phone = phoneSelect.value;
console.log(name)
fetch('/trig', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ pageType: ann, phone: phone })
});
}
</script>
<div class="position-absolute top-0 start-0 m-3">
<select class="form-select" id="phoneSelect">
<% Object.entries(phones).forEach(([name, number])=> { %>
<option value="<%= number %>">
<%= name %>
</option>
<% }); %>
</select>
</div>
<%
// determine columns and chunk rows
const cols = (buttons && buttons.COLS) || [''];
const numCols = Math.max(1, cols.length);
const rowsFlat = (buttons && buttons.ROWS) || [];
const chunks = [];
for (let i = 0; i < rowsFlat.length; i += numCols) {
const slice = rowsFlat.slice(i, i + numCols);
// pad short slice with empty objects so layout stays consistent
while (slice.length < numCols) slice.push({});
chunks.push(slice);
}
%>
<div class="container-fluid d-flex justify-content-center align-items-center min-vh-100">
<div>
<table class="table table-borderless table-sm">
<thead>
<tr>
<% for (let c = 0; c < numCols; c++) { %>
<th class="text-left">
<h3><%= cols[c] || '' %></h3>
</th>
<% } %>
</tr>
</thead>
<tbody>
<% chunks.forEach((row) => { %>
<tr>
<% for (let c = 0; c < numCols; c++) {
const cell = row[c] || {};
const isBlank = Object.keys(cell).length === 0;
%>
<td class="text-left">
<% if (isBlank) { %>
<!-- blank space -->
<% } else {
const ctx = cell.context || {};
%>
<button
class="btn <%= cell.btnClass || 'btn-secondary' %> mb-1 w-100 <%= cell.doubleHeight ? 'btn-tall' : 'btn-short' %> fw-bold fs-4 <%= cell.faIcon ? 'd-flex justify-content-center align-items-center' : '' %>"
name="<%= cell.name || '' %>"
onclick="triggerAnnouncement(this)"
<% if (ctx.context) { %> data-context="<%= ctx.context %>" <% } %>
<% if (ctx.timeout) { %> data-timeout="<%= ctx.timeout %>" <% } %>
<% if (ctx.cid) { %> data-cid="<%= ctx.cid %>" <% } %>
<% if (ctx.dial) { %> data-dial="<%= ctx.dial %>" <% } %>
>
<% if (cell.faIcon) { %>
<i class="<%= cell.faIcon %> me-2" <% if (cell.faColor) { %> style="color: <%= cell.faColor %>" <% } %>></i>
<span><%= cell.text || '' %></span>
<% } else { %>
<%= cell.text || '' %>
<% } %>
</button>
<% } %>
</td>
<% } %>
</tr>
<% }); %>
</tbody>
</table>
</div>
</div>
<script src="/assets/js/bootstrap.min.js"></script>
<script src="/assets/js/bootstrap.bundle.min.js"></script>
<script src="/assets/js/jquery.min.js"></script>
<script>
function triggerAnnouncement(button) {
const ann = button.getAttribute('name');
const phoneSelect = document.getElementById('phoneSelect');
const phone = phoneSelect.value;
console.log(ann);
// send the button's context attrs if you want them server-side
const payload = {
pageType: ann,
phone: phone,
context: {
context: button.dataset.context,
timeout: button.dataset.timeout,
cid: button.dataset.cid,
dial: button.dataset.dial
}
};
fetch('/trig', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
}
</script>
</body>
</html>