feat(uat-batch-3): wave-1 primitives — DatePicker, DateTimePicker, FileInputButton, ColumnPicker hideAll
Builds the foundational primitives that subsequent waves depend on. None of these introduce new deps — date-fns, react-day-picker, and shadcn Calendar were already in the tree. - `<DatePicker>` and `<DateTimePicker>` in src/components/ui — desktop popover wrapping the existing shadcn Calendar (caption-dropdown nav so reps can jump months/years for the SkipAheadBanner backfill UX), mobile native input via useIsMobile. Drop-in for `<Input type=date>` / `<Input type=datetime-local>`. - `<FileInputButton>` in src/components/ui — styled Button + hidden input, replaces browser-default file picker UI. Most queued sweep sites already used the hidden-input + Button-trigger pattern; the primitive lands for any new caller plus consistent filename display + clear button. - ColumnPicker `hideAll()` footer item — symmetric to existing `showAll()`, with the same visibility gate. Lands platform-wide via the shared component. - Migrated highest-leverage call sites to the new primitives: * MilestoneAdvanceButton (backfill UX) * Reminder form (datetime-local → DateTimePicker) * Snooze dialog (datetime-local → DateTimePicker) * External-EOI upload dialog (date + file picker) * Payments section (received-on date) - Remaining 15+ date-input call sites parked for a follow-up sweep — several use react-hook-form `register` patterns that need careful migration to the new controlled-value contract. tsc clean. 1419/1419 vitest pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
import { useState, useMemo } from 'react';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { DateTimePicker } from '@/components/ui/date-time-picker';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Textarea } from '@/components/ui/textarea';
|
||||
@@ -304,12 +305,11 @@ function ReminderFormBody({
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<Input
|
||||
<DateTimePicker
|
||||
id="reminder-due"
|
||||
type="datetime-local"
|
||||
value={dueAt}
|
||||
onChange={(e) => setDueAt(e.target.value)}
|
||||
required
|
||||
onChange={setDueAt}
|
||||
placeholder="Pick a due date and time"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { useState } from 'react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { DateTimePicker } from '@/components/ui/date-time-picker';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import {
|
||||
Dialog,
|
||||
@@ -91,13 +91,14 @@ export function SnoozeDialog({ open, onOpenChange, reminderId, onSuccess }: Snoo
|
||||
<div className="space-y-2 pt-2">
|
||||
<Label htmlFor="custom-snooze">Custom date & time</Label>
|
||||
<div className="flex gap-2">
|
||||
<Input
|
||||
id="custom-snooze"
|
||||
type="datetime-local"
|
||||
value={customDate}
|
||||
onChange={(e) => setCustomDate(e.target.value)}
|
||||
className="flex-1"
|
||||
/>
|
||||
<div className="flex-1">
|
||||
<DateTimePicker
|
||||
id="custom-snooze"
|
||||
value={customDate}
|
||||
onChange={setCustomDate}
|
||||
placeholder="Pick a date and time"
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
disabled={loading || !customDate}
|
||||
onClick={() => handleSnooze(new Date(customDate).toISOString())}
|
||||
|
||||
Reference in New Issue
Block a user