fix(ui): cap date inputs to 4-digit years via min/max

Without min/max, native <input type="date"> lets you type arbitrarily-many
year digits (YYYYYY-MM-DD). Add min="2000-01-01" max="2099-12-31" to every
date input (and bounded range on the single datetime-local) across expenses,
projects, tasks, assets, decisions, and maintenance.
This commit is contained in:
2026-04-23 15:45:15 +07:00
parent 3417ed6698
commit f8478f5019
9 changed files with 17 additions and 17 deletions
+1 -1
View File
@@ -61,7 +61,7 @@
</div> </div>
<div> <div>
<label for="purchased_at" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Purchased on</label> <label for="purchased_at" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Purchased on</label>
<input id="purchased_at" name="purchased_at" type="date" value={dateInput(a.purchasedAt)} <input id="purchased_at" name="purchased_at" type="date" min="2000-01-01" max="2099-12-31" value={dateInput(a.purchasedAt)}
class="mt-1 block w-full rounded-md border border-gray-300 bg-white px-3 py-2 text-sm shadow-sm focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-900 dark:text-gray-100" /> class="mt-1 block w-full rounded-md border border-gray-300 bg-white px-3 py-2 text-sm shadow-sm focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-900 dark:text-gray-100" />
</div> </div>
{#if a.currentContainerKind === 'property'} {#if a.currentContainerKind === 'property'}
@@ -75,7 +75,7 @@
{#if kind === 'time'} {#if kind === 'time'}
<div> <div>
<label for="start_from" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Anchor (optional)</label> <label for="start_from" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Anchor (optional)</label>
<input id="start_from" name="start_from" type="date" <input id="start_from" name="start_from" type="date" min="2000-01-01" max="2099-12-31"
class="mt-1 block w-full rounded-md border border-gray-300 bg-white px-3 py-2 text-sm shadow-sm focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-900 dark:text-gray-100" /> class="mt-1 block w-full rounded-md border border-gray-300 bg-white px-3 py-2 text-sm shadow-sm focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-900 dark:text-gray-100" />
<p class="mt-1 text-xs text-gray-400">First service due = anchor + interval. Defaults to today.</p> <p class="mt-1 text-xs text-gray-400">First service due = anchor + interval. Defaults to today.</p>
</div> </div>
@@ -161,7 +161,7 @@
<div class="grid gap-3 sm:grid-cols-2"> <div class="grid gap-3 sm:grid-cols-2">
<label class="block"> <label class="block">
<span class="block text-xs font-medium text-gray-700 dark:text-gray-300">Performed at</span> <span class="block text-xs font-medium text-gray-700 dark:text-gray-300">Performed at</span>
<input name="performed_at" type="datetime-local" <input name="performed_at" type="datetime-local" min="2000-01-01T00:00" max="2099-12-31T23:59"
value={new Date().toISOString().slice(0, 16)} value={new Date().toISOString().slice(0, 16)}
class="mt-1 block w-full rounded-md border border-gray-300 bg-white px-3 py-1.5 text-sm shadow-sm focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-900 dark:text-gray-100" /> class="mt-1 block w-full rounded-md border border-gray-300 bg-white px-3 py-1.5 text-sm shadow-sm focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-900 dark:text-gray-100" />
</label> </label>
+1 -1
View File
@@ -114,7 +114,7 @@
</div> </div>
<div> <div>
<label for="purchased_at" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Purchased on</label> <label for="purchased_at" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Purchased on</label>
<input id="purchased_at" name="purchased_at" type="date" <input id="purchased_at" name="purchased_at" type="date" min="2000-01-01" max="2099-12-31"
class="mt-1 block w-full rounded-md border border-gray-300 bg-white px-3 py-2 text-sm shadow-sm focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-900 dark:text-gray-100" /> class="mt-1 block w-full rounded-md border border-gray-300 bg-white px-3 py-2 text-sm shadow-sm focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-900 dark:text-gray-100" />
</div> </div>
</div> </div>
+2 -2
View File
@@ -51,12 +51,12 @@
</div> </div>
<div> <div>
<label for="start_date" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Start date</label> <label for="start_date" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Start date</label>
<input id="start_date" name="start_date" type="date" value={dateInput(p.startDate)} <input id="start_date" name="start_date" type="date" min="2000-01-01" max="2099-12-31" value={dateInput(p.startDate)}
class="mt-1 block w-full rounded-md border border-gray-300 bg-white px-3 py-2 text-sm shadow-sm focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-900 dark:text-gray-100" /> class="mt-1 block w-full rounded-md border border-gray-300 bg-white px-3 py-2 text-sm shadow-sm focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-900 dark:text-gray-100" />
</div> </div>
<div> <div>
<label for="end_date" class="block text-sm font-medium text-gray-700 dark:text-gray-300">End date</label> <label for="end_date" class="block text-sm font-medium text-gray-700 dark:text-gray-300">End date</label>
<input id="end_date" name="end_date" type="date" value={dateInput(p.endDate)} <input id="end_date" name="end_date" type="date" min="2000-01-01" max="2099-12-31" value={dateInput(p.endDate)}
class="mt-1 block w-full rounded-md border border-gray-300 bg-white px-3 py-2 text-sm shadow-sm focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-900 dark:text-gray-100" /> class="mt-1 block w-full rounded-md border border-gray-300 bg-white px-3 py-2 text-sm shadow-sm focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-900 dark:text-gray-100" />
</div> </div>
<div class="sm:col-span-2"> <div class="sm:col-span-2">
@@ -68,7 +68,7 @@
</div> </div>
<div> <div>
<label for="decided_at" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Decided on <span class="text-red-500">*</span></label> <label for="decided_at" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Decided on <span class="text-red-500">*</span></label>
<input id="decided_at" name="decided_at" type="date" required value={v.decided_at ?? new Date().toISOString().slice(0, 10)} <input id="decided_at" name="decided_at" type="date" min="2000-01-01" max="2099-12-31" required value={v.decided_at ?? new Date().toISOString().slice(0, 10)}
class="mt-1 block w-full rounded-md border border-gray-300 bg-white px-3 py-2 text-sm shadow-sm focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-900 dark:text-gray-100" /> class="mt-1 block w-full rounded-md border border-gray-300 bg-white px-3 py-2 text-sm shadow-sm focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-900 dark:text-gray-100" />
</div> </div>
</div> </div>
@@ -88,7 +88,7 @@
</div> </div>
<div> <div>
<label for="due_at" class="block text-xs font-medium text-gray-700 dark:text-gray-300">Due</label> <label for="due_at" class="block text-xs font-medium text-gray-700 dark:text-gray-300">Due</label>
<input id="due_at" name="due_at" type="date" <input id="due_at" name="due_at" type="date" min="2000-01-01" max="2099-12-31"
class="mt-1 block w-full rounded-md border border-gray-300 bg-white px-3 py-1.5 text-sm shadow-sm focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-900 dark:text-gray-100" /> class="mt-1 block w-full rounded-md border border-gray-300 bg-white px-3 py-1.5 text-sm shadow-sm focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-900 dark:text-gray-100" />
</div> </div>
<div class="sm:col-span-3 flex justify-end"> <div class="sm:col-span-3 flex justify-end">
@@ -46,7 +46,7 @@
</div> </div>
<div> <div>
<label for="due_at" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Due</label> <label for="due_at" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Due</label>
<input id="due_at" name="due_at" type="date" value={dateInput(t.dueAt)} <input id="due_at" name="due_at" type="date" min="2000-01-01" max="2099-12-31" value={dateInput(t.dueAt)}
class="mt-1 block w-full rounded-md border border-gray-300 bg-white px-3 py-2 text-sm shadow-sm focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-900 dark:text-gray-100" /> class="mt-1 block w-full rounded-md border border-gray-300 bg-white px-3 py-2 text-sm shadow-sm focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-900 dark:text-gray-100" />
</div> </div>
</div> </div>
+2 -2
View File
@@ -46,12 +46,12 @@
</div> </div>
<div> <div>
<label for="start_date" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Start date</label> <label for="start_date" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Start date</label>
<input id="start_date" name="start_date" type="date" value={v.start_date ?? ''} <input id="start_date" name="start_date" type="date" min="2000-01-01" max="2099-12-31" value={v.start_date ?? ''}
class="mt-1 block w-full rounded-md border border-gray-300 bg-white px-3 py-2 text-sm shadow-sm focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-900 dark:text-gray-100" /> class="mt-1 block w-full rounded-md border border-gray-300 bg-white px-3 py-2 text-sm shadow-sm focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-900 dark:text-gray-100" />
</div> </div>
<div> <div>
<label for="end_date" class="block text-sm font-medium text-gray-700 dark:text-gray-300">End date</label> <label for="end_date" class="block text-sm font-medium text-gray-700 dark:text-gray-300">End date</label>
<input id="end_date" name="end_date" type="date" value={v.end_date ?? ''} <input id="end_date" name="end_date" type="date" min="2000-01-01" max="2099-12-31" value={v.end_date ?? ''}
class="mt-1 block w-full rounded-md border border-gray-300 bg-white px-3 py-2 text-sm shadow-sm focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-900 dark:text-gray-100" /> class="mt-1 block w-full rounded-md border border-gray-300 bg-white px-3 py-2 text-sm shadow-sm focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-900 dark:text-gray-100" />
</div> </div>
</div> </div>
@@ -106,17 +106,17 @@
</label> </label>
<label class="block"> <label class="block">
<span class="block text-xs font-medium text-gray-700 dark:text-gray-300">Incurred on <span class="text-red-500">*</span></span> <span class="block text-xs font-medium text-gray-700 dark:text-gray-300">Incurred on <span class="text-red-500">*</span></span>
<input name="incurred_at" type="date" required value={new Date().toISOString().slice(0, 10)} <input name="incurred_at" type="date" min="2000-01-01" max="2099-12-31" required value={new Date().toISOString().slice(0, 10)}
class="mt-1 block w-full rounded-md border border-gray-300 bg-white px-3 py-1.5 text-sm shadow-sm focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-900 dark:text-gray-100" /> class="mt-1 block w-full rounded-md border border-gray-300 bg-white px-3 py-1.5 text-sm shadow-sm focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-900 dark:text-gray-100" />
</label> </label>
<label class="block"> <label class="block">
<span class="block text-xs font-medium text-gray-700 dark:text-gray-300">Period start</span> <span class="block text-xs font-medium text-gray-700 dark:text-gray-300">Period start</span>
<input name="period_start" type="date" <input name="period_start" type="date" min="2000-01-01" max="2099-12-31"
class="mt-1 block w-full rounded-md border border-gray-300 bg-white px-3 py-1.5 text-sm shadow-sm focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-900 dark:text-gray-100" /> class="mt-1 block w-full rounded-md border border-gray-300 bg-white px-3 py-1.5 text-sm shadow-sm focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-900 dark:text-gray-100" />
</label> </label>
<label class="block"> <label class="block">
<span class="block text-xs font-medium text-gray-700 dark:text-gray-300">Period end</span> <span class="block text-xs font-medium text-gray-700 dark:text-gray-300">Period end</span>
<input name="period_end" type="date" <input name="period_end" type="date" min="2000-01-01" max="2099-12-31"
class="mt-1 block w-full rounded-md border border-gray-300 bg-white px-3 py-1.5 text-sm shadow-sm focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-900 dark:text-gray-100" /> class="mt-1 block w-full rounded-md border border-gray-300 bg-white px-3 py-1.5 text-sm shadow-sm focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-900 dark:text-gray-100" />
</label> </label>
<label class="block"> <label class="block">
@@ -199,17 +199,17 @@
</label> </label>
<label class="block"> <label class="block">
<span class="block text-xs font-medium text-gray-700 dark:text-gray-300">Incurred</span> <span class="block text-xs font-medium text-gray-700 dark:text-gray-300">Incurred</span>
<input name="incurred_at" type="date" required value={dateInput(e.incurredAt)} <input name="incurred_at" type="date" min="2000-01-01" max="2099-12-31" required value={dateInput(e.incurredAt)}
class="mt-1 block w-full rounded-md border border-gray-300 bg-white px-2 py-1 text-sm dark:border-gray-600 dark:bg-gray-900 dark:text-gray-100" /> class="mt-1 block w-full rounded-md border border-gray-300 bg-white px-2 py-1 text-sm dark:border-gray-600 dark:bg-gray-900 dark:text-gray-100" />
</label> </label>
<label class="block"> <label class="block">
<span class="block text-xs font-medium text-gray-700 dark:text-gray-300">Period start</span> <span class="block text-xs font-medium text-gray-700 dark:text-gray-300">Period start</span>
<input name="period_start" type="date" value={dateInput(e.periodStart)} <input name="period_start" type="date" min="2000-01-01" max="2099-12-31" value={dateInput(e.periodStart)}
class="mt-1 block w-full rounded-md border border-gray-300 bg-white px-2 py-1 text-sm dark:border-gray-600 dark:bg-gray-900 dark:text-gray-100" /> class="mt-1 block w-full rounded-md border border-gray-300 bg-white px-2 py-1 text-sm dark:border-gray-600 dark:bg-gray-900 dark:text-gray-100" />
</label> </label>
<label class="block"> <label class="block">
<span class="block text-xs font-medium text-gray-700 dark:text-gray-300">Period end</span> <span class="block text-xs font-medium text-gray-700 dark:text-gray-300">Period end</span>
<input name="period_end" type="date" value={dateInput(e.periodEnd)} <input name="period_end" type="date" min="2000-01-01" max="2099-12-31" value={dateInput(e.periodEnd)}
class="mt-1 block w-full rounded-md border border-gray-300 bg-white px-2 py-1 text-sm dark:border-gray-600 dark:bg-gray-900 dark:text-gray-100" /> class="mt-1 block w-full rounded-md border border-gray-300 bg-white px-2 py-1 text-sm dark:border-gray-600 dark:bg-gray-900 dark:text-gray-100" />
</label> </label>
<label class="block"> <label class="block">