Debounce date input loads to prevent mid-type API calls

Typing a date manually (e.g. "21") fires onChange on each keystroke,
so "2" would trigger a load for the 2nd before "21" was complete.
Added a 600ms debounce on the week-start and since-date inputs so the
load only fires after the user stops typing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
jtricerolph 2026-07-22 12:59:26 +00:00
parent 0b63543e1f
commit f1ba176195
4 changed files with 15 additions and 15 deletions

File diff suppressed because one or more lines are too long

View file

@ -5,7 +5,7 @@
<meta name="viewport" content="width=1280" /> <meta name="viewport" content="width=1280" />
<meta name="theme-color" content="#2d6a4f" /> <meta name="theme-color" content="#2d6a4f" />
<title>HK Planner</title> <title>HK Planner</title>
<script type="module" crossorigin src="/hk-planner/assets/index-pKsveas1.js"></script> <script type="module" crossorigin src="/hk-planner/assets/index-IImb5HHO.js"></script>
<link rel="stylesheet" crossorigin href="/hk-planner/assets/index-BY6qKqNq.css"> <link rel="stylesheet" crossorigin href="/hk-planner/assets/index-BY6qKqNq.css">
<link rel="manifest" href="/hk-planner/manifest.webmanifest"><script id="vite-plugin-pwa:register-sw" src="/hk-planner/registerSW.js"></script></head> <link rel="manifest" href="/hk-planner/manifest.webmanifest"><script id="vite-plugin-pwa:register-sw" src="/hk-planner/registerSW.js"></script></head>
<body> <body>

2
frontend/dist/sw.js vendored
View file

@ -1 +1 @@
if(!self.define){let e,i={};const n=(n,s)=>(n=new URL(n+".js",s).href,i[n]||new Promise(i=>{if("document"in self){const e=document.createElement("script");e.src=n,e.onload=i,document.head.appendChild(e)}else e=n,importScripts(n),i()}).then(()=>{let e=i[n];if(!e)throw new Error(`Module ${n} didnt register its module`);return e}));self.define=(s,r)=>{const o=e||("document"in self?document.currentScript.src:"")||location.href;if(i[o])return;let t={};const c=e=>n(e,o),d={module:{uri:o},exports:t,require:c};i[o]=Promise.all(s.map(e=>d[e]||c(e))).then(e=>(r(...e),t))}}define(["./workbox-9c191d2f"],function(e){"use strict";self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"registerSW.js",revision:"a2c395d8c225f1b3ea12388f15189bce"},{url:"index.html",revision:"ed36f64c6584bab6b7811659079d81c2"},{url:"icons/icon-512.png",revision:"c32202b9deed67ef38331f63dec9d1c8"},{url:"icons/icon-192.png",revision:"46ece317d50d10b8f5e225e073b3221d"},{url:"assets/index-pKsveas1.js",revision:null},{url:"assets/index-BY6qKqNq.css",revision:null},{url:"manifest.webmanifest",revision:"c2510de876adb84db0c4b300b71216fa"}],{}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("/hk-planner/index.html"),{denylist:[/\/api\//]}))}); if(!self.define){let e,i={};const n=(n,s)=>(n=new URL(n+".js",s).href,i[n]||new Promise(i=>{if("document"in self){const e=document.createElement("script");e.src=n,e.onload=i,document.head.appendChild(e)}else e=n,importScripts(n),i()}).then(()=>{let e=i[n];if(!e)throw new Error(`Module ${n} didnt register its module`);return e}));self.define=(s,r)=>{const o=e||("document"in self?document.currentScript.src:"")||location.href;if(i[o])return;let t={};const d=e=>n(e,o),c={module:{uri:o},exports:t,require:d};i[o]=Promise.all(s.map(e=>c[e]||d(e))).then(e=>(r(...e),t))}}define(["./workbox-9c191d2f"],function(e){"use strict";self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"registerSW.js",revision:"a2c395d8c225f1b3ea12388f15189bce"},{url:"index.html",revision:"c559453bdaf3e95d6d3ad0625d673085"},{url:"icons/icon-512.png",revision:"c32202b9deed67ef38331f63dec9d1c8"},{url:"icons/icon-192.png",revision:"46ece317d50d10b8f5e225e073b3221d"},{url:"assets/index-IImb5HHO.js",revision:null},{url:"assets/index-BY6qKqNq.css",revision:null},{url:"manifest.webmanifest",revision:"c2510de876adb84db0c4b300b71216fa"}],{}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("/hk-planner/index.html"),{denylist:[/\/api\//]}))});

View file

@ -338,7 +338,7 @@ export function Planner() {
<input <input
type="date" type="date"
value={displayWeekStart} value={displayWeekStart}
onChange={e => { if (e.target.value) { setWeekStart(e.target.value); stampLastReviewed(); loadAll(true, e.target.value) } }} onChange={e => { if (e.target.value) { const v = e.target.value; setWeekStart(v); stampLastReviewed(); debounce('weekStart', () => loadAll(true, v), 600) } }}
style={{ border: '1px solid var(--card-border)', borderRadius: '6px', padding: '0.35rem 0.5rem', fontSize: '0.82rem', color: 'var(--text-dark)' }} style={{ border: '1px solid var(--card-border)', borderRadius: '6px', padding: '0.35rem 0.5rem', fontSize: '0.82rem', color: 'var(--text-dark)' }}
/> />
<div style={{ width: '1px', height: '24px', background: 'var(--card-border)' }} /> <div style={{ width: '1px', height: '24px', background: 'var(--card-border)' }} />
@ -348,7 +348,7 @@ export function Planner() {
<input <input
type="date" type="date"
value={lastViewed} value={lastViewed}
onChange={e => { if (e.target.value) { setLastViewed(e.target.value); loadAll(true, undefined, e.target.value) } }} onChange={e => { if (e.target.value) { const v = e.target.value; setLastViewed(v); debounce('lastViewed', () => loadAll(true, undefined, v), 600) } }}
style={{ border: '1px solid var(--card-border)', borderRadius: '6px', padding: '0.3rem 0.5rem', fontSize: '0.78rem', color: 'var(--text-dark)' }} style={{ border: '1px solid var(--card-border)', borderRadius: '6px', padding: '0.3rem 0.5rem', fontSize: '0.78rem', color: 'var(--text-dark)' }}
/> />
</label> </label>