fix: remaining audit items — anim counter, API 404s, graceful shutdown, null checks
- anim(): guarantee final frame shows exact target value (not target-1) - API: /api/* catch-all returns 404 JSON instead of SPA fallback HTML - Server: SIGTERM handler closes pool + server gracefully - renderTeamBar: null-check allBtn before DOM manipulation
This commit is contained in:
@@ -403,8 +403,10 @@ function renderTeamBar(stats) {
|
||||
// Clear existing member pills (keep the "Everyone" button)
|
||||
const allBtn = bar.querySelector('[data-member="all"]');
|
||||
bar.innerHTML = '';
|
||||
if (activeMember === 'all') allBtn.classList.add('active'); else allBtn.classList.remove('active');
|
||||
bar.appendChild(allBtn);
|
||||
if (allBtn) {
|
||||
if (activeMember === 'all') allBtn.classList.add('active'); else allBtn.classList.remove('active');
|
||||
bar.appendChild(allBtn);
|
||||
}
|
||||
|
||||
stats.members.forEach(m => {
|
||||
const btn = document.createElement('button');
|
||||
@@ -419,7 +421,7 @@ function renderTeamBar(stats) {
|
||||
|
||||
function fmtDate(str){try{const d=new Date(str+'T00:00:00');return d.toLocaleDateString('en-GB',{weekday:'short',day:'numeric',month:'short',year:'numeric'});}catch{return str;}}
|
||||
function esc(s){const d=document.createElement('div');d.textContent=s;return d.innerHTML;}
|
||||
function anim(el,target,dur){if(!el)return;const t0=performance.now();(function f(now){const p=Math.min((now-t0)/dur,1);el.textContent=Math.floor(target*(1-Math.pow(1-p,3)));if(p<1)requestAnimationFrame(f);})(t0);}
|
||||
function anim(el,target,dur){if(!el)return;const t0=performance.now();(function f(now){const p=Math.min((now-t0)/dur,1);el.textContent=p>=1?target:Math.floor(target*(1-Math.pow(1-p,3)));if(p<1)requestAnimationFrame(f);})(t0);}
|
||||
|
||||
document.querySelector('.lv-pill[data-filter="all"]').onclick=()=>filterTo('all');
|
||||
init();
|
||||
|
||||
@@ -233,12 +233,26 @@ app.get('/work/', (req, res) => res.redirect(301, '/work/charityright/'));
|
||||
// Serve static files from html/ directory
|
||||
app.use(express.static(path.join(__dirname, 'html')));
|
||||
|
||||
// API 404 — don't let SPA fallback swallow bad API routes
|
||||
app.all('/api/*', (req, res) => {
|
||||
res.status(404).json({ error: 'not found' });
|
||||
});
|
||||
|
||||
// SPA fallback: send index.html for unmatched routes
|
||||
app.get('*', (req, res) => {
|
||||
res.sendFile(path.join(__dirname, 'html', 'index.html'));
|
||||
});
|
||||
|
||||
const PORT = process.env.PORT || 3000;
|
||||
app.listen(PORT, '0.0.0.0', () => {
|
||||
const server = app.listen(PORT, '0.0.0.0', () => {
|
||||
console.log(`QuikCue Site server listening on :${PORT}`);
|
||||
});
|
||||
|
||||
// Graceful shutdown
|
||||
process.on('SIGTERM', () => {
|
||||
console.log('SIGTERM received, shutting down...');
|
||||
server.close(() => {
|
||||
if (pool) pool.end();
|
||||
process.exit(0);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user