Skip to content

Commit ae37580

Browse files
committed
Update commissions variable schema to allow any status string, commission sync handler usage
1 parent 13f6d0c commit ae37580

6 files changed

Lines changed: 90 additions & 13 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ Session Example:
194194
amount: 1000, // Commission amount as a number, or null if not applicable. Defaults to null
195195
currency: 'USD', // Currency code for the commission amount as a string. Defaults to 'USD'
196196
date: '2023-10-01', // Date of the commission in any valid date/datetime format. Defaults to null
197-
status: 'in-progress', // Status of the commission ('completed', 'in-progress', 'on-hold', 'cancelled')
197+
status: 'On Hold', // Status of the commission as a string (e.g., 'Completed', 'In Progress', 'On Hold', 'Cancelled')
198198
fields: { // Custom fields associated with the commission
199199
'id': 'value' // Key-value pairs for custom fields
200200
},

frontend/pages/foot.ejs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
<p class="fixed"<%= new Date().getFullYear() %> CommTrackr</p>
33
<p class="fixed2">Changes saved</p>
44
</main>
5+
<script>
6+
const appPath = '<%= tenant.domain %><%= tenant.path %>';
7+
</script>
58
<script src="<%= tenant.domain %><%= tenant.path %>/scripts.js" type="module"></script>
69
</body>
710

frontend/pages/user.ejs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,13 @@
1212
<a class="button" href="<%= tenant.domain %><%= tenant.path %>/create">New Commission</a>
1313
</div>
1414
<div class="commissions">
15+
<div id="sync"><svg xmlns="http://www.w3.org/2000/svg" width="23" height="23" viewBox="0 0 23 23" fill="none">
16+
<path d="M18.5949 5.16663C16.8618 3.32009 14.3989 2.16663 11.6666 2.16663C6.41992 2.16663 2.16663 6.41992 2.16663 11.6666C2.16663 16.9133 6.41992 21.1666 11.6666 21.1666C14.3989 21.1666 16.8618 20.0132 18.5949 18.1666M17.3236 7.98035L20.9804 7.98035L20.9804 4.3235" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" />
17+
</svg> Sync</div>
1518
<% session[vars.commissions].forEach(commission => { %>
1619
<div class="commission">
1720
<h2><%= commission.id %></h2>
18-
<p><%= commission.status.replaceAll('-', ' ').replace(/\w\S*/g, function(txt) { return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase() }) %></p>
21+
<p><%= commission.status %></p>
1922
<a class="button" href="<%= tenant.domain %><%= tenant.path %>/<%= commission.id %>"><%= commission.locked ? 'View' : 'Edit' %></a>
2023
</div>
2124
<% }) %>

frontend/public/scripts.js

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
if (!appPath) document.body.innerHTML = 'Error: appPath is not defined';
2+
13
document.querySelectorAll('.button[href]').forEach(button => button.addEventListener('click', function (event) {
24
event.preventDefault();
35
anim_out();
@@ -10,6 +12,7 @@ document.getElementById('back')?.addEventListener('click', back);
1012
document.getElementById('next')?.addEventListener('click', next);
1113
document.getElementById('start')?.addEventListener('click', start);
1214
document.getElementById('create')?.addEventListener('click', create);
15+
document.getElementById('sync')?.addEventListener('click', sync);
1316

1417
function anim_in() {
1518
document.querySelector('main').classList.remove('out');
@@ -134,7 +137,6 @@ function next() {
134137
} else {
135138
document.getElementById('back')?.classList.remove('hidden');
136139
};
137-
// focus first input of the new step
138140
const newField = document.querySelector(`.inputField[step="${step}"]`);
139141
if (newField) {
140142
const input = newField.querySelector('input, textarea, select');
@@ -159,7 +161,6 @@ function back() {
159161
document.getElementById('back')?.classList.remove('hidden');
160162
};
161163
document.getElementById('create')?.classList.add('hidden');
162-
// focus first input of the new step
163164
const newField = document.querySelector(`.inputField[step="${step}"]`);
164165
if (newField) {
165166
const input = newField.querySelector('input, textarea, select');
@@ -242,7 +243,7 @@ async function create() {
242243
};
243244
};
244245
});
245-
await fetch(window.location.href, {
246+
await fetch(`${appPath}/create`, {
246247
method: 'POST',
247248
headers: {
248249
'Content-Type': 'application/json'
@@ -256,7 +257,7 @@ async function create() {
256257
if (result.status === 'success') {
257258
document.querySelectorAll('.inputField').forEach(field => {
258259
field.classList.remove('active');
259-
});;
260+
});
260261
document.getElementById('success').classList.remove('hidden');
261262
localStorage.clear();
262263
backDisabled = true;
@@ -276,6 +277,32 @@ async function create() {
276277
});
277278
};
278279

280+
async function sync() {
281+
if (backDisabled) return;
282+
document.getElementById('sync').classList.add('active');
283+
anim_out();
284+
await fetch(`${appPath}/sync`, {
285+
method: 'PUT',
286+
headers: {
287+
'Content-Type': 'application/json'
288+
},
289+
})
290+
.then(response => response.json())
291+
.then(result => {
292+
backDisabled = true;
293+
if (result.status === 'success') {
294+
window.location.reload();
295+
} else {
296+
document.getElementById('error').classList.remove('hidden');
297+
document.querySelector('.inner h1').innerText = 'Error';
298+
document.querySelector('.inner p').innerText = result.message || 'An unknown error occurred. Please try again later.';
299+
};
300+
setTimeout(() => {
301+
anim_in();
302+
}, 750)
303+
});
304+
};
305+
279306
function progress(percent) {
280307
const progressBar = document.querySelector('.progress');
281308
progressBar.style.width = percent + '%';

frontend/public/styles.css

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,35 @@ main {
274274
gap: 5px;
275275
width: -webkit-fill-available;
276276
max-width: 500px;
277-
margin-top: 10px;
277+
margin-top: 5px;
278+
279+
#sync {
280+
display: flex;
281+
align-items: center;
282+
justify-content: flex-start;
283+
margin-bottom: 5px;
284+
cursor: pointer;
285+
286+
svg {
287+
height: 12.5px;
288+
transition: rotate 0.5s linear;
289+
290+
path {
291+
stroke: #ffffff;
292+
stroke-width: 2px;
293+
}
294+
}
295+
}
296+
297+
#sync.active {
298+
user-select: none;
299+
pointer-events: none;
300+
301+
svg {
302+
rotate: 360deg;
303+
transition: rotate 0.5s linear;
304+
}
305+
}
278306

279307
.commission {
280308
display: flex;
@@ -287,8 +315,8 @@ main {
287315

288316
.button {
289317
margin-left: auto;
290-
width: fit-content;
291-
min-width: 35px;
318+
width: fit-content;
319+
min-width: 35px;
292320
}
293321

294322
p {

index.js

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,9 @@ function init({
5555
},
5656
fields: newFields = [],
5757
handlers: {
58-
newCreateHandler = null,
59-
newUpdateHandler = null,
60-
newSyncHandler = null
58+
create: newCreateHandler = null,
59+
update: newUpdateHandler = null,
60+
sync: newSyncHandler = null
6161
}
6262
}) {
6363
tenant = {
@@ -122,7 +122,7 @@ app.get('/', async (req, res) => {
122122
if (!tenant.slug || !tenant.name || !tenant.domain) return res.render('tenant', { tenant, title: 'Configuration' });
123123
if (tenant.auth && tenant.auth.enabled && vars.userId && !req.session[vars.userId]) return res.render('auth', { tenant, title: 'Authenticate' });
124124
req.session[vars.commissions] = (req.session[vars.commissions] || []).map(commission => {
125-
if (!commission.id || !commission.user || (commission.date ? isNaN(new Date(commission.date).getTime()) : false) || !['completed', 'in-progress', 'on-hold', 'cancelled'].some(status => commission.status.includes(status)) || (typeof commission.tasks !== 'object')) return null;
125+
if (!commission.id || !commission.user || (commission.date ? isNaN(new Date(commission.date).getTime()) : false) || (typeof commission.status !== 'string') || (typeof commission.tasks !== 'object')) return null;
126126
return {
127127
id: commission.id,
128128
user: commission.user,
@@ -192,6 +192,22 @@ app.post('/create', async (req, res) => {
192192
res.status(200).json({ status: 'success', message: 'Your commission was created successfully.' });
193193
});
194194

195+
app.put('/sync', async (req, res) => {
196+
if (!on) return res.status(503).json({ status: 'error', message: 'Service is currently offline.' });
197+
if (!req.session) return res.status(401).json({ status: 'error', message: 'No session found. Please enable cookies and try again.' });
198+
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.' });
199+
if (!tenant.slug || !tenant.name || !tenant.domain) return res.status(500).json({ status: 'error', message: 'Service is not properly configured. Please contact the administrator.' });
200+
if (syncHandler && typeof syncHandler === 'function') {
201+
try {
202+
await syncHandler(req);
203+
} catch (error) {
204+
console.error('Error in handler function:', error);
205+
return res.status(500).json({ status: 'error', message: 'An error occurred while processing your request. Please try again later.' });
206+
};
207+
};
208+
res.status(200).json({ status: 'success', message: 'Your commissions were synchronized successfully.' });
209+
});
210+
195211
app.use((req, res) => {
196212
res.status(404).render('error', { tenant, title: 'Not Found', message: 'The requested resource was not found.' });
197213
});

0 commit comments

Comments
 (0)