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:
@@ -59,11 +59,18 @@ export function ColumnPicker({
|
||||
onChange([]);
|
||||
}
|
||||
|
||||
function hideAll() {
|
||||
onChange(columns.filter((c) => !c.alwaysVisible).map((c) => c.id));
|
||||
}
|
||||
|
||||
// The "All visible" affordance is only useful when something is
|
||||
// hidden — a no-op button is noise.
|
||||
const canShowAll = hidden.some((id) =>
|
||||
columns.some((col) => col.id === id && !col.alwaysVisible),
|
||||
);
|
||||
// Mirror: "Hide all" is only useful when at least one toggleable
|
||||
// column is currently visible.
|
||||
const canHideAll = columns.some((col) => !col.alwaysVisible && !hiddenSet.has(col.id));
|
||||
|
||||
return (
|
||||
<DropdownMenu>
|
||||
@@ -113,13 +120,16 @@ export function ColumnPicker({
|
||||
</DropdownMenuItem>
|
||||
);
|
||||
})}
|
||||
{(canShowAll || canHideAll) && <DropdownMenuSeparator />}
|
||||
{canShowAll && (
|
||||
<>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem onClick={showAll} className="text-xs text-muted-foreground">
|
||||
Show all columns
|
||||
</DropdownMenuItem>
|
||||
</>
|
||||
<DropdownMenuItem onClick={showAll} className="text-xs text-muted-foreground">
|
||||
Show all columns
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
{canHideAll && (
|
||||
<DropdownMenuItem onClick={hideAll} className="text-xs text-muted-foreground">
|
||||
Hide all columns
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
{onSaveView && (
|
||||
<>
|
||||
|
||||
Reference in New Issue
Block a user