Skip to content

Commit 053ce60

Browse files
committed
Edit commission view, edit commission, add IDs to all inputs
1 parent 513b2f6 commit 053ce60

5 files changed

Lines changed: 171 additions & 5 deletions

File tree

frontend/pages/create.ejs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
<h3><%= field.label %><%= field.required ? '*' : '' %></h3>
88
<p><%= field.required ? 'Required' : 'Optional' %><%= field.description ? ': ' + field.description : '' %></p>
99
<% if (field.type === 'textarea') { %>
10-
<textarea placeholder="<%= field.placeholder || '' %>"></textarea>
10+
<textarea id="<%= field.id %>Textarea" placeholder="<%= field.placeholder || '' %>"></textarea>
1111
<% } else if (field.type === 'checkbox') { %>
12-
<input type="checkbox" class="hidden">
12+
<input id="<%= field.id %>Input" type="checkbox" class="hidden">
1313
<div class="checkbox" change="cms">|||</div>
1414
<% } else if (field.type === 'radio') { %>
1515
<div class="radioOptions">
@@ -36,7 +36,7 @@
3636
<% }) %>
3737
</select>
3838
<% } else { %>
39-
<input type="<%= field.type %>" placeholder="<%= field.placeholder || '' %>">
39+
<input id="<%= field.id %>Input" type="<%= field.type %>" placeholder="<%= field.placeholder || '' %>">
4040
<% } %>
4141
</div>
4242
<% step++; }) %>

frontend/pages/edit.ejs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<%- include('head.ejs') %>
2+
<img src="<%= tenant.logo %>" alt="<%= tenant.name %>">
3+
<h1><%= title %></h1>
4+
<% fields.forEach(field => { %>
5+
<div class="inputField active <%= field.required ? 'required' : '' %>" id="<%= field.id %>">
6+
<h3><%= field.label %><%= field.required ? '*' : '' %></h3>
7+
<p><%= field.required ? 'Required' : 'Optional' %><%= field.description ? ': ' + field.description : '' %></p>
8+
<% if (field.type === 'textarea') { %>
9+
<textarea id="<%= field.id %>Textarea" placeholder="<%= field.placeholder || '' %>"></textarea>
10+
<% } else if (field.type === 'checkbox') { %>
11+
<input id="<%= field.id %>Input" type="checkbox" class="hidden">
12+
<div class="checkbox" change="cms">|||</div>
13+
<% } else if (field.type === 'radio') { %>
14+
<div class="radioOptions">
15+
<% if (!field.required) { %>
16+
<div class="radioOption">
17+
<input type="radio" id="none" name="none" value="">
18+
<label for="none">None</label>
19+
</div>
20+
<% } %>
21+
<% (field.options || []).forEach(option => { %>
22+
<div class="radioOption">
23+
<input type="radio" id="<%= field.id %>-<%= option.value %>" name="<%= option.value %>" value="<%= option.value %>">
24+
<label for="<%= field.id %>-<%= option.value %>"><%= option.label %></label>
25+
</div>
26+
<% }) %>
27+
</div>
28+
<% } else if (field.type === 'select') { %>
29+
<select id="<%= field.id %>Select">
30+
<% if (!field.required) { %>
31+
<option value="">None</option>
32+
<% } %>
33+
<% (field.options || []).forEach(option => { %>
34+
<option value="<%= option.value %>"><%= option.label %></option>
35+
<% }) %>
36+
</select>
37+
<% } else { %>
38+
<input id="<%= field.id %>Input" type="<%= field.type %>" placeholder="<%= field.placeholder || '' %>">
39+
<% } %>
40+
</div>
41+
<% }) %>
42+
<div class="buttons">
43+
<% if (!commission.locked || (role !== 'user')) { %><div id="save" class="button">Save</div><% } %>
44+
<a id="error" class="button active hidden" href="<%= tenant.domain %><%= tenant.path %>/<%= commission.id %>/edit">Restart</a>
45+
</div>
46+
<script>
47+
const commissionId = '<%= commission.id %>';
48+
const restore = <%- JSON.stringify(commission.fields) %>;
49+
</script>
50+
<%- include('foot.ejs') %>

frontend/public/scripts.js

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ document.getElementById('next')?.addEventListener('click', next);
1313
document.getElementById('start')?.addEventListener('click', start);
1414
document.getElementById('create')?.addEventListener('click', create);
1515
document.getElementById('sync')?.addEventListener('click', sync);
16+
document.getElementById('save')?.addEventListener('click', save);
1617

1718
function anim_in() {
1819
document.querySelector('main').classList.remove('out');
@@ -74,6 +75,30 @@ window.onload = function () {
7475
};
7576
});
7677
});
78+
if (restore) {
79+
Object.keys(restore).forEach(key => {
80+
const field = document.getElementById(key);
81+
if (field) {
82+
const input = field.querySelector('input, textarea, select');
83+
if (input) {
84+
if (input.type === 'checkbox') {
85+
if (restore[key] === true) {
86+
field.querySelector('.checkbox').classList.add('checked');
87+
input.checked = true;
88+
};
89+
} else if (input.type === 'radio') {
90+
field.querySelectorAll('.radioOption input[type="radio"]').forEach(radio => {
91+
if (radio.value === restore[key]) {
92+
radio.checked = true;
93+
};
94+
});
95+
} else {
96+
input.value = restore[key];
97+
};
98+
};
99+
};
100+
});
101+
};
77102
};
78103

79104
window.addEventListener('pageshow', (event) => {
@@ -317,6 +342,52 @@ async function sync() {
317342
});
318343
};
319344

345+
async function save() {
346+
if (backDisabled) return;
347+
anim_out();
348+
var data = {};
349+
document.querySelectorAll('.inputField').forEach(field => {
350+
const input = field.querySelector('input, textarea, select');
351+
if (input) {
352+
if (input.type === 'checkbox') {
353+
data[field.id] = input.checked;
354+
} if (input.type === 'radio') {
355+
const radios = field.querySelectorAll('input[type="radio"]');
356+
radios.forEach(radio => {
357+
if (radio.checked) data[field.id] = radio.value;
358+
});
359+
} else {
360+
data[field.id] = input.value;
361+
};
362+
};
363+
});
364+
await fetch(`${appPath}/${commissionId}/edit`, {
365+
method: 'POST',
366+
headers: {
367+
'Content-Type': 'application/json'
368+
},
369+
body: JSON.stringify(data),
370+
})
371+
.then(response => response.json())
372+
.then(result => {
373+
backDisabled = true;
374+
document.getElementById('save').classList.add('hidden');
375+
if (result.status === 'success') {
376+
window.location.href = `${appPath}/${commissionId}`;
377+
} else {
378+
document.querySelectorAll('.inputField').forEach(field => {
379+
field.classList.remove('active');
380+
});
381+
document.getElementById('error').classList.remove('hidden');
382+
document.querySelector('.inner h1').innerText = 'Error';
383+
document.querySelector('.inner p').innerText = result.message || 'An unknown error occurred. Please try again later.';
384+
setTimeout(() => {
385+
anim_in();
386+
}, 750)
387+
};
388+
});
389+
};
390+
320391
function progress(percent) {
321392
const progressBar = document.querySelector('.progress');
322393
progressBar.style.width = percent + '%';

frontend/public/styles.css

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -280,8 +280,7 @@ main {
280280
}
281281
}
282282

283-
.inner:has(.commissions),
284-
.inner:has(table) {
283+
.inner:not(:has(.inputField:not(.active))) {
285284
overflow: scroll;
286285
}
287286

index.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,52 @@ app.get('/:id', async (req, res) => {
234234
return res.render('commission', { tenant, title: `Commission ${commission.id}`, session: req.session, vars, fields, role: getUserRole(req.session), commission });
235235
});
236236

237+
app.get('/:id/edit', async (req, res) => {
238+
if (!on) return res.render('off', { tenant, title: 'Activation' });
239+
if (!req.session) return res.render('session', { tenant, title: 'Session' });
240+
if (!tenant.slug || !tenant.name || !tenant.domain) return res.render('tenant', { tenant, title: 'Configuration' });
241+
if (tenant.auth && tenant.auth.enabled && vars.userId && !req.session[vars.userId]) return res.render('auth', { tenant, title: 'Authenticate' });
242+
req.session[vars.commissions] = verifyAgainstSchema('commission', req.session[vars.commissions] || []);
243+
if (getUserRole(req.session) === 'user') req.session[vars.commissions] = req.session[vars.commissions].filter(commission => commission.user === req.session[vars.userId]);
244+
const commission = (req.session[vars.commissions] || []).find(commission => (String(commission.id) === String(req.params.id)) && (commission.user === req.session[vars.userId]));
245+
if (!commission) return res.status(404).render('error', { tenant, title: 'Not Found', message: 'The requested commission was not found.' });
246+
if (commission.locked && (getUserRole(req.session) === 'user')) return res.status(403).render('error', { tenant, title: 'Forbidden', message: 'You do not have permission to edit this commission.' });
247+
return res.render('edit', { tenant, title: `Edit Commission ${commission.id}`, session: req.session, vars, fields, commission, role: getUserRole(req.session) });
248+
});
249+
250+
app.post('/:id/edit', async (req, res) => {
251+
if (!on) return res.status(503).json({ status: 'error', message: 'Service is currently offline.' });
252+
if (!req.session) return res.status(401).json({ status: 'error', message: 'No session found. Please enable cookies and try again.' });
253+
if (tenant.auth && tenant.auth.enabled && vars.userId && !req.session[vars.userId]) return res.status(401).json({ status: 'error', message: 'User not authenticated. Please log in and try again.' });
254+
if (!tenant.slug || !tenant.name || !tenant.domain) return res.status(500).json({ status: 'error', message: 'Service is not properly configured. Please contact the administrator.' });
255+
req.session[vars.commissions] = verifyAgainstSchema('commission', req.session[vars.commissions] || []);
256+
if (getUserRole(req.session) === 'user') req.session[vars.commissions] = req.session[vars.commissions].filter(commission => commission.user === req.session[vars.userId]);
257+
const commissionIndex = (req.session[vars.commissions] || []).findIndex(commission => (String(commission.id) === String(req.params.id)) && (commission.user === req.session[vars.userId]));
258+
if (commissionIndex === -1) return res.status(404).json({ status: 'error', message: 'The requested commission was not found.' });
259+
const commission = req.session[vars.commissions][commissionIndex];
260+
if (commission.locked && (getUserRole(req.session) === 'user')) return res.status(403).json({ status: 'error', message: 'You do not have permission to edit this commission.' });
261+
const data = {};
262+
fields.forEach(field => {
263+
if (field.id) data[field.id] = req.body[field.id] || null;
264+
});
265+
data.updatedAt = new Date();
266+
data.updatedBy = (tenant.auth && tenant.auth.enabled) ? {
267+
id: req.session[vars.userId],
268+
name: req.session[vars.name] || req.session[vars.userId],
269+
role: getUserRole(req.session) || 'user'
270+
} : {};
271+
if (updateHandler && typeof updateHandler === 'function') {
272+
try {
273+
await updateHandler(req, { ...commission, fields: data });
274+
await syncHandler(req);
275+
} catch (error) {
276+
console.error('Error in handler function:', error);
277+
return res.status(500).json({ status: 'error', message: 'An error occurred while processing your request. Please try again later.' });
278+
};
279+
};
280+
return res.status(200).json({ status: 'success', message: 'Your commission was updated successfully.' });
281+
});
282+
237283
app.use((req, res) => {
238284
return res.status(404).render('error', { tenant, title: 'Not Found', message: 'The requested resource was not found.' });
239285
});

0 commit comments

Comments
 (0)